Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs37
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs8
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs33
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs67
-rw-r--r--src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs411
-rw-r--r--src/ILLink.Shared/TrimAnalysis/SystemReflectionMethodBaseValue.cs10
-rw-r--r--src/linker/Linker.Dataflow/HandleCallAction.cs36
-rw-r--r--src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs446
-rw-r--r--src/linker/Linker.Dataflow/ValueNode.cs12
-rw-r--r--test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs33
-rw-r--r--test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs72
-rw-r--r--test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs48
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs27
-rw-r--r--test/Mono.Linker.Tests.Cases/DataFlow/DynamicDependencyDataflow.cs6
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs81
-rw-r--r--test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAccessedThrough.cs4
-rw-r--r--test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs32
-rw-r--r--test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresWithCopyAssembly.cs2
18 files changed, 795 insertions, 570 deletions
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs
index d0a7af8c7..ebb14a434 100644
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs
@@ -1,8 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
using ILLink.RoslynAnalyzer;
+using ILLink.RoslynAnalyzer.DataFlow;
using ILLink.RoslynAnalyzer.TrimAnalysis;
using ILLink.Shared.TypeSystemProxy;
using Microsoft.CodeAnalysis;
@@ -16,13 +19,15 @@ namespace ILLink.Shared.TrimAnalysis
readonly ISymbol _owningSymbol;
readonly IOperation _operation;
+ readonly ReflectionAccessAnalyzer _reflectionAccessAnalyzer;
public HandleCallAction (in DiagnosticContext diagnosticContext, ISymbol owningSymbol, IOperation operation)
{
_owningSymbol = owningSymbol;
_operation = operation;
_diagnosticContext = diagnosticContext;
- _requireDynamicallyAccessedMembersAction = new (diagnosticContext, new ReflectionAccessAnalyzer ());
+ _reflectionAccessAnalyzer = new ReflectionAccessAnalyzer ();
+ _requireDynamicallyAccessedMembersAction = new (diagnosticContext, _reflectionAccessAnalyzer);
}
// TODO: This is relatively expensive on the analyzer since it doesn't cache the annotation information
@@ -41,9 +46,39 @@ namespace ILLink.Shared.TrimAnalysis
private partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
=> new (method.Method, dynamicallyAccessedMemberTypes);
+ private partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => new (method.Method.Parameters[parameterIndex], dynamicallyAccessedMemberTypes);
+
+ 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));
+ }
+
+ private partial IEnumerable<SystemTypeValue> GetNestedTypesOnType (TypeProxy type, string name, BindingFlags? bindingFlags)
+ {
+ foreach (var nestedType in type.Type.GetNestedTypesOnType (t => t.Name == name, bindingFlags))
+ yield return new SystemTypeValue (new TypeProxy (nestedType));
+ }
+
// TODO: Does the analyzer need to do something here?
private partial void MarkStaticConstructor (TypeProxy type) { }
+ private partial void MarkEventsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForEventsOnTypeHierarchy (_diagnosticContext, type.Type, name, bindingFlags);
+
+ private partial void MarkFieldsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForFieldsOnTypeHierarchy (_diagnosticContext, type.Type, name, bindingFlags);
+
+ private partial void MarkPropertiesOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForPropertiesOnTypeHierarchy (_diagnosticContext, type.Type, name, bindingFlags);
+
+ private partial void MarkMethod (MethodProxy method)
+ => ReflectionAccessAnalyzer.GetReflectionAccessDiagnosticsForMethod (_diagnosticContext, method.Method);
+
+ // TODO: Does the analyzer need to do something here?
+ private partial void MarkType (TypeProxy type) { }
+
private partial string GetContainingSymbolDisplayName () => _operation.FindContainingSymbol (_owningSymbol).GetDisplayName ();
}
}
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs
index e7b44d8a2..0aa1abbcf 100644
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodParameterValue.cs
@@ -11,11 +11,15 @@ namespace ILLink.Shared.TrimAnalysis
{
partial record MethodParameterValue
{
- public MethodParameterValue (IParameterSymbol parameterSymbol) => ParameterSymbol = parameterSymbol;
+ public MethodParameterValue (IParameterSymbol parameterSymbol)
+ : this (parameterSymbol, FlowAnnotations.GetMethodParameterAnnotation (parameterSymbol)) { }
+
+ public MethodParameterValue (IParameterSymbol parameterSymbol, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => (ParameterSymbol, DynamicallyAccessedMemberTypes) = (parameterSymbol, dynamicallyAccessedMemberTypes);
public readonly IParameterSymbol ParameterSymbol;
- public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes => FlowAnnotations.GetMethodParameterAnnotation (ParameterSymbol);
+ public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch ()
=> new string[] { ParameterSymbol.GetDisplayName (), ParameterSymbol.ContainingSymbol.GetDisplayName () };
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs
index b22fb9fde..b5663698a 100644
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
using ILLink.RoslynAnalyzer.DataFlow;
using ILLink.Shared;
using ILLink.Shared.TrimAnalysis;
@@ -17,7 +18,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
foreach (var member in typeSymbol.GetDynamicallyAccessedMembers (requiredMemberTypes, declaredOnly)) {
switch (member) {
case IMethodSymbol method:
- GetDiagnosticsForMethod (diagnosticContext, method);
+ GetReflectionAccessDiagnosticsForMethod (diagnosticContext, method);
break;
case IFieldSymbol field:
GetDiagnosticsForField (diagnosticContext, field);
@@ -40,6 +41,24 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
}
}
+ internal void GetReflectionAccessDiagnosticsForEventsOnTypeHierarchy (in DiagnosticContext diagnosticContext, ITypeSymbol typeSymbol, string name, BindingFlags? bindingFlags)
+ {
+ foreach (var @event in typeSymbol.GetEventsOnTypeHierarchy (e => e.Name == name, bindingFlags))
+ GetDiagnosticsForEvent (diagnosticContext, @event);
+ }
+
+ internal void GetReflectionAccessDiagnosticsForFieldsOnTypeHierarchy (in DiagnosticContext diagnosticContext, ITypeSymbol typeSymbol, string name, BindingFlags? bindingFlags)
+ {
+ foreach (var field in typeSymbol.GetFieldsOnTypeHierarchy (f => f.Name == name, bindingFlags))
+ GetDiagnosticsForField (diagnosticContext, field);
+ }
+
+ internal void GetReflectionAccessDiagnosticsForPropertiesOnTypeHierarchy (in DiagnosticContext diagnosticContext, ITypeSymbol typeSymbol, string name, BindingFlags? bindingFlags)
+ {
+ foreach (var prop in typeSymbol.GetPropertiesOnTypeHierarchy (p => p.Name == name, bindingFlags))
+ GetDiagnosticsForProperty (diagnosticContext, prop);
+ }
+
static void ReportRequiresUnreferencedCodeDiagnostic (in DiagnosticContext diagnosticContext, AttributeData requiresAttributeData, ISymbol member)
{
var message = RequiresUnreferencedCodeUtils.GetMessageFromAttribute (requiresAttributeData);
@@ -47,7 +66,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
diagnosticContext.AddDiagnostic (DiagnosticId.RequiresUnreferencedCode, member.GetDisplayName (), message, url);
}
- static void GetDiagnosticsForMethod (in DiagnosticContext diagnosticContext, IMethodSymbol methodSymbol)
+ internal static void GetReflectionAccessDiagnosticsForMethod (in DiagnosticContext diagnosticContext, IMethodSymbol methodSymbol)
{
if (methodSymbol.TryGetRequiresUnreferencedCodeAttribute (out var requiresAttributeData))
ReportRequiresUnreferencedCodeDiagnostic (diagnosticContext, requiresAttributeData, methodSymbol);
@@ -69,19 +88,19 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
static void GetDiagnosticsForProperty (in DiagnosticContext diagnosticContext, IPropertySymbol propertySymbol)
{
if (propertySymbol.SetMethod is not null)
- GetDiagnosticsForMethod (diagnosticContext, propertySymbol.SetMethod);
+ GetReflectionAccessDiagnosticsForMethod (diagnosticContext, propertySymbol.SetMethod);
if (propertySymbol.GetMethod is not null)
- GetDiagnosticsForMethod (diagnosticContext, propertySymbol.GetMethod);
+ GetReflectionAccessDiagnosticsForMethod (diagnosticContext, propertySymbol.GetMethod);
}
static void GetDiagnosticsForEvent (in DiagnosticContext diagnosticContext, IEventSymbol eventSymbol)
{
if (eventSymbol.AddMethod is not null)
- GetDiagnosticsForMethod (diagnosticContext, eventSymbol.AddMethod);
+ GetReflectionAccessDiagnosticsForMethod (diagnosticContext, eventSymbol.AddMethod);
if (eventSymbol.RemoveMethod is not null)
- GetDiagnosticsForMethod (diagnosticContext, eventSymbol.RemoveMethod);
+ GetReflectionAccessDiagnosticsForMethod (diagnosticContext, eventSymbol.RemoveMethod);
if (eventSymbol.RaiseMethod is not null)
- GetDiagnosticsForMethod (diagnosticContext, eventSymbol.RaiseMethod);
+ GetReflectionAccessDiagnosticsForMethod (diagnosticContext, eventSymbol.RaiseMethod);
}
static void GetDiagnosticsForField (in DiagnosticContext diagnosticContext, IFieldSymbol fieldSymbol)
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs
index 7a61a03a8..04b3367e0 100644
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs
@@ -22,12 +22,15 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
{
public readonly TrimAnalysisPatternStore TrimAnalysisPatterns;
+ readonly ValueSetLattice<SingleValue> _multiValueLattice;
+
public TrimAnalysisVisitor (
LocalStateLattice<MultiValue, ValueSetLattice<SingleValue>> lattice,
OperationBlockAnalysisContext context
) : base (lattice, context)
{
- TrimAnalysisPatterns = new TrimAnalysisPatternStore (lattice.Lattice.ValueLattice);
+ _multiValueLattice = lattice.Lattice.ValueLattice;
+ TrimAnalysisPatterns = new TrimAnalysisPatternStore (_multiValueLattice);
}
// Override visitor methods to create tracked values when visiting operations
@@ -36,6 +39,26 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
// - 'this' parameter (for annotated methods)
// - field reference
+ public override MultiValue Visit (IOperation? operation, StateValue argument)
+ {
+ var returnValue = base.Visit (operation, argument);
+
+ // If the return value is empty (TopValue basically) and the Operation tree
+ // reports it as having a constant value, use that as it will automatically cover
+ // cases we don't need/want to handle.
+ if (operation != null && returnValue.IsEmpty () && operation.ConstantValue.HasValue) {
+ object? constantValue = operation.ConstantValue.Value;
+ if (constantValue == null)
+ return NullValue.Instance;
+ else if (operation.Type?.SpecialType == SpecialType.System_String && constantValue is string stringConstantValue)
+ return new KnownStringValue (stringConstantValue);
+ else if (operation.Type?.TypeKind == TypeKind.Enum && constantValue is int intConstantValue)
+ return new ConstIntValue (intConstantValue);
+ }
+
+ return returnValue;
+ }
+
public override MultiValue VisitConversion (IConversionOperation operation, StateValue state)
{
var value = base.VisitConversion (operation, state);
@@ -70,14 +93,15 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
public override MultiValue VisitFieldReference (IFieldReferenceOperation fieldRef, StateValue state)
{
- if (!fieldRef.Field.Type.IsTypeInterestingForDataflow ())
- return TopValue;
+ if (fieldRef.Field.Type.IsTypeInterestingForDataflow ()) {
+ var field = fieldRef.Field;
+ if (field.Name is "Empty" && field.ContainingType.HasName ("System.String"))
+ return new KnownStringValue (string.Empty);
- var field = fieldRef.Field;
- if (field.Name is "Empty" && field.ContainingType.HasName ("System.String"))
- return new KnownStringValue (string.Empty);
+ return new FieldValue (fieldRef.Field);
+ }
- return new FieldValue (fieldRef.Field);
+ return TopValue;
}
public override MultiValue VisitTypeOf (ITypeOfOperation typeOfOperation, StateValue state)
@@ -90,9 +114,34 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
return TopValue;
}
- public override MultiValue VisitLiteral (ILiteralOperation literalOperation, StateValue state)
+ public override MultiValue VisitBinaryOperator (IBinaryOperation operation, StateValue argument)
{
- return literalOperation.ConstantValue.Value == null ? NullValue.Instance : TopValue;
+ if (!operation.ConstantValue.HasValue && // Optimization - if there is already a constant value available, rely on the Visit(IOperation) instead
+ operation.OperatorKind == BinaryOperatorKind.Or &&
+ operation.OperatorMethod is null &&
+ (operation.Type?.TypeKind == TypeKind.Enum || operation.Type?.SpecialType == SpecialType.System_Int32)) {
+ MultiValue leftValue = Visit (operation.LeftOperand, argument);
+ MultiValue rightValue = Visit (operation.RightOperand, argument);
+
+ MultiValue result = TopValue;
+ foreach (var left in leftValue) {
+ if (left is UnknownValue)
+ result = _multiValueLattice.Meet (result, left);
+ else if (left is ConstIntValue leftConstInt) {
+ foreach (var right in rightValue) {
+ if (right is UnknownValue)
+ result = _multiValueLattice.Meet (result, right);
+ else if (right is ConstIntValue rightConstInt) {
+ result = _multiValueLattice.Meet (result, new ConstIntValue (leftConstInt.Value | rightConstInt.Value));
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ return base.VisitBinaryOperator (operation, argument);
}
// Override handlers for situations where annotated locations may be involved in reflection access:
diff --git a/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs b/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs
index ee8c257e0..57a48187b 100644
--- a/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs
+++ b/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
using System.Runtime.InteropServices;
using ILLink.Shared.DataFlow;
using ILLink.Shared.TypeSystemProxy;
@@ -147,6 +148,313 @@ namespace ILLink.Shared.TrimAnalysis
}
break;
+ //
+ // GetConstructors (BindingFlags)
+ // GetMethods (BindingFlags)
+ // GetFields (BindingFlags)
+ // GetEvents (BindingFlags)
+ // GetProperties (BindingFlags)
+ // GetNestedTypes (BindingFlags)
+ // GetMembers (BindingFlags)
+ //
+ case var callType when (callType == IntrinsicId.Type_GetConstructors || callType == IntrinsicId.Type_GetMethods || callType == IntrinsicId.Type_GetFields ||
+ callType == IntrinsicId.Type_GetProperties || callType == IntrinsicId.Type_GetEvents || callType == IntrinsicId.Type_GetNestedTypes || callType == IntrinsicId.Type_GetMembers)
+ && calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.Reflection.BindingFlags")
+ && !calledMethod.IsStatic (): {
+
+ BindingFlags? bindingFlags;
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[0]);
+ DynamicallyAccessedMemberTypes memberTypes;
+ if (BindingFlagsAreUnsupported (bindingFlags)) {
+ memberTypes = callType switch {
+ IntrinsicId.Type_GetConstructors => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors,
+ IntrinsicId.Type_GetMethods => DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods,
+ IntrinsicId.Type_GetEvents => DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents,
+ IntrinsicId.Type_GetFields => DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields,
+ IntrinsicId.Type_GetProperties => DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties,
+ IntrinsicId.Type_GetNestedTypes => DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
+ IntrinsicId.Type_GetMembers => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
+ DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
+ DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
+ DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
+ DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
+ DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
+ _ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
+ };
+ } else {
+ memberTypes = callType switch {
+ IntrinsicId.Type_GetConstructors => GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags),
+ IntrinsicId.Type_GetMethods => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags),
+ IntrinsicId.Type_GetEvents => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags),
+ IntrinsicId.Type_GetFields => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags),
+ IntrinsicId.Type_GetProperties => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags),
+ IntrinsicId.Type_GetNestedTypes => GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags),
+ IntrinsicId.Type_GetMembers => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (bindingFlags),
+ _ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
+ };
+ }
+
+ var targetValue = GetMethodThisParameterValue (calledMethod, memberTypes);
+ _requireDynamicallyAccessedMembersAction.Invoke (instanceValue, targetValue);
+ }
+ break;
+
+ //
+ // GetField (string)
+ // GetField (string, BindingFlags)
+ // GetEvent (string)
+ // GetEvent (string, BindingFlags)
+ // GetProperty (string)
+ // GetProperty (string, BindingFlags)
+ // GetProperty (string, Type)
+ // GetProperty (string, Type[])
+ // GetProperty (string, Type, Type[])
+ // GetProperty (string, Type, Type[], ParameterModifier[])
+ // GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[])
+ //
+ case var fieldPropertyOrEvent when (fieldPropertyOrEvent == IntrinsicId.Type_GetField || fieldPropertyOrEvent == IntrinsicId.Type_GetProperty || fieldPropertyOrEvent == IntrinsicId.Type_GetEvent)
+ && calledMethod.IsDeclaredOnType ("System.Type")
+ && calledMethod.HasParameterOfType (0, "System.String")
+ && !calledMethod.IsStatic (): {
+
+ BindingFlags? bindingFlags;
+ if (calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
+ else
+ // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
+ bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
+
+ DynamicallyAccessedMemberTypes memberTypes = fieldPropertyOrEvent switch {
+ IntrinsicId.Type_GetEvent => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags),
+ IntrinsicId.Type_GetField => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags),
+ IntrinsicId.Type_GetProperty => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags),
+ _ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
+ };
+
+ var targetValue = GetMethodThisParameterValue (calledMethod, memberTypes);
+ foreach (var value in instanceValue) {
+ if (value is SystemTypeValue systemTypeValue) {
+ foreach (var stringParam in argumentValues[0]) {
+ if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
+ switch (fieldPropertyOrEvent) {
+ case IntrinsicId.Type_GetEvent:
+ MarkEventsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ case IntrinsicId.Type_GetField:
+ MarkFieldsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ case IntrinsicId.Type_GetProperty:
+ MarkPropertiesOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ default:
+ Debug.Fail ("Unreachable.");
+ break;
+ }
+ } else {
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ } else {
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ }
+ break;
+
+ //
+ // GetMember (String)
+ // GetMember (String, BindingFlags)
+ // GetMember (String, MemberTypes, BindingFlags)
+ //
+ case IntrinsicId.Type_GetMember: {
+ BindingFlags? bindingFlags;
+ if (calledMethod.HasParametersCount (1)) {
+ // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
+ bindingFlags = BindingFlags.Public | BindingFlags.Instance;
+ } else if (calledMethod.HasParametersCount (2) && calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
+ else if (calledMethod.HasParametersCount (3) && calledMethod.HasParameterOfType (2, "System.Reflection.BindingFlags")) {
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[2]);
+ } else // Non recognized intrinsic
+ throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is an unexpected intrinsic.");
+
+ DynamicallyAccessedMemberTypes requiredMemberTypes;
+ if (BindingFlagsAreUnsupported (bindingFlags)) {
+ requiredMemberTypes = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
+ DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
+ DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
+ DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
+ DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
+ DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
+ } else {
+ requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (bindingFlags);
+ }
+
+ var targetValue = GetMethodThisParameterValue (calledMethod, requiredMemberTypes);
+
+ // Go over all types we've seen
+ foreach (var value in instanceValue) {
+ // Mark based on bitfield requirements
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ break;
+
+ //
+ // GetMethod (string)
+ // GetMethod (string, BindingFlags)
+ // GetMethod (string, Type[])
+ // GetMethod (string, Type[], ParameterModifier[])
+ // GetMethod (string, BindingFlags, Type[])
+ // GetMethod (string, BindingFlags, Binder, Type[], ParameterModifier[])
+ // GetMethod (string, BindingFlags, Binder, CallingConventions, Type[], ParameterModifier[])
+ // GetMethod (string, int, Type[])
+ // GetMethod (string, int, Type[], ParameterModifier[]?)
+ // GetMethod (string, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
+ // GetMethod (string, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
+ //
+ case IntrinsicId.Type_GetMethod: {
+ BindingFlags? bindingFlags;
+ if (calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
+ else if (calledMethod.HasParameterOfType (2, "System.Reflection.BindingFlags"))
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[2]);
+ else
+ // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
+ bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
+
+ var targetValue = GetMethodThisParameterValue (calledMethod, GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags));
+ foreach (var value in instanceValue) {
+ if (value is SystemTypeValue systemTypeValue) {
+ foreach (var stringParam in argumentValues[0]) {
+ if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
+ foreach (var methodValue in ProcessGetMethodByName (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags))
+ AddReturnValue (methodValue);
+ } else {
+ // Otherwise fall back to the bitfield requirements
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ } else {
+ // Otherwise fall back to the bitfield requirements
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ }
+ break;
+
+ //
+ // GetNestedType (string)
+ // GetNestedType (string, BindingFlags)
+ //
+ case IntrinsicId.Type_GetNestedType: {
+ BindingFlags? bindingFlags;
+ if (calledMethod.HasParameterOfType (1, "System.Reflection.BindingFlags"))
+ bindingFlags = GetBindingFlagsFromValue (argumentValues[1]);
+ else
+ // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
+ bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
+
+ var targetValue = GetMethodThisParameterValue (calledMethod, GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags));
+ bool everyParentTypeHasAll = true;
+ foreach (var value in instanceValue) {
+ if (value is SystemTypeValue systemTypeValue) {
+ foreach (var stringParam in argumentValues[0]) {
+ if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
+ foreach (var nestedTypeValue in GetNestedTypesOnType (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags)) {
+ MarkType (nestedTypeValue.RepresentedType);
+ AddReturnValue (nestedTypeValue);
+ }
+ } else {
+ // Otherwise fall back to the bitfield requirements
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ } else {
+ // Otherwise fall back to the bitfield requirements
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+
+ if (value is ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers) {
+ if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.All)
+ everyParentTypeHasAll = false;
+ } else if (!(value is NullValue || value is SystemTypeValue)) {
+ // Known Type values are always OK - either they're fully resolved above and thus the return value
+ // is set to the known resolved type, or if they're not resolved, they won't exist at runtime
+ // and will cause exceptions - and thus don't introduce new requirements on marking.
+ // nulls are intentionally ignored as they will lead to exceptions at runtime
+ // and thus don't introduce new requirements on marking.
+ everyParentTypeHasAll = false;
+ }
+ }
+
+ // If the parent type (all the possible values) has DynamicallyAccessedMemberTypes.All it means its nested types are also fully marked
+ // (see MarkStep.MarkEntireType - it will recursively mark entire type on nested types). In that case we can annotate
+ // the returned type (the nested type) with DynamicallyAccessedMemberTypes.All as well.
+ // Note it's OK to blindly overwrite any potential annotation on the return value from the method definition
+ // since DynamicallyAccessedMemberTypes.All is a superset of any other annotation.
+ if (everyParentTypeHasAll && returnValue == null)
+ returnValue = GetMethodReturnValue (calledMethod, DynamicallyAccessedMemberTypes.All);
+ }
+ break;
+
+ //
+ // System.Reflection.RuntimeReflectionExtensions
+ //
+ // static GetRuntimeEvent (this Type type, string name)
+ // static GetRuntimeField (this Type type, string name)
+ // static GetRuntimeMethod (this Type type, string name, Type[] parameters)
+ // static GetRuntimeProperty (this Type type, string name)
+ //
+ case var getRuntimeMember when getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty: {
+
+ BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
+ DynamicallyAccessedMemberTypes requiredMemberTypes = getRuntimeMember switch {
+ IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent => DynamicallyAccessedMemberTypes.PublicEvents,
+ IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField => DynamicallyAccessedMemberTypes.PublicFields,
+ IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod => DynamicallyAccessedMemberTypes.PublicMethods,
+ IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty => DynamicallyAccessedMemberTypes.PublicProperties,
+ _ => throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{GetContainingSymbolDisplayName ()}' is of unexpected member type."),
+ };
+
+ var targetValue = GetMethodParameterValue (calledMethod, 0, requiredMemberTypes);
+
+ foreach (var value in argumentValues[0]) {
+ if (value is SystemTypeValue systemTypeValue) {
+ foreach (var stringParam in argumentValues[1]) {
+ if (stringParam is KnownStringValue stringValue) {
+ switch (getRuntimeMember) {
+ case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent:
+ MarkEventsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField:
+ MarkFieldsOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod:
+ foreach (var methodValue in ProcessGetMethodByName (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags))
+ AddReturnValue (methodValue);
+ break;
+ case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty:
+ MarkPropertiesOnTypeHierarchy (systemTypeValue.RepresentedType, stringValue.Contents, bindingFlags);
+ break;
+ default:
+ throw new ArgumentException ($"Error processing reflection call '{calledMethod.GetDisplayName ()}' inside {GetContainingSymbolDisplayName ()}. Unexpected member kind.");
+ }
+ } else {
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ } else {
+ _requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
+ }
+ }
+ }
+ break;
+
case IntrinsicId.None:
methodReturnValue = MultiValueLattice.Top;
return false;
@@ -188,6 +496,93 @@ namespace ILLink.Shared.TrimAnalysis
}
}
+ IEnumerable<MultiValue> ProcessGetMethodByName (TypeProxy type, string methodName, BindingFlags? bindingFlags)
+ {
+ bool foundAny = false;
+ foreach (var method in GetMethodsOnTypeHierarchy (type, methodName, bindingFlags)) {
+ MarkMethod (method.MethodRepresented);
+ yield return method;
+ foundAny = true;
+ }
+
+ // If there were no methods found the API will return null at runtime, so we should
+ // track the null as a return value as well.
+ // This also prevents warnings in such case, since if we don't set the return value it will be
+ // "unknown" and consumers may warn.
+ if (!foundAny)
+ yield return NullValue.Instance;
+ }
+
+ internal static BindingFlags? GetBindingFlagsFromValue (in MultiValue parameter) => (BindingFlags?) parameter.AsConstInt ();
+
+ internal static bool BindingFlagsAreUnsupported (BindingFlags? bindingFlags)
+ {
+ if (bindingFlags == null)
+ return true;
+
+ // Binding flags we understand
+ const BindingFlags UnderstoodBindingFlags =
+ BindingFlags.DeclaredOnly |
+ BindingFlags.Instance |
+ BindingFlags.Static |
+ BindingFlags.Public |
+ BindingFlags.NonPublic |
+ BindingFlags.FlattenHierarchy |
+ BindingFlags.ExactBinding;
+
+ // Binding flags that don't affect binding outside InvokeMember (that we don't analyze).
+ const BindingFlags IgnorableBindingFlags =
+ BindingFlags.InvokeMethod |
+ BindingFlags.CreateInstance |
+ BindingFlags.GetField |
+ BindingFlags.SetField |
+ BindingFlags.GetProperty |
+ BindingFlags.SetProperty;
+
+ BindingFlags flags = bindingFlags.Value;
+ return (flags & ~(UnderstoodBindingFlags | IgnorableBindingFlags)) != 0;
+ }
+
+ internal static bool HasBindingFlag (BindingFlags? bindingFlags, BindingFlags? search) => bindingFlags != null && (bindingFlags & search) == search;
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicNestedTypes : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicConstructors : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicMethods : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicFields : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicProperties : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (BindingFlags? bindingFlags) =>
+ (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicEvents : DynamicallyAccessedMemberTypes.None) |
+ (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None) |
+ (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None);
+
+ internal static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (BindingFlags? bindingFlags) =>
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags) |
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags) |
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags) |
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags) |
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags) |
+ GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags);
+
private partial bool MethodRequiresDataFlowAnalysis (MethodProxy method);
private partial DynamicallyAccessedMemberTypes GetReturnValueAnnotation (MethodProxy method);
@@ -198,8 +593,24 @@ namespace ILLink.Shared.TrimAnalysis
private partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
+ private partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
+
+ private partial IEnumerable<SystemReflectionMethodBaseValue> GetMethodsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags);
+
+ private partial IEnumerable<SystemTypeValue> GetNestedTypesOnType (TypeProxy type, string name, BindingFlags? bindingFlags);
+
private partial void MarkStaticConstructor (TypeProxy type);
+ private partial void MarkEventsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags);
+
+ private partial void MarkFieldsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags);
+
+ private partial void MarkPropertiesOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags);
+
+ private partial void MarkMethod (MethodProxy method);
+
+ private partial void MarkType (TypeProxy type);
+
// Only used for internal diagnostic purposes (not even for warning messages)
private partial string GetContainingSymbolDisplayName ();
}
diff --git a/src/ILLink.Shared/TrimAnalysis/SystemReflectionMethodBaseValue.cs b/src/ILLink.Shared/TrimAnalysis/SystemReflectionMethodBaseValue.cs
index 945b64262..a32d52fea 100644
--- a/src/ILLink.Shared/TrimAnalysis/SystemReflectionMethodBaseValue.cs
+++ b/src/ILLink.Shared/TrimAnalysis/SystemReflectionMethodBaseValue.cs
@@ -2,11 +2,19 @@
// The .NET Foundation licenses this file to you under the MIT license.
using ILLink.Shared.DataFlow;
+using ILLink.Shared.TypeSystemProxy;
namespace ILLink.Shared.TrimAnalysis
{
/// <summary>
/// This is a known System.Reflection.MethodBase value. MethodRepresented is the 'value' of the MethodBase.
/// </summary>
- sealed partial record SystemReflectionMethodBaseValue : SingleValue;
+ sealed partial record SystemReflectionMethodBaseValue : SingleValue
+ {
+ public SystemReflectionMethodBaseValue (MethodProxy methodRepresented) => MethodRepresented = methodRepresented;
+
+ public readonly MethodProxy MethodRepresented;
+
+ public override string ToString () => this.ValueToString (MethodRepresented);
+ }
}
diff --git a/src/linker/Linker.Dataflow/HandleCallAction.cs b/src/linker/Linker.Dataflow/HandleCallAction.cs
index b3f3d1c25..b88e6d8e9 100644
--- a/src/linker/Linker.Dataflow/HandleCallAction.cs
+++ b/src/linker/Linker.Dataflow/HandleCallAction.cs
@@ -1,7 +1,9 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
using Mono.Linker;
@@ -47,9 +49,43 @@ namespace ILLink.Shared.TrimAnalysis
private partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
=> new (method.Method, dynamicallyAccessedMemberTypes);
+ private partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => new (
+ ReflectionMethodBodyScanner.ResolveToTypeDefinition (_context, method.Method.Parameters[parameterIndex].ParameterType),
+ method.Method,
+ parameterIndex,
+ dynamicallyAccessedMemberTypes);
+
+ private partial IEnumerable<SystemReflectionMethodBaseValue> GetMethodsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
+ {
+ foreach (var method in type.Type.GetMethodsOnTypeHierarchy (_context, m => m.Name == name, bindingFlags))
+ yield return new SystemReflectionMethodBaseValue (new MethodProxy (method));
+ }
+
+ private partial IEnumerable<SystemTypeValue> GetNestedTypesOnType (TypeProxy type, string name, BindingFlags? bindingFlags)
+ {
+ foreach (var nestedType in type.Type.GetNestedTypesOnType (t => t.Name == name, bindingFlags))
+ yield return new SystemTypeValue (new TypeProxy (nestedType));
+ }
+
private partial void MarkStaticConstructor (TypeProxy type)
=> _reflectionMethodBodyScanner.MarkStaticConstructor (_analysisContext, type.Type);
+ private partial void MarkEventsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionMethodBodyScanner.MarkEventsOnTypeHierarchy (_analysisContext, type.Type, e => e.Name == name, bindingFlags);
+
+ private partial void MarkFieldsOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionMethodBodyScanner.MarkFieldsOnTypeHierarchy (_analysisContext, type.Type, f => f.Name == name, bindingFlags);
+
+ private partial void MarkPropertiesOnTypeHierarchy (TypeProxy type, string name, BindingFlags? bindingFlags)
+ => _reflectionMethodBodyScanner.MarkPropertiesOnTypeHierarchy (_analysisContext, type.Type, p => p.Name == name, bindingFlags);
+
+ private partial void MarkMethod (MethodProxy method)
+ => _reflectionMethodBodyScanner.MarkMethod (_analysisContext, method.Method);
+
+ private partial void MarkType (TypeProxy type)
+ => _reflectionMethodBodyScanner.MarkType (_analysisContext, type.Type);
+
private partial string GetContainingSymbolDisplayName () => _callingMethodDefinition.GetDisplayName ();
}
}
diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
index 4ae5b0b9a..1358a5ff3 100644
--- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
@@ -269,7 +269,25 @@ namespace Mono.Linker.Dataflow
case IntrinsicId.Type_get_TypeHandle:
case IntrinsicId.Type_GetInterface:
case IntrinsicId.Type_get_AssemblyQualifiedName:
- case IntrinsicId.RuntimeHelpers_RunClassConstructor: {
+ case IntrinsicId.RuntimeHelpers_RunClassConstructor:
+ case var callType when (callType == IntrinsicId.Type_GetConstructors || callType == IntrinsicId.Type_GetMethods || callType == IntrinsicId.Type_GetFields ||
+ callType == IntrinsicId.Type_GetProperties || callType == IntrinsicId.Type_GetEvents || callType == IntrinsicId.Type_GetNestedTypes || callType == IntrinsicId.Type_GetMembers)
+ && calledMethod.DeclaringType.Namespace == "System"
+ && calledMethod.DeclaringType.Name == "Type"
+ && calledMethod.Parameters[0].ParameterType.FullName == "System.Reflection.BindingFlags"
+ && calledMethod.HasThis:
+ case var fieldPropertyOrEvent when (fieldPropertyOrEvent == IntrinsicId.Type_GetField || fieldPropertyOrEvent == IntrinsicId.Type_GetProperty || fieldPropertyOrEvent == IntrinsicId.Type_GetEvent)
+ && calledMethod.DeclaringType.Namespace == "System"
+ && calledMethod.DeclaringType.Name == "Type"
+ && calledMethod.Parameters[0].ParameterType.FullName == "System.String"
+ && calledMethod.HasThis:
+ case var getRuntimeMember when getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod
+ || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty:
+ case IntrinsicId.Type_GetMember:
+ case IntrinsicId.Type_GetMethod:
+ case IntrinsicId.Type_GetNestedType: {
var instanceValue = MultiValueLattice.Top;
IReadOnlyList<MultiValue> parameterValues = methodParams;
if (calledMethodDefinition.HasImplicitThis ()) {
@@ -344,61 +362,6 @@ namespace Mono.Linker.Dataflow
break;
//
- // System.Reflection.RuntimeReflectionExtensions
- //
- // static GetRuntimeEvent (this Type type, string name)
- // static GetRuntimeField (this Type type, string name)
- // static GetRuntimeMethod (this Type type, string name, Type[] parameters)
- // static GetRuntimeProperty (this Type type, string name)
- //
- case var getRuntimeMember when getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent
- || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField
- || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod
- || getRuntimeMember == IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty: {
-
- BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
- DynamicallyAccessedMemberTypes requiredMemberTypes = getRuntimeMember switch {
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent => DynamicallyAccessedMemberTypes.PublicEvents,
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField => DynamicallyAccessedMemberTypes.PublicFields,
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod => DynamicallyAccessedMemberTypes.PublicMethods,
- IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty => DynamicallyAccessedMemberTypes.PublicProperties,
- _ => throw new InternalErrorException ($"Reflection call '{calledMethodDefinition.GetDisplayName ()}' inside '{callingMethodDefinition.GetDisplayName ()}' is of unexpected member type."),
- };
-
- var targetValue = GetMethodParameterValue (calledMethodDefinition, 0, requiredMemberTypes);
-
- foreach (var value in methodParams[0]) {
- if (value is SystemTypeValue systemTypeValue) {
- foreach (var stringParam in methodParams[1]) {
- if (stringParam is KnownStringValue stringValue) {
- switch (getRuntimeMember) {
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeEvent:
- MarkEventsOnTypeHierarchy (analysisContext, systemTypeValue.RepresentedType.Type, e => e.Name == stringValue.Contents, bindingFlags);
- break;
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeField:
- MarkFieldsOnTypeHierarchy (analysisContext, systemTypeValue.RepresentedType.Type, f => f.Name == stringValue.Contents, bindingFlags);
- break;
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeMethod:
- ProcessGetMethodByName (analysisContext, systemTypeValue.RepresentedType.Type, stringValue.Contents, bindingFlags, ref methodReturnValue);
- break;
- case IntrinsicId.RuntimeReflectionExtensions_GetRuntimeProperty:
- MarkPropertiesOnTypeHierarchy (analysisContext, systemTypeValue.RepresentedType.Type, p => p.Name == stringValue.Contents, bindingFlags);
- break;
- default:
- throw new InternalErrorException ($"Error processing reflection call '{calledMethod.GetDisplayName ()}' inside {callingMethodDefinition.GetDisplayName ()}. Unexpected member kind.");
- }
- } else {
- RequireDynamicallyAccessedMembers (analysisContext, value, targetValue);
- }
- }
- } else {
- RequireDynamicallyAccessedMembers (analysisContext, value, targetValue);
- }
- }
- }
- break;
-
- //
// System.Linq.Expressions.Expression
//
// static Call (Type, String, Type[], Expression[])
@@ -460,7 +423,7 @@ namespace Mono.Linker.Dataflow
// We have one of the accessors for the property. The Expression.Property will in this case search
// for the matching PropertyInfo and store that. So to be perfectly correct we need to mark the
// respective PropertyInfo as "accessed via reflection".
- if (methodBaseValue.MethodRepresented.TryGetProperty (out PropertyDefinition? propertyDefinition)) {
+ if (methodBaseValue.MethodRepresented.Method.TryGetProperty (out PropertyDefinition? propertyDefinition)) {
MarkProperty (analysisContext, propertyDefinition);
continue;
}
@@ -673,105 +636,6 @@ namespace Mono.Linker.Dataflow
break;
//
- // GetMethod (string)
- // GetMethod (string, BindingFlags)
- // GetMethod (string, Type[])
- // GetMethod (string, Type[], ParameterModifier[])
- // GetMethod (string, BindingFlags, Type[])
- // GetMethod (string, BindingFlags, Binder, Type[], ParameterModifier[])
- // GetMethod (string, BindingFlags, Binder, CallingConventions, Type[], ParameterModifier[])
- // GetMethod (string, int, Type[])
- // GetMethod (string, int, Type[], ParameterModifier[]?)
- // GetMethod (string, int, BindingFlags, Binder?, Type[], ParameterModifier[]?)
- // GetMethod (string, int, BindingFlags, Binder?, CallingConventions, Type[], ParameterModifier[]?)
- //
- case IntrinsicId.Type_GetMethod: {
- BindingFlags? bindingFlags;
- if (calledMethod.Parameters.Count > 1 && calledMethodDefinition.Parameters[1].ParameterType.Name == "BindingFlags")
- bindingFlags = GetBindingFlagsFromValue (methodParams[2]);
- else if (calledMethod.Parameters.Count > 2 && calledMethodDefinition.Parameters[2].ParameterType.Name == "BindingFlags")
- bindingFlags = GetBindingFlagsFromValue (methodParams[3]);
- else
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
-
- var targetValue = GetMethodParameterValue (calledMethodDefinition, 0, GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags));
- foreach (var value in methodParams[0]) {
- if (value is SystemTypeValue systemTypeValue) {
- foreach (var stringParam in methodParams[1]) {
- if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
- ProcessGetMethodByName (analysisContext, systemTypeValue.RepresentedType.Type, stringValue.Contents, bindingFlags, ref methodReturnValue);
- } else {
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers (analysisContext, value, targetValue);
- }
- }
- } else {
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers (analysisContext, value, targetValue);
- }
- }
- }
- break;
-
- //
- // GetNestedType (string)
- // GetNestedType (string, BindingFlags)
- //
- case IntrinsicId.Type_GetNestedType: {
- BindingFlags? bindingFlags;
- if (calledMethodDefinition.Parameters.Count > 1 && calledMethodDefinition.Parameters[1].ParameterType.Name == "BindingFlags")
- bindingFlags = GetBindingFlagsFromValue (methodParams[2]);
- else
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
-
- var targetValue = GetMethodParameterValue (calledMethodDefinition, 0, GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags));
- bool everyParentTypeHasAll = true;
- foreach (var value in methodParams[0]) {
- if (value is SystemTypeValue systemTypeValue) {
- foreach (var stringParam in methodParams[1]) {
- if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
- TypeDefinition[]? matchingNestedTypes = MarkNestedTypesOnType (analysisContext, systemTypeValue.RepresentedType.Type, m => m.Name == stringValue.Contents, bindingFlags);
-
- if (matchingNestedTypes != null) {
- for (int i = 0; i < matchingNestedTypes.Length; i++)
- methodReturnValue = MultiValueLattice.Meet (methodReturnValue, new SystemTypeValue (matchingNestedTypes[i]));
- }
- } else {
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers (analysisContext, value, targetValue);
- }
- }
- } else {
- // Otherwise fall back to the bitfield requirements
- RequireDynamicallyAccessedMembers (analysisContext, value, targetValue);
- }
-
- if (value is ValueWithDynamicallyAccessedMembers valueWithDynamicallyAccessedMembers) {
- if (valueWithDynamicallyAccessedMembers.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.All)
- everyParentTypeHasAll = false;
- } else if (!(value is NullValue || value is SystemTypeValue)) {
- // Known Type values are always OK - either they're fully resolved above and thus the return value
- // is set to the known resolved type, or if they're not resolved, they won't exist at runtime
- // and will cause exceptions - and thus don't introduce new requirements on marking.
- // nulls are intentionally ignored as they will lead to exceptions at runtime
- // and thus don't introduce new requirements on marking.
- everyParentTypeHasAll = false;
- }
- }
-
- // If the parent type (all the possible values) has DynamicallyAccessedMemberTypes.All it means its nested types are also fully marked
- // (see MarkStep.MarkEntireType - it will recursively mark entire type on nested types). In that case we can annotate
- // the returned type (the nested type) with DynamicallyAccessedMemberTypes.All as well.
- // Note it's OK to blindly overwrite any potential annotation on the return value from the method definition
- // since DynamicallyAccessedMemberTypes.All is a superset of any other annotation.
- if (everyParentTypeHasAll && methodReturnValue.IsEmpty ())
- methodReturnValue = GetMethodReturnValue (calledMethodDefinition, DynamicallyAccessedMemberTypes.All);
- }
- break;
-
- //
// Type.BaseType
//
case IntrinsicId.Type_get_BaseType: {
@@ -821,165 +685,6 @@ namespace Mono.Linker.Dataflow
break;
//
- // GetField (string)
- // GetField (string, BindingFlags)
- // GetEvent (string)
- // GetEvent (string, BindingFlags)
- // GetProperty (string)
- // GetProperty (string, BindingFlags)
- // GetProperty (string, Type)
- // GetProperty (string, Type[])
- // GetProperty (string, Type, Type[])
- // GetProperty (string, Type, Type[], ParameterModifier[])
- // GetProperty (string, BindingFlags, Binder, Type, Type[], ParameterModifier[])
- //
- case var fieldPropertyOrEvent when (fieldPropertyOrEvent == IntrinsicId.Type_GetField || fieldPropertyOrEvent == IntrinsicId.Type_GetProperty || fieldPropertyOrEvent == IntrinsicId.Type_GetEvent)
- && calledMethod.DeclaringType.Namespace == "System"
- && calledMethod.DeclaringType.Name == "Type"
- && calledMethod.Parameters[0].ParameterType.FullName == "System.String"
- && calledMethod.HasThis: {
-
- BindingFlags? bindingFlags;
- if (calledMethodDefinition.Parameters.Count > 1 && calledMethodDefinition.Parameters[1].ParameterType.Name == "BindingFlags")
- bindingFlags = GetBindingFlagsFromValue (methodParams[2]);
- else
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
-
- DynamicallyAccessedMemberTypes memberTypes = fieldPropertyOrEvent switch {
- IntrinsicId.Type_GetEvent => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags),
- IntrinsicId.Type_GetField => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags),
- IntrinsicId.Type_GetProperty => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags),
- _ => throw new ArgumentException ($"Reflection call '{calledMethodDefinition.GetDisplayName ()}' inside '{callingMethodDefinition.GetDisplayName ()}' is of unexpected member type."),
- };
-
- var targetValue = GetMethodParameterValue (calledMethodDefinition, 0, memberTypes);
- foreach (var value in methodParams[0]) {
- if (value is SystemTypeValue systemTypeValue) {
- foreach (var stringParam in methodParams[1]) {
- if (stringParam is KnownStringValue stringValue && !BindingFlagsAreUnsupported (bindingFlags)) {
- switch (fieldPropertyOrEvent) {
- case IntrinsicId.Type_GetEvent:
- MarkEventsOnTypeHierarchy (analysisContext, systemTypeValue.RepresentedType.Type, filter: e => e.Name == stringValue.Contents, bindingFlags);
- break;
- case IntrinsicId.Type_GetField:
- MarkFieldsOnTypeHierarchy (analysisContext, systemTypeValue.RepresentedType.Type, filter: f => f.Name == stringValue.Contents, bindingFlags);
- break;
- case IntrinsicId.Type_GetProperty:
- MarkPropertiesOnTypeHierarchy (analysisContext, systemTypeValue.RepresentedType.Type, filter: p => p.Name == stringValue.Contents, bindingFlags);
- break;
- default:
- Debug.Fail ("Unreachable.");
- break;
- }
- } else {
- RequireDynamicallyAccessedMembers (analysisContext, value, targetValue);
- }
- }
- } else {
- RequireDynamicallyAccessedMembers (analysisContext, value, targetValue);
- }
- }
- }
- break;
-
- //
- // GetConstructors (BindingFlags)
- // GetMethods (BindingFlags)
- // GetFields (BindingFlags)
- // GetEvents (BindingFlags)
- // GetProperties (BindingFlags)
- // GetNestedTypes (BindingFlags)
- // GetMembers (BindingFlags)
- //
- case var callType when (callType == IntrinsicId.Type_GetConstructors || callType == IntrinsicId.Type_GetMethods || callType == IntrinsicId.Type_GetFields ||
- callType == IntrinsicId.Type_GetProperties || callType == IntrinsicId.Type_GetEvents || callType == IntrinsicId.Type_GetNestedTypes || callType == IntrinsicId.Type_GetMembers)
- && calledMethod.DeclaringType.Namespace == "System"
- && calledMethod.DeclaringType.Name == "Type"
- && calledMethod.Parameters[0].ParameterType.FullName == "System.Reflection.BindingFlags"
- && calledMethod.HasThis: {
-
- BindingFlags? bindingFlags;
- bindingFlags = GetBindingFlagsFromValue (methodParams[1]);
- DynamicallyAccessedMemberTypes memberTypes = DynamicallyAccessedMemberTypes.None;
- if (BindingFlagsAreUnsupported (bindingFlags)) {
- memberTypes = callType switch {
- IntrinsicId.Type_GetConstructors => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors,
- IntrinsicId.Type_GetMethods => DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods,
- IntrinsicId.Type_GetEvents => DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents,
- IntrinsicId.Type_GetFields => DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields,
- IntrinsicId.Type_GetProperties => DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties,
- IntrinsicId.Type_GetNestedTypes => DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
- IntrinsicId.Type_GetMembers => DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
- DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
- DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
- DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
- DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
- DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes,
- _ => throw new ArgumentException ($"Reflection call '{calledMethodDefinition.GetDisplayName ()}' inside '{callingMethodDefinition.GetDisplayName ()}' is of unexpected member type."),
- };
- } else {
- memberTypes = callType switch {
- IntrinsicId.Type_GetConstructors => GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags),
- IntrinsicId.Type_GetMethods => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags),
- IntrinsicId.Type_GetEvents => GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags),
- IntrinsicId.Type_GetFields => GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags),
- IntrinsicId.Type_GetProperties => GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags),
- IntrinsicId.Type_GetNestedTypes => GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags),
- IntrinsicId.Type_GetMembers => GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (bindingFlags),
- _ => throw new ArgumentException ($"Reflection call '{calledMethodDefinition.GetDisplayName ()}' inside '{callingMethodDefinition.GetDisplayName ()}' is of unexpected member type."),
- };
- }
-
- var targetValue = GetMethodParameterValue (calledMethodDefinition, 0, memberTypes);
- foreach (var value in methodParams[0]) {
- RequireDynamicallyAccessedMembers (analysisContext, value, targetValue);
- }
- }
- break;
-
-
- //
- // GetMember (String)
- // GetMember (String, BindingFlags)
- // GetMember (String, MemberTypes, BindingFlags)
- //
- case IntrinsicId.Type_GetMember: {
- var parameters = calledMethodDefinition.Parameters;
- BindingFlags? bindingFlags;
- if (parameters.Count == 1) {
- // Assume a default value for BindingFlags for methods that don't use BindingFlags as a parameter
- bindingFlags = BindingFlags.Public | BindingFlags.Instance;
- } else if (parameters.Count == 2 && calledMethodDefinition.Parameters[1].ParameterType.Name == "BindingFlags")
- bindingFlags = GetBindingFlagsFromValue (methodParams[2]);
- else if (parameters.Count == 3 && calledMethodDefinition.Parameters[2].ParameterType.Name == "BindingFlags") {
- bindingFlags = GetBindingFlagsFromValue (methodParams[3]);
- } else // Non recognized intrinsic
- throw new ArgumentException ($"Reflection call '{calledMethod.GetDisplayName ()}' inside '{callingMethodDefinition.GetDisplayName ()}' is an unexpected intrinsic.");
-
- DynamicallyAccessedMemberTypes requiredMemberTypes = DynamicallyAccessedMemberTypes.None;
- if (BindingFlagsAreUnsupported (bindingFlags)) {
- requiredMemberTypes = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
- DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
- DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
- DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
- DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
- DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
- } else {
- requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (bindingFlags);
- }
-
- var targetValue = GetMethodParameterValue (calledMethodDefinition, 0, requiredMemberTypes);
-
- // Go over all types we've seen
- foreach (var value in methodParams[0]) {
- // Mark based on bitfield requirements
- RequireDynamicallyAccessedMembers (analysisContext, value, targetValue);
- }
- }
- break;
-
- //
// System.Activator
//
// static CreateInstance (System.Type type)
@@ -1147,7 +852,7 @@ namespace Mono.Linker.Dataflow
foreach (var methodValue in methodParams[0]) {
if (methodValue is SystemReflectionMethodBaseValue methodBaseValue) {
- ValidateGenericMethodInstantiation (analysisContext, methodBaseValue.MethodRepresented, methodParams[1], calledMethodDefinition);
+ ValidateGenericMethodInstantiation (analysisContext, methodBaseValue.MethodRepresented.Method, methodParams[1], calledMethodDefinition);
} else if (methodValue == NullValue.Instance) {
// Nothing to do
} else {
@@ -1384,65 +1089,17 @@ namespace Mono.Linker.Dataflow
}
}
- void ProcessGetMethodByName (
- in AnalysisContext analysisContext,
- TypeDefinition typeDefinition,
- string methodName,
- BindingFlags? bindingFlags,
- ref MultiValue methodReturnValue)
- {
- bool foundAny = false;
- foreach (var method in typeDefinition.GetMethodsOnTypeHierarchy (_context, m => m.Name == methodName, bindingFlags)) {
- MarkMethod (analysisContext, method);
- methodReturnValue = MultiValueLattice.Meet (methodReturnValue, new SystemReflectionMethodBaseValue (method));
- foundAny = true;
- }
-
- // If there were no methods found the API will return null at runtime, so we should
- // track the null as a return value as well.
- // This also prevents warnings in such case, since if we don't set the return value it will be
- // "unknown" and consumers may warn.
- if (!foundAny)
- methodReturnValue = MultiValueLattice.Meet (methodReturnValue, NullValue.Instance);
- }
-
void RequireDynamicallyAccessedMembers (in AnalysisContext analysisContext, in MultiValue value, ValueWithDynamicallyAccessedMembers targetValue)
{
var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (_context, this, analysisContext);
requireDynamicallyAccessedMembersAction.Invoke (value, targetValue);
}
- static BindingFlags? GetBindingFlagsFromValue (in MultiValue parameter) => (BindingFlags?) parameter.AsConstInt ();
+ static BindingFlags? GetBindingFlagsFromValue (in MultiValue parameter) => HandleCallAction.GetBindingFlagsFromValue (parameter);
- static bool BindingFlagsAreUnsupported (BindingFlags? bindingFlags)
- {
- if (bindingFlags == null)
- return true;
-
- // Binding flags we understand
- const BindingFlags UnderstoodBindingFlags =
- BindingFlags.DeclaredOnly |
- BindingFlags.Instance |
- BindingFlags.Static |
- BindingFlags.Public |
- BindingFlags.NonPublic |
- BindingFlags.FlattenHierarchy |
- BindingFlags.ExactBinding;
-
- // Binding flags that don't affect binding outside InvokeMember (that we don't analyze).
- const BindingFlags IgnorableBindingFlags =
- BindingFlags.InvokeMethod |
- BindingFlags.CreateInstance |
- BindingFlags.GetField |
- BindingFlags.SetField |
- BindingFlags.GetProperty |
- BindingFlags.SetProperty;
-
- BindingFlags flags = bindingFlags.Value;
- return (flags & ~(UnderstoodBindingFlags | IgnorableBindingFlags)) != 0;
- }
+ static bool BindingFlagsAreUnsupported (BindingFlags? bindingFlags) => HandleCallAction.BindingFlagsAreUnsupported (bindingFlags);
- static bool HasBindingFlag (BindingFlags? bindingFlags, BindingFlags? search) => bindingFlags != null && (bindingFlags & search) == search;
+ static bool HasBindingFlag (BindingFlags? bindingFlags, BindingFlags? search) => HandleCallAction.HasBindingFlag (bindingFlags, search);
internal void MarkTypeForDynamicallyAccessedMembers (in AnalysisContext analysisContext, TypeDefinition typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, DependencyKind dependencyKind, bool declaredOnly = false)
{
@@ -1476,7 +1133,7 @@ namespace Mono.Linker.Dataflow
_markStep.MarkTypeVisibleToReflection (typeReference, type, new DependencyInfo (dependencyKind, analysisContext.Origin.Provider));
}
- void MarkMethod (in AnalysisContext analysisContext, MethodDefinition method, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
+ internal void MarkMethod (in AnalysisContext analysisContext, MethodDefinition method, DependencyKind dependencyKind = DependencyKind.AccessedViaReflection)
{
_markStep.MarkMethodVisibleToReflection (method, new DependencyInfo (dependencyKind, analysisContext.Origin.Provider));
}
@@ -1507,31 +1164,19 @@ namespace Mono.Linker.Dataflow
MarkMethod (analysisContext, ctor);
}
- void MarkFieldsOnTypeHierarchy (in AnalysisContext analysisContext, TypeDefinition type, Func<FieldDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
+ internal void MarkFieldsOnTypeHierarchy (in AnalysisContext analysisContext, TypeDefinition type, Func<FieldDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
{
foreach (var field in type.GetFieldsOnTypeHierarchy (_context, filter, bindingFlags))
MarkField (analysisContext, field);
}
- TypeDefinition[]? MarkNestedTypesOnType (in AnalysisContext analysisContext, TypeDefinition type, Func<TypeDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
- {
- var result = new ArrayBuilder<TypeDefinition> ();
-
- foreach (var nestedType in type.GetNestedTypesOnType (filter, bindingFlags)) {
- result.Add (nestedType);
- MarkType (analysisContext, nestedType);
- }
-
- return result.ToArray ();
- }
-
- void MarkPropertiesOnTypeHierarchy (in AnalysisContext analysisContext, TypeDefinition type, Func<PropertyDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
+ internal void MarkPropertiesOnTypeHierarchy (in AnalysisContext analysisContext, TypeDefinition type, Func<PropertyDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
{
foreach (var property in type.GetPropertiesOnTypeHierarchy (_context, filter, bindingFlags))
MarkProperty (analysisContext, property);
}
- void MarkEventsOnTypeHierarchy (in AnalysisContext analysisContext, TypeDefinition type, Func<EventDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
+ internal void MarkEventsOnTypeHierarchy (in AnalysisContext analysisContext, TypeDefinition type, Func<EventDefinition, bool> filter, BindingFlags? bindingFlags = BindingFlags.Default)
{
foreach (var @event in type.GetEventsOnTypeHierarchy (_context, filter, bindingFlags))
MarkEvent (analysisContext, @event);
@@ -1557,42 +1202,11 @@ namespace Mono.Linker.Dataflow
}
}
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicNestedTypes : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None);
-
static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicConstructors : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None);
+ HandleCallAction.GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags);
static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicMethods : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicFields : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicProperties : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None);
-
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (BindingFlags? bindingFlags) =>
- (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicEvents : DynamicallyAccessedMemberTypes.None) |
- (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None) |
- (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None);
- static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (BindingFlags? bindingFlags) =>
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (bindingFlags) |
- GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (bindingFlags);
+ HandleCallAction.GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (bindingFlags);
internal readonly struct AnalysisContext
{
diff --git a/src/linker/Linker.Dataflow/ValueNode.cs b/src/linker/Linker.Dataflow/ValueNode.cs
index 29bc92cc6..a079e777f 100644
--- a/src/linker/Linker.Dataflow/ValueNode.cs
+++ b/src/linker/Linker.Dataflow/ValueNode.cs
@@ -120,18 +120,6 @@ namespace ILLink.Shared.TrimAnalysis
}
/// <summary>
- /// This is a known System.Reflection.MethodBase value. MethodRepresented is the 'value' of the MethodBase.
- /// </summary>
- partial record SystemReflectionMethodBaseValue
- {
- public SystemReflectionMethodBaseValue (MethodDefinition methodRepresented) => MethodRepresented = methodRepresented;
-
- public readonly MethodDefinition MethodRepresented;
-
- public override string ToString () => this.ValueToString (MethodRepresented);
- }
-
- /// <summary>
/// A value that came from a method parameter - such as the result of a ldarg.
/// </summary>
partial record MethodParameterValue : IValueWithStaticType
diff --git a/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs
index d24ad8aa7..9e250aabc 100644
--- a/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs
+++ b/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs
@@ -196,14 +196,13 @@ class C
// (17,9): warning IL2070: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
// The parameter 'type' of method 'C.M(Type)' does not have matching annotations.
// The source value must declare at least the same requirements as those declared on the target location it is assigned to.
- return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations);
- /*,
- VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter)
- .WithSpan (17, 9, 17, 30)
- .WithArguments ("System.Type.GetMethod(String)",
- "type",
- "C.M(Type)",
- "'DynamicallyAccessedMemberTypes.PublicMethods'")*/
+ return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations,
+ VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter)
+ .WithSpan (17, 9, 17, 30)
+ .WithArguments ("System.Type.GetMethod(String)",
+ "type",
+ "C.M(Type)",
+ "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
#endregion
@@ -351,11 +350,10 @@ class C
// (12,9): warning IL2075: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
// The return value of method 'C.GetT()' does not have matching annotations.
// The source value must declare at least the same requirements as those declared on the target location it is assigned to.
- return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations
- /*,
+ return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations,
VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchMethodReturnTypeTargetsThisParameter)
.WithSpan (12, 9, 12, 34)
- .WithArguments ("System.Type.GetMethod(String)", "C.GetFoo()", "'DynamicallyAccessedMemberTypes.PublicMethods'")*/);
+ .WithArguments ("System.Type.GetMethod(String)", "C.GetFoo()", "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
#endregion
@@ -493,13 +491,12 @@ class C
// (14,9): warning IL2080: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in call to 'System.Type.GetMethod(String)'.
// The field 'C.f' does not have matching annotations.
// The source value must declare at least the same requirements as those declared on the target location it is assigned to.
- return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations);
- /*,
- VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter)
- .WithSpan (14, 9, 14, 27)
- .WithArguments ("System.Type.GetMethod(String)",
- "C.f",
- "'DynamicallyAccessedMemberTypes.PublicMethods'")*/
+ return VerifyDynamicallyAccessedMembersAnalyzer (TargetMethodWithAnnotations,
+ VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter)
+ .WithSpan (14, 9, 14, 27)
+ .WithArguments ("System.Type.GetMethod(String)",
+ "C.f",
+ "'DynamicallyAccessedMemberTypes.PublicMethods'"));
}
#endregion
diff --git a/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs b/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs
index 581d5a279..7dc1e1639 100644
--- a/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs
+++ b/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs
@@ -25,8 +25,7 @@ namespace ILLink.RoslynAnalyzer.Tests
[Fact]
public Task ConstructorsUsedViaReflection ()
{
- // https://github.com/dotnet/linker/issues/2578
- return RunTest (allowMissingWarnings: true);
+ return RunTest ();
}
[Fact]
@@ -37,10 +36,15 @@ namespace ILLink.RoslynAnalyzer.Tests
}
[Fact]
+ public Task EventUsedViaReflection ()
+ {
+ return RunTest ();
+ }
+
+ [Fact]
public Task EventsUsedViaReflection ()
{
- // https://github.com/dotnet/linker/issues/2578
- return RunTest (allowMissingWarnings: true);
+ return RunTest ();
}
[Fact]
@@ -63,38 +67,63 @@ namespace ILLink.RoslynAnalyzer.Tests
}
[Fact]
+ public Task FieldUsedViaReflection ()
+ {
+ return RunTest ();
+ }
+
+ [Fact]
public Task FieldsUsedViaReflection ()
{
- // https://github.com/dotnet/linker/issues/2578
- return RunTest (allowMissingWarnings: true);
+ return RunTest ();
}
[Fact]
public Task MembersUsedViaReflection ()
{
- // https://github.com/dotnet/linker/issues/2578
- return RunTest (allowMissingWarnings: true);
+ return RunTest ();
}
[Fact]
public Task MemberUsedViaReflection ()
{
- // https://github.com/dotnet/linker/issues/2578
- return RunTest (allowMissingWarnings: true);
+ return RunTest ();
+ }
+
+ [Fact]
+ public Task MethodUsedViaReflection ()
+ {
+ return RunTest ();
+ }
+
+ [Fact]
+ public Task MethodUsedViaReflectionAndLocal ()
+ {
+ return RunTest ();
+ }
+
+ [Fact]
+ public Task MethodUsedViaReflectionWithDefaultBindingFlags ()
+ {
+ return RunTest ();
}
[Fact]
public Task MethodsUsedViaReflection ()
{
- // https://github.com/dotnet/linker/issues/2578
- return RunTest (allowMissingWarnings: true);
+ return RunTest ();
+ }
+
+ [Fact]
+ public Task NestedTypeUsedViaReflection ()
+ {
+ return RunTest ();
}
[Fact]
public Task NestedTypesUsedViaReflection ()
{
- // https://github.com/dotnet/linker/issues/2578
- return RunTest (allowMissingWarnings: true);
+ return RunTest ();
}
[Fact]
@@ -105,10 +134,21 @@ namespace ILLink.RoslynAnalyzer.Tests
}
[Fact]
+ public Task PropertyUsedViaReflection ()
+ {
+ return RunTest ();
+ }
+
+ [Fact]
public Task PropertiesUsedViaReflection ()
{
- // https://github.com/dotnet/linker/issues/2578
- return RunTest (allowMissingWarnings: true);
+ return RunTest ();
+ }
+
+ [Fact]
+ public Task RuntimeReflectionExtensionsCalls ()
+ {
+ return RunTest ();
}
[Fact]
diff --git a/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs b/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs
index 486718f26..2ef192d11 100644
--- a/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs
+++ b/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs
@@ -38,12 +38,6 @@ namespace ILLink.RoslynAnalyzer.Tests
}
[Fact]
- public Task EventUsedViaReflection ()
- {
- return RunTest (allowMissingWarnings: true);
- }
-
- [Fact]
public Task ExpressionCallStringAndLocals ()
{
return RunTest (allowMissingWarnings: true);
@@ -62,36 +56,6 @@ namespace ILLink.RoslynAnalyzer.Tests
}
[Fact]
- public Task FieldUsedViaReflection ()
- {
- return RunTest (allowMissingWarnings: true);
- }
-
- [Fact]
- public Task MethodUsedViaReflection ()
- {
- return RunTest (allowMissingWarnings: true);
- }
-
- [Fact]
- public Task MethodUsedViaReflectionAndLocal ()
- {
- return RunTest (allowMissingWarnings: true);
- }
-
- [Fact]
- public Task MethodUsedViaReflectionWithDefaultBindingFlags ()
- {
- return RunTest (allowMissingWarnings: true);
- }
-
- [Fact]
- public Task NestedTypeUsedViaReflection ()
- {
- return RunTest (allowMissingWarnings: true);
- }
-
- [Fact]
public Task ObjectGetTypeLibraryMode ()
{
return RunTest (allowMissingWarnings: true);
@@ -104,24 +68,12 @@ namespace ILLink.RoslynAnalyzer.Tests
}
[Fact]
- public Task PropertyUsedViaReflection ()
- {
- return RunTest (allowMissingWarnings: true);
- }
-
- [Fact]
public Task RunClassConstructorUsedViaReflection ()
{
return RunTest (allowMissingWarnings: true);
}
[Fact]
- public Task RuntimeReflectionExtensionsCalls ()
- {
- return RunTest (allowMissingWarnings: true);
- }
-
- [Fact]
public Task TypeBaseTypeUseViaReflection ()
{
return RunTest (allowMissingWarnings: true);
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs b/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs
index 07a450776..ef5339d7f 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs
@@ -39,8 +39,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
public static Type _annotatedField;
- // Intrinsic is disabled https://github.com/dotnet/linker/issues/2559
- [ExpectedWarning ("IL2110", nameof (_annotatedField), ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2110", nameof (_annotatedField))]
static void Reflection ()
{
typeof (AnnotatedField).GetField ("_annotatedField").SetValue (null, typeof (TestType));
@@ -52,8 +51,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
typeof (AnnotatedField).GetField ("_annotatedField").SetValue (null, typeof (TestType));
}
- // Intrinsic is disabled https://github.com/dotnet/linker/issues/2559
- [ExpectedWarning ("IL2110", nameof (_annotatedField), ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2110", nameof (_annotatedField))]
static void ReflectionReadOnly ()
{
typeof (AnnotatedField).GetField ("_annotatedField").GetValue (null);
@@ -160,8 +158,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
{ }
}
- // Intrinsic is disabled https://github.com/dotnet/linker/issues/2559
- [ExpectedWarning ("IL2111", nameof (MethodWithSingleAnnotatedParameter), ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2111", nameof (MethodWithSingleAnnotatedParameter))]
static void Reflection ()
{
typeof (AnnotatedMethodParameters).GetMethod (nameof (MethodWithSingleAnnotatedParameter)).Invoke (null, null);
@@ -294,8 +291,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
typeof (AnnotatedMethodReturnValue).GetMethod (nameof (InstanceMethodWithAnnotatedReturnValue)).Invoke (null, null);
}
- // Intrinsic is disabled https://github.com/dotnet/linker/issues/2559
- [ExpectedWarning ("IL2111", nameof (VirtualMethodWithAnnotatedReturnValue), ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2111", nameof (VirtualMethodWithAnnotatedReturnValue))]
static void ReflectionOnVirtual ()
{
typeof (AnnotatedMethodReturnValue).GetMethod (nameof (VirtualMethodWithAnnotatedReturnValue)).Invoke (null, null);
@@ -423,8 +419,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
public Type PropertyWithAnnotation { get; set; }
}
- // Intrinsic is disabled https://github.com/dotnet/linker/issues/2559
- [ExpectedWarning ("IL2111", nameof (Property1WithAnnotation) + ".set", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2111", nameof (Property1WithAnnotation) + ".set")]
static void ReflectionOnPropertyItself ()
{
typeof (AnnotatedProperty).GetProperty (nameof (Property1WithAnnotation));
@@ -441,8 +436,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
typeof (AnnotatedProperty).GetProperty (nameof (Property2WithAnnotationGetterOnly));
}
- // Intrinsic is disabled https://github.com/dotnet/linker/issues/2559
- [ExpectedWarning ("IL2111", nameof (VirtualProperty3WithAnnotationGetterOnly), ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2111", nameof (VirtualProperty3WithAnnotationGetterOnly))]
static void ReflectionOnPropertyWithGetterOnlyOnVirtual ()
{
typeof (AnnotatedProperty).GetProperty (nameof (VirtualProperty3WithAnnotationGetterOnly));
@@ -453,15 +447,13 @@ namespace Mono.Linker.Tests.Cases.DataFlow
typeof (AnnotatedProperty).GetMethod ("get_" + nameof (Property1WithAnnotation));
}
- // Intrinsic is disabled https://github.com/dotnet/linker/issues/2559
- [ExpectedWarning ("IL2111", nameof (Property1WithAnnotation) + ".set", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2111", nameof (Property1WithAnnotation) + ".set")]
static void ReflectionOnSetter ()
{
typeof (AnnotatedProperty).GetMethod ("set_" + nameof (Property1WithAnnotation));
}
- // Intrinsic is disabled https://github.com/dotnet/linker/issues/2559
- [ExpectedWarning ("IL2111", nameof (VirtualProperty3WithAnnotationGetterOnly) + ".get", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2111", nameof (VirtualProperty3WithAnnotationGetterOnly) + ".get")]
static void ReflectionOnVirtualGetter ()
{
typeof (AnnotatedProperty).GetMethod ("get_" + nameof (VirtualProperty3WithAnnotationGetterOnly));
@@ -662,8 +654,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
var _ = new Action<Type> (GenericWithAnnotatedMethod<TestType>.AnnotatedMethod);
}
- // Intrinsic is disabled https://github.com/dotnet/linker/issues/2559
- [ExpectedWarning ("IL2111", nameof (GenericMethodWithAnnotation), ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2111", nameof (GenericMethodWithAnnotation))]
public static void GenericMethodWithAnnotationReflection ()
{
typeof (AnnotationOnGenerics).GetMethod (nameof (GenericMethodWithAnnotation));
diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/DynamicDependencyDataflow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/DynamicDependencyDataflow.cs
index 8237bc4db..029e5848b 100644
--- a/test/Mono.Linker.Tests.Cases/DataFlow/DynamicDependencyDataflow.cs
+++ b/test/Mono.Linker.Tests.Cases/DataFlow/DynamicDependencyDataflow.cs
@@ -18,18 +18,16 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
static Type TypeWithPublicMethods;
- // Intrinsic is disabled https://github.com/dotnet/linker/issues/2559
[Kept]
- [ExpectedWarning ("IL2080", nameof (Type.GetField), ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2080", nameof (Type.GetField))]
[DynamicDependency ("DynamicDependencyTo")]
static void DynamicDependencyFrom ()
{
_ = TypeWithPublicMethods.GetField ("f");
}
- // Intrinsic is disabled https://github.com/dotnet/linker/issues/2559
[Kept]
- [ExpectedWarning ("IL2080", nameof (Type.GetProperty), ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2080", nameof (Type.GetProperty))]
static void DynamicDependencyTo ()
{
_ = TypeWithPublicMethods.GetProperty ("p");
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs
index fcede014b..2ffbde48e 100644
--- a/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs
+++ b/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs
@@ -24,6 +24,10 @@ namespace Mono.Linker.Tests.Cases.Reflection
TestIgnoreCaseBindingFlags ();
TestIgnorableBindingFlags ();
TestUnsupportedBindingFlags ();
+
+ HandlingOfComplexExpressionForBindingFlags.Test ();
+ HandlingOfBindingFlagsAsNumbers.Test ();
+ HandlingOfBindingFlagsFromConstants.Test ();
}
[Kept]
@@ -307,5 +311,82 @@ namespace Mono.Linker.Tests.Cases.Reflection
return true;
}
}
+
+ [Kept]
+ class HandlingOfComplexExpressionForBindingFlags
+ {
+ [Kept]
+ class TestClassWithRUCMethods
+ {
+ [Kept]
+ public void Method () { }
+
+ [Kept]
+ [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))]
+ [RequiresUnreferencedCode (nameof (HandlingOfComplexExpressionForBindingFlags) + "--" + nameof (TestClassWithRUCMethods))]
+ private void PrivateMethodWithRUC () { }
+ }
+
+ [Kept]
+ // https://github.com/dotnet/linker/issues/2638
+ [ExpectedWarning ("IL2026", ProducedBy = ProducedBy.Trimmer)]
+ public static void Test ()
+ {
+ BindingFlags left = BindingFlags.Instance | BindingFlags.Static;
+ BindingFlags right = BindingFlags.Public;
+ int result = (int) left | (int) right;
+ typeof (TestClassWithRUCMethods).GetMethods ((BindingFlags) result);
+ }
+ }
+
+ [Kept]
+ class HandlingOfBindingFlagsAsNumbers
+ {
+ [Kept]
+ class TestClassWithRUCMethods
+ {
+ [Kept]
+ public static void Method () { }
+
+ [RequiresUnreferencedCode (nameof (HandlingOfBindingFlagsAsNumbers) + "--" + nameof (TestClassWithRUCMethods))]
+ private static void PrivateMethodWithRUC () { }
+ }
+
+ [Kept]
+ // https://github.com/dotnet/linker/issues/2638
+ [ExpectedWarning ("IL2026", ProducedBy = ProducedBy.Analyzer)]
+ public static void Test ()
+ {
+ typeof (TestClassWithRUCMethods).GetMethods ((BindingFlags) 24);
+
+ // Analyzer currently can't figure this out
+ int bindingFlagsNumber = 24;
+ typeof (TestClassWithRUCMethods).GetMethods ((BindingFlags) bindingFlagsNumber);
+ }
+ }
+
+ [Kept]
+ class HandlingOfBindingFlagsFromConstants
+ {
+ [Kept]
+ class TestClassWithRUCMethods
+ {
+ [Kept]
+ public static void Method () { }
+
+ [RequiresUnreferencedCode (nameof (HandlingOfBindingFlagsAsNumbers) + "--" + nameof (TestClassWithRUCMethods))]
+ private static void PrivateMethodWithRUC () { }
+ }
+
+ const BindingFlags PublicStaticFlags = BindingFlags.Public | BindingFlags.Static;
+ const BindingFlags PublicOnlyFlags = BindingFlags.Public;
+
+ [Kept]
+ public static void Test ()
+ {
+ typeof (TestClassWithRUCMethods).GetMethods (PublicStaticFlags);
+ typeof (TestClassWithRUCMethods).GetMethods (PublicOnlyFlags | BindingFlags.Static);
+ }
+ }
}
}
diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAccessedThrough.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAccessedThrough.cs
index 14b70f2a8..758d7a744 100644
--- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAccessedThrough.cs
+++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAccessedThrough.cs
@@ -39,7 +39,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
{
}
- [ExpectedWarning ("IL2026", "--RequiresOnlyThroughReflection--", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2026", "--RequiresOnlyThroughReflection--")]
static void TestRequiresOnlyThroughReflection ()
{
typeof (RequiresAccessedThrough)
@@ -54,7 +54,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
{
}
- [ExpectedWarning ("IL2026", "--GenericType.RequiresOnlyThroughReflection--", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2026", "--GenericType.RequiresOnlyThroughReflection--")]
public static void Test ()
{
typeof (AccessedThroughReflectionOnGenericType<T>)
diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs
index 2b7bfae37..240fd2d67 100644
--- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs
+++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs
@@ -464,10 +464,10 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
typeof (DerivedWithoutRequiresOnType).RequiresPublicMethods ();
}
- [ExpectedWarning ("IL2026", "BaseWithoutRequiresOnType.Method()", ProducedBy = ProducedBy.Trimmer)]
- [ExpectedWarning ("IL2026", "InterfaceWithoutRequires.Method(Int32)", ProducedBy = ProducedBy.Trimmer)]
- [ExpectedWarning ("IL2026", "InterfaceWithoutRequires.Method()", ProducedBy = ProducedBy.Trimmer)]
- [ExpectedWarning ("IL2026", "ImplementationWithRequiresOnType.Method()", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2026", "BaseWithoutRequiresOnType.Method()")]
+ [ExpectedWarning ("IL2026", "InterfaceWithoutRequires.Method(Int32)")]
+ [ExpectedWarning ("IL2026", "InterfaceWithoutRequires.Method()")]
+ [ExpectedWarning ("IL2026", "ImplementationWithRequiresOnType.Method()")]
static void TestDirectReflectionAccess ()
{
// Requires on the method itself
@@ -600,16 +600,16 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
typeof (DerivedWithRequires).RequiresPublicFields ();
}
- [ExpectedWarning ("IL2026", "WithRequires.StaticField", ProducedBy = ProducedBy.Trimmer)]
- [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticField", ProducedBy = ProducedBy.Trimmer)]
- [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticField", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2026", "WithRequires.StaticField")]
+ [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticField")]
+ [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticField")]
static void TestDirectReflectionAccess ()
{
typeof (WithRequires).GetField (nameof (WithRequires.StaticField));
typeof (WithRequires).GetField (nameof (WithRequires.InstanceField)); // Doesn't warn
typeof (WithRequires).GetField ("PrivateStaticField", BindingFlags.NonPublic);
typeof (WithRequiresOnlyInstanceFields).GetField (nameof (WithRequiresOnlyInstanceFields.InstanceField)); // Doesn't warn
- typeof (DerivedWithoutRequires).GetField (nameof (DerivedWithRequires.DerivedStaticField)); // Doesn't warn
+ typeof (DerivedWithoutRequires).GetField (nameof (DerivedWithoutRequires.DerivedStaticField)); // Doesn't warn
typeof (DerivedWithRequires).GetField (nameof (DerivedWithRequires.DerivedStaticField));
}
@@ -676,7 +676,9 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
public static event EventHandler StaticEvent;
}
- [ExpectedWarning ("IL2026", "StaticEvent.add", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2026", "StaticEvent.add")]
+ // https://github.com/mono/linker/issues/2218
+ [ExpectedWarning ("IL2026", "StaticEvent.remove", ProducedBy = ProducedBy.Analyzer)]
static void TestDirectReflectionAccess ()
{
typeof (WithRequires).GetEvent (nameof (WithRequires.StaticEvent));
@@ -735,12 +737,12 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
typeof (DerivedWithRequires).RequiresPublicProperties ();
}
- [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get", ProducedBy = ProducedBy.Trimmer)]
- [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set", ProducedBy = ProducedBy.Trimmer)]
- [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticProperty.get", ProducedBy = ProducedBy.Trimmer)]
- [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticProperty.set", ProducedBy = ProducedBy.Trimmer)]
- [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.get", ProducedBy = ProducedBy.Trimmer)]
- [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.set", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.get")]
+ [ExpectedWarning ("IL2026", "WithRequires.StaticProperty.set")]
+ [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticProperty.get")]
+ [ExpectedWarning ("IL2026", "WithRequires.PrivateStaticProperty.set")]
+ [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.get")]
+ [ExpectedWarning ("IL2026", "DerivedWithRequires.DerivedStaticProperty.set")]
static void TestDirectReflectionAccess ()
{
typeof (WithRequires).GetProperty (nameof (WithRequires.StaticProperty));
diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresWithCopyAssembly.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresWithCopyAssembly.cs
index facd4cf73..b2e1e0f39 100644
--- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresWithCopyAssembly.cs
+++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresWithCopyAssembly.cs
@@ -50,7 +50,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
tmp.Method ();
}
- [ExpectedWarning ("IL2026", "--MethodCalledThroughReflection--", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2026", "--MethodCalledThroughReflection--")]
static void TestRequiresThroughReflectionInMethodFromCopiedAssembly ()
{
typeof (RequiresInCopyAssembly)