dotnet / linker

389 stars 127 forks source link

Analyzer processes expression tree construction data flow differently from linker #3172

Open vitek-karas opened 1 year ago

vitek-karas commented 1 year ago

For example:

            public static void MethodWithSingleAnnotatedParameter (
                [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type)
            { }

            static void LdToken ()
            {
                                // Linker produces IL2111
                                // Analyzer produces IL2067
                Expression<Action<Type>> _ = (Type t) => MethodWithSingleAnnotatedParameter (t);

                                // Linker produces IL2111
                                // Analyzer doesn't warn
                Expression<Action> _ = () => MethodWithSingleAnnotatedParameter (typeof(string));
            }

The difference is because linker sees ldtoken and not an actual call and doesn't perform true data flow, but analyzer sees this as a normal statement and processes it through data flow. The linker behavior is correct here, under the hood this creates expression tree with MethodInfo which is publicly accessible. And anybody with the expression tree can invoke the MethodInfo with any input. So this needs to warn always, regardless of data flow.

vitek-karas commented 1 year ago

In this case the analyzer should probably always produce less warnings than trimmer, which is the better outcome.

The one place where this might be a problem is cases where expression trees are used as a performance optimization and as a convenient way to generate code at runtime. Where the code builds an expression tree which is then compiled and executed.