Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Share intrinsic handling of GetMember and similar APIs #2639

Merged
merged 3 commits into from
Feb 28, 2022

Conversation

vitek-karas
Copy link
Member

Other than sharing more code and adapting it so that it works on both linker and analyzer, this change brings simple analysis of constant integer values in the analyzer. This is necessary to make most reflection API calls recognize binding flags. For example GetMethods(BindingFlags.Public | BindingFlags.Static). So this change adds analysis of constant values (as recognized by the Roslyn's operation tree) and the OR binary operator for integers and enums.

Added some new tests for the binding flags handling.

Reenabled some disabled tests for analyzer.
Moved the main affected tests from the generated source files to the hardcoded one and force them to exact match of warnings for both linker and analyzer.

private partial IEnumerable<SystemReflectionMethodBaseValue> GetMethodsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
{
foreach (var method in type.Type.GetMethodsOnTypeHierarchy (m => m.Name == name, bindingFlags))
yield return new SystemReflectionMethodBaseValue (new MethodProxy (method));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is going to cause a quadratic number of calls in the depth of the tree. Since iterators are lazy, we'll walk all the way down the tree to fetch the first element, then walk n-1 levels to fetch the second, and so on.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I don't understand. The GetMethodsOnTypeHierarchy helper we're calling here already uses iterator, so this is basically just a pass through...

I guess I could rewrite both to use ImmutableArray...

I must admit I don't understand what the problem is.

@@ -88,6 +104,35 @@ public override MultiValue VisitLiteral (ILiteralOperation literalOperation, Sta
return literalOperation.ConstantValue.Value == null ? NullValue.Instance : TopValue;
}

public override MultiValue VisitBinaryOperator (IBinaryOperation operation, StateValue argument)
Copy link
Member

@agocke agocke Feb 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this locally and it looks like operation has a constant value for many of the tests. Is there a specific case I'm missing where it doesn't and we need to evaluate manually? And is it worth checking the ConstantValue anyway for the easy cases?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right - I was looking at the ArgumentOperation which is the parent of this and that one doesn't have a constant value. I'll improve this to use the Roslyns const evaluator when available.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could maybe put it in the top-level Visit(IOperation) helper, unless there's some reason we would want to skip that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm kind of split on that - it's semi-dangerous. It would mean that the actual specific operation visitor method would not have final say in what the return value is. Maybe not a big deal... I'll probably do it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with that approach - Visit(IOperation) now handles constants (if the operation specific visit doesn't provide a value). It solves lot of easy cases and works generally for things like null and strings as well.
I kept the BinaryOperation visitor as there are cases where it still works (if one or both of the operands are local variables for example - that requires data flow to figure out values, so constant detection itself doesn't do it) and also as a sample what we would need to add for other operators if necessary.

Copy link
Member

@sbomer sbomer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you!

Other than sharing more code and adapting it so that it works on both linker and analyzer, this change brings simple analysis of constant integer values in the analyzer. This is necessary to make most reflection API calls recognize binding flags. For example `GetMethods(BindingFlags.Public | BindingFlags.Static)`. So this change adds analysis of constant values (as recognized by the Roslyn's operation tree) and the OR binary operator for integers and enums.

Added some new tests for the binding flags handling.

Reenabled some disabled tests for analyzer.
Moved the main affected tests from the generated source files to the hardcoded one and force them to exact match of warnings for both linker and analyzer.
Detect constant expressions generally for all operations and return the constant value representation.
@vitek-karas vitek-karas merged commit f0bd2ae into dotnet:main Feb 28, 2022
@vitek-karas vitek-karas deleted the IntrinsicMembers branch February 28, 2022 11:48
agocke pushed a commit to dotnet/runtime that referenced this pull request Nov 16, 2022
…#2639)

Other than sharing more code and adapting it so that it works on both linker and analyzer, this change brings simple analysis of constant integer values in the analyzer. This is necessary to make most reflection API calls recognize binding flags. For example `GetMethods(BindingFlags.Public | BindingFlags.Static)`. So this change adds analysis of constant values (as recognized by the Roslyn's operation tree) and the OR binary operator for integers and enums.

Added some new tests for the binding flags handling.

Reenabled some disabled tests for analyzer.
Moved the main affected tests from the generated source files to the hardcoded one and force them to exact match of warnings for both linker and analyzer.

Commit migrated from dotnet/linker@f0bd2ae
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants