NativeAOT fixes around data flow analysis (#80694)
authorVitek Karas <10670590+vitek-karas@users.noreply.github.com>
Thu, 19 Jan 2023 15:20:23 +0000 (07:20 -0800)
committerGitHub <noreply@github.com>
Thu, 19 Jan 2023 15:20:23 +0000 (07:20 -0800)
Removes the `Origin` class as it doesn't seem to serve any purpose anymore. The code used it to basically just only call `GetDisplayName` on members and pass that as the `reason` to dependency analysis. Replaced with passing just string directly as the `reason`.

Fixes bugs in warning subsystem when the warning is generated from an origin which is a module or assembly. This would previously crash the compiler. There are basically no tests for this right now - some of the tests in linker which hit this can't be easily ported yet due to NativeAOT not producing "reflection access to DAM" warnings. I have these mostly working locally but enabling the warnings fails some tests outside of the linker ones, so it needs more work.

Fixes analysis bugs when methods or fields are accessed via `ldtoken` or `ldftn` instructions. In such cases we still need to process them for RUC and DAM based warnings and so on. There are only a few tests for this in this change - more will come when we port the `AnnotatedMembersAccessedViaReflection` from linker, but those all require to enable the "reflection access to DAM" warnings as mentioned above.
* This required addition of a new TrimAnalysisPattern since the processing happens in reflection scanning and all warnings/marking hapening from there must go through the patterns.

Changes `DynamicDependencyAttribute` processing to happen in a separate dependency node. Previously if there were warnings generated due to the `DynamicDependencyAttribute` the compiler may report them multiple times (if it hit the same member twice during the rest of the analysis). To avoid this, the processing is postponed by adding a new dependency node - which then acts as the unification mechanism and thus warnings are produced just once.

33 files changed:
src/coreclr/tools/Common/Compiler/Dataflow/EcmaExtensions.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/AttributeDataFlow.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/DiagnosticUtilities.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericArgumentDataFlow.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/GenericParameterValue.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodBodyScanner.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/MethodParameterValue.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/Origin.cs [deleted file]
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/RequireDynamicallyAccessedMembersAction.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisAssignmentPattern.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisPatternStore.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisReflectionAccessPattern.cs [new file with mode: 0644]
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DynamicDependencyAttributeAlgorithm.cs [deleted file]
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DynamicDependencyAttributesOnEntityNode.cs [new file with mode: 0644]
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FieldMetadataNode.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/MethodMetadataNode.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logger.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/MessageContainer.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs
src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs
src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/IReflectDataflow.cs
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresAccessedThrough.cs
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaDataflow.cs

index 96885c9a1960ab4fb9816e1c9668545ff7417ad3..dca04632ae6bfce047a655409ceeffb42f20e681 100644 (file)
@@ -111,6 +111,7 @@ namespace ILCompiler.Dataflow
                 MetadataType type => type.ContainingType,
                 PropertyPseudoDesc property => property.OwningType,
                 EventPseudoDesc @event => @event.OwningType,
+                ModuleDesc => null,
                 _ => throw new NotImplementedException("Unexpected type system entity")
             };
         }
index d5d537be1eda92fd33d47d2b745a76efba9b8de9..25ad48c6a98cd6d858f097fa85766d44e2ed0cb4 100644 (file)
@@ -89,7 +89,7 @@ namespace ILCompiler.Dataflow
                 {
                     MultiValue value = GetValueForCustomAttributeArgument(arguments[parameter.MetadataIndex]);
                     var diagnosticContext = new DiagnosticContext(_origin, diagnosticsEnabled: true, _logger);
-                    RequireDynamicallyAccessedMembers(diagnosticContext, value, parameterValue, parameterValue.ParameterOrigin, ref result);
+                    RequireDynamicallyAccessedMembers(diagnosticContext, value, parameterValue, method.GetDisplayName(), ref result);
                 }
             }
         }
@@ -102,7 +102,7 @@ namespace ILCompiler.Dataflow
             {
                 MultiValue valueNode = GetValueForCustomAttributeArgument(value);
                 var diagnosticContext = new DiagnosticContext(_origin, diagnosticsEnabled: true, _logger);
-                RequireDynamicallyAccessedMembers(diagnosticContext, valueNode, fieldValue, new FieldOrigin(field), ref result);
+                RequireDynamicallyAccessedMembers(diagnosticContext, valueNode, fieldValue, field.GetDisplayName(), ref result);
             }
         }
 
@@ -120,11 +120,11 @@ namespace ILCompiler.Dataflow
             in DiagnosticContext diagnosticContext,
             in MultiValue value,
             ValueWithDynamicallyAccessedMembers targetValue,
-            Origin memberWithRequirements,
+            string reason,
             ref DependencyList? result)
         {
-            var reflectionMarker = new ReflectionMarker(_logger, _factory, _annotations, typeHierarchyDataFlow: false, enabled: true);
-            var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(reflectionMarker, diagnosticContext, memberWithRequirements);
+            var reflectionMarker = new ReflectionMarker(_logger, _factory, _annotations, typeHierarchyDataFlowOrigin: null, enabled: true);
+            var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(reflectionMarker, diagnosticContext, reason);
             requireDynamicallyAccessedMembersAction.Invoke(value, targetValue);
 
             if (result == null)
index edae12569e18e31f9ea88133d3153518c995c8cb..213ace382d6c28ea2b1133eed19308917bb31eae 100644 (file)
@@ -24,9 +24,9 @@ namespace ILCompiler.Dataflow
             return method.GetDisplayName();
         }
 
-        internal static string GetGenericParameterDeclaringMemberDisplayName(GenericParameterOrigin origin)
+        internal static string GetGenericParameterDeclaringMemberDisplayName(GenericParameterDesc genericParameter)
         {
-            var param = (EcmaGenericParameter)origin.GenericParameter;
+            var param = (EcmaGenericParameter)genericParameter;
             var parent = param.Module.GetObject(param.MetadataReader.GetGenericParameter(param.Handle).Parent);
             if (parent is MethodDesc m)
                 return m.GetDisplayName();
index 200bd57ed500ae7fed99fece8d30b587c0e88a1d..0cf5a42421be8930fcbf0fc449a0eb8242168794 100644 (file)
@@ -792,8 +792,8 @@ namespace ILLink.Shared.TrimAnalysis
                     break;
                 case GenericParameterDesc genericParameterOverride:
                     _logger.LogWarning(origin, DiagnosticId.DynamicallyAccessedMembersMismatchOnGenericParameterBetweenOverrides,
-                        genericParameterOverride.Name, DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(new GenericParameterOrigin(genericParameterOverride)),
-                        ((GenericParameterDesc)baseProvider).Name, DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(new GenericParameterOrigin((GenericParameterDesc)baseProvider)));
+                        genericParameterOverride.Name, DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(genericParameterOverride),
+                        ((GenericParameterDesc)baseProvider).Name, DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName((GenericParameterDesc)baseProvider));
                     break;
                 case TypeDesc:
                     _logger.LogWarning(origin, DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodReturnValueBetweenOverrides,
index 071f2bed0fbaf2c2b4aaaeceb4e81b676d85b5fb..555091d04a769324a8c959a643b11f6d0912ab7b 100644 (file)
@@ -44,17 +44,17 @@ namespace ILCompiler.Dataflow
                 _origin,
                 _logger.ShouldSuppressAnalysisWarningsForRequires(_origin.MemberDefinition, DiagnosticUtilities.RequiresUnreferencedCodeAttribute),
                 _logger);
-            return RequireDynamicallyAccessedMembers(diagnosticContext, genericArgumentValue, genericParameterValue, new GenericParameterOrigin(genericParameter));
+            return RequireDynamicallyAccessedMembers(diagnosticContext, genericArgumentValue, genericParameterValue, genericParameter.GetDisplayName());
         }
 
         private DependencyList RequireDynamicallyAccessedMembers(
             in DiagnosticContext diagnosticContext,
             in MultiValue value,
             ValueWithDynamicallyAccessedMembers targetValue,
-            Origin memberWithRequirements)
+            string reason)
         {
-            var reflectionMarker = new ReflectionMarker(_logger, _factory, _annotations, typeHierarchyDataFlow: false, enabled: true);
-            var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(reflectionMarker, diagnosticContext, memberWithRequirements);
+            var reflectionMarker = new ReflectionMarker(_logger, _factory, _annotations, typeHierarchyDataFlowOrigin: null, enabled: true);
+            var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(reflectionMarker, diagnosticContext, reason);
             requireDynamicallyAccessedMembersAction.Invoke(value, targetValue);
             return reflectionMarker.Dependencies;
         }
index 3e7ef0550d098a4f270358ccf9035cc11f83d4ba..d3ed103214b872f267f9c6445983f342d9a62ea0 100644 (file)
@@ -26,7 +26,7 @@ namespace ILLink.Shared.TrimAnalysis
         public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
 
         public override IEnumerable<string> GetDiagnosticArgumentsForAnnotationMismatch()
-            => new string[] { GenericParameter.GenericParameter.Name, DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(new GenericParameterOrigin(GenericParameter.GenericParameter)) };
+            => new string[] { GenericParameter.GenericParameter.Name, DiagnosticUtilities.GetGenericParameterDeclaringMemberDisplayName(GenericParameter.GenericParameter) };
 
         public override SingleValue DeepCopy() => this; // This value is immutable
 
index 45e59baaa1e74ec8815d33883d685bf16e0d539e..f09a76221ef37ba8934dac3eca655a2bec979e92 100644 (file)
@@ -20,21 +20,21 @@ namespace ILLink.Shared.TrimAnalysis
 
         private readonly ReflectionMarker _reflectionMarker;
         private readonly MethodDesc _callingMethod;
-        private readonly Origin _memberWithRequirements;
+        private readonly string _reason;
 
         public HandleCallAction(
             FlowAnnotations annotations,
             ReflectionMarker reflectionMarker,
             in DiagnosticContext diagnosticContext,
             MethodDesc callingMethod,
-            Origin memberWithRequirements)
+            string reason)
         {
             _reflectionMarker = reflectionMarker;
             _diagnosticContext = diagnosticContext;
             _callingMethod = callingMethod;
             _annotations = annotations;
-            _memberWithRequirements = memberWithRequirements;
-            _requireDynamicallyAccessedMembersAction = new(reflectionMarker, diagnosticContext, memberWithRequirements);
+            _reason = reason;
+            _requireDynamicallyAccessedMembersAction = new(reflectionMarker, diagnosticContext, reason);
         }
 
         private partial bool MethodIsTypeConstructor(MethodProxy method)
@@ -88,28 +88,28 @@ namespace ILLink.Shared.TrimAnalysis
 #pragma warning restore IDE0060
 
         private partial void MarkStaticConstructor(TypeProxy type)
-            => _reflectionMarker.MarkStaticConstructor(_diagnosticContext.Origin, type.Type);
+            => _reflectionMarker.MarkStaticConstructor(_diagnosticContext.Origin, type.Type, _reason);
 
         private partial void MarkEventsOnTypeHierarchy(TypeProxy type, string name, BindingFlags? bindingFlags)
-            => _reflectionMarker.MarkEventsOnTypeHierarchy(_diagnosticContext.Origin, type.Type, e => e.Name == name, _memberWithRequirements, bindingFlags);
+            => _reflectionMarker.MarkEventsOnTypeHierarchy(_diagnosticContext.Origin, type.Type, e => e.Name == name, _reason, bindingFlags);
 
         private partial void MarkFieldsOnTypeHierarchy(TypeProxy type, string name, BindingFlags? bindingFlags)
-            => _reflectionMarker.MarkFieldsOnTypeHierarchy(_diagnosticContext.Origin, type.Type, f => f.Name == name, _memberWithRequirements, bindingFlags);
+            => _reflectionMarker.MarkFieldsOnTypeHierarchy(_diagnosticContext.Origin, type.Type, f => f.Name == name, _reason, bindingFlags);
 
         private partial void MarkPropertiesOnTypeHierarchy(TypeProxy type, string name, BindingFlags? bindingFlags)
-            => _reflectionMarker.MarkPropertiesOnTypeHierarchy(_diagnosticContext.Origin, type.Type, p => p.Name == name, _memberWithRequirements, bindingFlags);
+            => _reflectionMarker.MarkPropertiesOnTypeHierarchy(_diagnosticContext.Origin, type.Type, p => p.Name == name, _reason, bindingFlags);
 
         private partial void MarkPublicParameterlessConstructorOnType(TypeProxy type)
-            => _reflectionMarker.MarkConstructorsOnType(_diagnosticContext.Origin, type.Type, m => m.IsPublic() && !m.HasMetadataParameters(), _memberWithRequirements);
+            => _reflectionMarker.MarkConstructorsOnType(_diagnosticContext.Origin, type.Type, m => m.IsPublic() && !m.HasMetadataParameters(), _reason);
 
         private partial void MarkConstructorsOnType(TypeProxy type, BindingFlags? bindingFlags, int? parameterCount)
-            => _reflectionMarker.MarkConstructorsOnType(_diagnosticContext.Origin, type.Type, parameterCount == null ? null : m => m.GetMetadataParametersCount() == parameterCount, _memberWithRequirements, bindingFlags);
+            => _reflectionMarker.MarkConstructorsOnType(_diagnosticContext.Origin, type.Type, parameterCount == null ? null : m => m.GetMetadataParametersCount() == parameterCount, _reason, bindingFlags);
 
         private partial void MarkMethod(MethodProxy method)
-            => _reflectionMarker.MarkMethod(_diagnosticContext.Origin, method.Method, _memberWithRequirements);
+            => _reflectionMarker.MarkMethod(_diagnosticContext.Origin, method.Method, _reason);
 
         private partial void MarkType(TypeProxy type)
-            => _reflectionMarker.MarkType(_diagnosticContext.Origin, type.Type, _memberWithRequirements);
+            => _reflectionMarker.MarkType(_diagnosticContext.Origin, type.Type, _reason);
 
         private partial bool MarkAssociatedProperty(MethodProxy method)
         {
@@ -119,7 +119,7 @@ namespace ILLink.Shared.TrimAnalysis
                 return false;
             }
 
-            _reflectionMarker.MarkProperty(_diagnosticContext.Origin, propertyDefinition, _memberWithRequirements);
+            _reflectionMarker.MarkProperty(_diagnosticContext.Origin, propertyDefinition, _reason);
             return true;
         }
 
index 8d6614a9806cb94fbba51cfd3f9c854e1ece7d72..70640274fc3b448ae63673489612504a64fa34d5 100644 (file)
@@ -477,6 +477,7 @@ namespace ILCompiler.Dataflow
                         {
                             if (methodBody.GetObject(reader.ReadILToken()) is MethodDesc methodOperand)
                             {
+                                HandleMethodReflectionAccess(methodBody, offset, methodOperand);
                                 TrackNestedFunctionReference(methodOperand, ref interproceduralState);
                             }
 
@@ -530,7 +531,19 @@ namespace ILCompiler.Dataflow
 
                     case ILOpcode.ldtoken:
                         object obj = methodBody.GetObject(reader.ReadILToken());
-                        ScanLdtoken(obj, currentStack);
+                        ScanLdtoken(methodBody, offset, obj, currentStack);
+                        break;
+
+                    case ILOpcode.ldvirtftn:
+                        {
+                            if (methodBody.GetObject(reader.ReadILToken()) is MethodDesc methodOperand)
+                            {
+                                HandleMethodReflectionAccess(methodBody, offset, methodOperand);
+                            }
+
+                            PopUnknown(currentStack, 1, methodBody, offset);
+                            PushUnknown(currentStack);
+                        }
                         break;
 
                     case ILOpcode.ldind_i:
@@ -544,7 +557,6 @@ namespace ILCompiler.Dataflow
                     case ILOpcode.ldind_u2:
                     case ILOpcode.ldind_u4:
                     case ILOpcode.ldlen:
-                    case ILOpcode.ldvirtftn:
                     case ILOpcode.localloc:
                     case ILOpcode.refanytype:
                     case ILOpcode.refanyval:
@@ -915,7 +927,7 @@ namespace ILCompiler.Dataflow
             currentStack.Push(newSlot);
         }
 
-        private static void ScanLdtoken(object operand, Stack<StackSlot> currentStack)
+        private void ScanLdtoken(MethodIL methodBody, int offset, object operand, Stack<StackSlot> currentStack)
         {
             if (operand is TypeDesc type)
             {
@@ -957,10 +969,16 @@ namespace ILCompiler.Dataflow
             {
                 StackSlot slot = new StackSlot(new RuntimeMethodHandleValue(method));
                 currentStack.Push(slot);
+
+                HandleMethodReflectionAccess(methodBody, offset, method);
             }
             else
             {
+                Debug.Assert(operand is FieldDesc);
+
                 PushUnknown(currentStack);
+
+                HandleFieldReflectionAccess(methodBody, offset, (FieldDesc)operand);
             }
         }
 
@@ -1206,6 +1224,16 @@ namespace ILCompiler.Dataflow
             }
         }
 
+        /// <summary>
+        /// Called to handle reflection access to a method without any other specifics (ldtoken or ldftn for example)
+        /// </summary>
+        protected abstract void HandleMethodReflectionAccess(MethodIL methodBody, int offset, MethodDesc accessedMethod);
+
+        /// <summary>
+        /// Called to handle reflection access to a field without any other specifics (ldtoken for example)
+        /// </summary>
+        protected abstract void HandleFieldReflectionAccess(MethodIL methodBody, int offset, FieldDesc accessedField);
+
         private void HandleCall(
             MethodIL callingMethodBody,
             ILOpcode opcode,
index 65d7fe84b2da8618fcfe06dd6f0c2961a6c29ab8..49528b93a2688d6648fa7ff7264bc2879da2c39b 100644 (file)
@@ -27,7 +27,5 @@ namespace ILLink.Shared.TrimAnalysis
         public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
 
         public TypeDesc? StaticType { get; }
-
-        internal ParameterOrigin ParameterOrigin => new ParameterOrigin(Parameter.Method.Method, (int)Parameter.Index);
     }
 }
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/Origin.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/Origin.cs
deleted file mode 100644 (file)
index bf8142a..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using Internal.TypeSystem;
-
-namespace ILCompiler.Dataflow
-{
-    internal abstract class Origin
-    {
-    }
-
-    internal sealed class MethodReturnOrigin : Origin
-    {
-        public MethodDesc Method { get; }
-
-        public MethodReturnOrigin(MethodDesc method)
-        {
-            Method = method;
-        }
-
-        public string GetDisplayName() => Method.GetDisplayName();
-    }
-
-    internal sealed class ParameterOrigin : Origin
-    {
-        public MethodDesc Method { get; }
-        public int Index { get; }
-
-        public ParameterOrigin(MethodDesc method, int index)
-        {
-            Method = method;
-            Index = index;
-        }
-
-        public string GetDisplayName() => Method.GetDisplayName();
-    }
-
-    internal sealed class MethodOrigin : Origin
-    {
-        public MethodDesc Method { get; }
-
-        public MethodOrigin(MethodDesc method)
-        {
-            Method = method;
-        }
-
-        public string GetDisplayName() => Method.GetDisplayName();
-    }
-
-    internal sealed class FieldOrigin : Origin
-    {
-        public FieldDesc Field { get; }
-
-        public FieldOrigin(FieldDesc field)
-        {
-            Field = field;
-        }
-
-        public string GetDisplayName() => Field.GetDisplayName();
-    }
-
-    internal sealed class TypeOrigin : Origin
-    {
-        public MetadataType Type { get; }
-
-        public TypeOrigin(MetadataType type)
-        {
-            Type = type;
-        }
-
-        public string GetDisplayName() => Type.GetDisplayName();
-    }
-
-    internal sealed class GenericParameterOrigin : Origin
-    {
-        public GenericParameterDesc GenericParameter { get; }
-
-        public string Name => GenericParameter.Name;
-
-        public GenericParameterOrigin(GenericParameterDesc genericParam)
-        {
-            GenericParameter = genericParam;
-        }
-
-        public string GetDisplayName() => GenericParameter.GetDisplayName();
-    }
-}
index f9b2615f62bdcaa68b9f2fd821aefb4278f7fcbc..d7b3e3fd7b6209384f8e77752e6772d2503aead8 100644 (file)
@@ -23,52 +23,58 @@ namespace ILCompiler.Dataflow
     {
         private DependencyList _dependencies = new DependencyList();
         private readonly Logger _logger;
+        private readonly MetadataType? _typeHierarchyDataFlowOrigin;
+        private readonly bool _enabled;
+
         public NodeFactory Factory { get; }
         public FlowAnnotations Annotations { get; }
-        private bool _typeHierarchyDataFlow;
-        private bool _enabled;
         public DependencyList Dependencies { get => _dependencies; }
 
-        public ReflectionMarker(Logger logger, NodeFactory factory, FlowAnnotations annotations, bool typeHierarchyDataFlow, bool enabled)
+        public ReflectionMarker(Logger logger, NodeFactory factory, FlowAnnotations annotations, MetadataType? typeHierarchyDataFlowOrigin, bool enabled)
         {
             _logger = logger;
             Factory = factory;
             Annotations = annotations;
-            _typeHierarchyDataFlow = typeHierarchyDataFlow;
+            _typeHierarchyDataFlowOrigin = typeHierarchyDataFlowOrigin;
             _enabled = enabled;
         }
 
-        internal void MarkTypeForDynamicallyAccessedMembers(in MessageOrigin origin, TypeDesc typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, Origin memberWithRequirements, bool declaredOnly = false)
+        internal void MarkTypeForDynamicallyAccessedMembers(in MessageOrigin origin, TypeDesc typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, string reason, bool declaredOnly = false)
         {
             if (!_enabled)
                 return;
 
             foreach (var member in typeDefinition.GetDynamicallyAccessedMembers(requiredMemberTypes, declaredOnly))
             {
-                switch (member)
-                {
-                    case MethodDesc method:
-                        MarkMethod(origin, method, memberWithRequirements);
-                        break;
-                    case FieldDesc field:
-                        MarkField(origin, field, memberWithRequirements);
-                        break;
-                    case MetadataType nestedType:
-                        MarkType(origin, nestedType, memberWithRequirements);
-                        break;
-                    case PropertyPseudoDesc property:
-                        MarkProperty(origin, property, memberWithRequirements);
-                        break;
-                    case EventPseudoDesc @event:
-                        MarkEvent(origin, @event, memberWithRequirements);
-                        break;
-                        // case InterfaceImplementation
-                        //  Nothing to do currently as Native AOT will presere all interfaces on a preserved type
-                }
+                MarkTypeSystemEntity(origin, member, reason);
             }
         }
 
-        internal bool TryResolveTypeNameAndMark(string typeName, in DiagnosticContext diagnosticContext, bool needsAssemblyName, Origin memberWithRequirements, [NotNullWhen(true)] out TypeDesc? type)
+        internal void MarkTypeSystemEntity(in MessageOrigin origin, TypeSystemEntity entity, string reason)
+        {
+            switch (entity)
+            {
+                case MethodDesc method:
+                    MarkMethod(origin, method, reason);
+                    break;
+                case FieldDesc field:
+                    MarkField(origin, field, reason);
+                    break;
+                case MetadataType nestedType:
+                    MarkType(origin, nestedType, reason);
+                    break;
+                case PropertyPseudoDesc property:
+                    MarkProperty(origin, property, reason);
+                    break;
+                case EventPseudoDesc @event:
+                    MarkEvent(origin, @event, reason);
+                    break;
+                    // case InterfaceImplementation
+                    //  Nothing to do currently as Native AOT will presere all interfaces on a preserved type
+            }
+        }
+
+        internal bool TryResolveTypeNameAndMark(string typeName, in DiagnosticContext diagnosticContext, bool needsAssemblyName, string reason, [NotNullWhen(true)] out TypeDesc? type)
         {
             ModuleDesc? callingModule = ((diagnosticContext.Origin.MemberDefinition as MethodDesc)?.OwningType as MetadataType)?.Module;
 
@@ -84,102 +90,102 @@ namespace ILCompiler.Dataflow
             {
                 // Also add module metadata in case this reference was through a type forward
                 if (Factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType()))
-                    _dependencies.Add(Factory.ModuleMetadata(referenceModule), memberWithRequirements.ToString());
+                    _dependencies.Add(Factory.ModuleMetadata(referenceModule), reason);
 
-                MarkType(diagnosticContext.Origin, foundType, memberWithRequirements);
+                MarkType(diagnosticContext.Origin, foundType, reason);
             }
 
             type = foundType;
             return true;
         }
 
-        internal void MarkType(in MessageOrigin origin, TypeDesc type, Origin memberWithRequirements)
+        internal void MarkType(in MessageOrigin origin, TypeDesc type, string reason)
         {
             if (!_enabled)
                 return;
 
-            RootingHelpers.TryGetDependenciesForReflectedType(ref _dependencies, Factory, type, memberWithRequirements.ToString());
+            RootingHelpers.TryGetDependenciesForReflectedType(ref _dependencies, Factory, type, reason);
         }
 
-        internal void MarkMethod(in MessageOrigin origin, MethodDesc method, Origin memberWithRequirements)
+        internal void MarkMethod(in MessageOrigin origin, MethodDesc method, string reason)
         {
             if (!_enabled)
                 return;
 
-            CheckAndWarnOnReflectionAccess(origin, method, memberWithRequirements);
+            CheckAndWarnOnReflectionAccess(origin, method);
 
-            RootingHelpers.TryGetDependenciesForReflectedMethod(ref _dependencies, Factory, method, memberWithRequirements.ToString());
+            RootingHelpers.TryGetDependenciesForReflectedMethod(ref _dependencies, Factory, method, reason);
         }
 
-        private void MarkField(in MessageOrigin origin, FieldDesc field, Origin memberWithRequirements)
+        internal void MarkField(in MessageOrigin origin, FieldDesc field, string reason)
         {
             if (!_enabled)
                 return;
 
-            CheckAndWarnOnReflectionAccess(origin, field, memberWithRequirements);
+            CheckAndWarnOnReflectionAccess(origin, field);
 
-            RootingHelpers.TryGetDependenciesForReflectedField(ref _dependencies, Factory, field, memberWithRequirements.ToString());
+            RootingHelpers.TryGetDependenciesForReflectedField(ref _dependencies, Factory, field, reason);
         }
 
-        internal void MarkProperty(in MessageOrigin origin, PropertyPseudoDesc property, Origin memberWithRequirements)
+        internal void MarkProperty(in MessageOrigin origin, PropertyPseudoDesc property, string reason)
         {
             if (!_enabled)
                 return;
 
             if (property.GetMethod != null)
-                MarkMethod(origin, property.GetMethod, memberWithRequirements);
+                MarkMethod(origin, property.GetMethod, reason);
             if (property.SetMethod != null)
-                MarkMethod(origin, property.SetMethod, memberWithRequirements);
+                MarkMethod(origin, property.SetMethod, reason);
         }
 
-        private void MarkEvent(in MessageOrigin origin, EventPseudoDesc @event, Origin memberWithRequirements)
+        private void MarkEvent(in MessageOrigin origin, EventPseudoDesc @event, string reason)
         {
             if (!_enabled)
                 return;
 
             if (@event.AddMethod != null)
-                MarkMethod(origin, @event.AddMethod, memberWithRequirements);
+                MarkMethod(origin, @event.AddMethod, reason);
             if (@event.RemoveMethod != null)
-                MarkMethod(origin, @event.RemoveMethod, memberWithRequirements);
+                MarkMethod(origin, @event.RemoveMethod, reason);
         }
 
-        internal void MarkConstructorsOnType(in MessageOrigin origin, TypeDesc type, Func<MethodDesc, bool>? filter, Origin memberWithRequirements, BindingFlags? bindingFlags = null)
+        internal void MarkConstructorsOnType(in MessageOrigin origin, TypeDesc type, Func<MethodDesc, bool>? filter, string reason, BindingFlags? bindingFlags = null)
         {
             if (!_enabled)
                 return;
 
             foreach (var ctor in type.GetConstructorsOnType(filter, bindingFlags))
-                MarkMethod(origin, ctor, memberWithRequirements);
+                MarkMethod(origin, ctor, reason);
         }
 
-        internal void MarkFieldsOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func<FieldDesc, bool> filter, Origin memberWithRequirements, BindingFlags? bindingFlags = BindingFlags.Default)
+        internal void MarkFieldsOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func<FieldDesc, bool> filter, string reason, BindingFlags? bindingFlags = BindingFlags.Default)
         {
             if (!_enabled)
                 return;
 
             foreach (var field in type.GetFieldsOnTypeHierarchy(filter, bindingFlags))
-                MarkField(origin, field, memberWithRequirements);
+                MarkField(origin, field, reason);
         }
 
-        internal void MarkPropertiesOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func<PropertyPseudoDesc, bool> filter, Origin memberWithRequirements, BindingFlags? bindingFlags = BindingFlags.Default)
+        internal void MarkPropertiesOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func<PropertyPseudoDesc, bool> filter, string reason, BindingFlags? bindingFlags = BindingFlags.Default)
         {
             if (!_enabled)
                 return;
 
             foreach (var property in type.GetPropertiesOnTypeHierarchy(filter, bindingFlags))
-                MarkProperty(origin, property, memberWithRequirements);
+                MarkProperty(origin, property, reason);
         }
 
-        internal void MarkEventsOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func<EventPseudoDesc, bool> filter, Origin memberWithRequirements, BindingFlags? bindingFlags = BindingFlags.Default)
+        internal void MarkEventsOnTypeHierarchy(in MessageOrigin origin, TypeDesc type, Func<EventPseudoDesc, bool> filter, string reason, BindingFlags? bindingFlags = BindingFlags.Default)
         {
             if (!_enabled)
                 return;
 
             foreach (var @event in type.GetEventsOnTypeHierarchy(filter, bindingFlags))
-                MarkEvent(origin, @event, memberWithRequirements);
+                MarkEvent(origin, @event, reason);
         }
 
-        internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type)
+        internal void MarkStaticConstructor(in MessageOrigin origin, TypeDesc type, string reason)
         {
             if (!_enabled)
                 return;
@@ -192,14 +198,17 @@ namespace ILCompiler.Dataflow
             }
         }
 
-        private void CheckAndWarnOnReflectionAccess(in MessageOrigin origin, TypeSystemEntity entity, Origin memberWithRequirements)
+        internal void CheckAndWarnOnReflectionAccess(in MessageOrigin origin, TypeSystemEntity entity)
         {
+            if (!_enabled)
+                return;
+
             if (entity.DoesMemberRequire(DiagnosticUtilities.RequiresUnreferencedCodeAttribute, out CustomAttributeValue<TypeDesc>? requiresAttribute))
             {
-                if (_typeHierarchyDataFlow)
+                if (_typeHierarchyDataFlowOrigin is not null)
                 {
                     _logger.LogWarning(origin, DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithRequiresUnreferencedCode,
-                        ((TypeOrigin)memberWithRequirements).GetDisplayName(),
+                        _typeHierarchyDataFlowOrigin.GetDisplayName(),
                         entity.GetDisplayName(),
                         MessageFormat.FormatRequiresAttributeMessageArg(DiagnosticUtilities.GetRequiresAttributeMessage(requiresAttribute.Value)),
                         MessageFormat.FormatRequiresAttributeUrlArg(DiagnosticUtilities.GetRequiresAttributeUrl(requiresAttribute.Value)));
@@ -223,14 +232,14 @@ namespace ILCompiler.Dataflow
             if (!Annotations.ShouldWarnWhenAccessedForReflection(entity))
                 return;
 
-            if (_typeHierarchyDataFlow)
+            if (_typeHierarchyDataFlowOrigin is not null)
             {
                 // Don't check whether the current scope is a RUC type or RUC method because these warnings
                 // are not suppressed in RUC scopes. Here the scope represents the DynamicallyAccessedMembers
                 // annotation on a type, not a callsite which uses the annotation. We always want to warn about
                 // possible reflection access indicated by these annotations.
                 _logger.LogWarning(origin, DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithDynamicallyAccessedMembers,
-                    ((TypeOrigin)memberWithRequirements).GetDisplayName(), entity.GetDisplayName());
+                    _typeHierarchyDataFlowOrigin.GetDisplayName(), entity.GetDisplayName());
             }
             else
             {
index 22692dc23873041f2034756371a2adda4bcc747c..7a73ba40d0812f4a46b25668448b2885e67b5055 100644 (file)
@@ -77,7 +77,7 @@ namespace ILCompiler.Dataflow
             _logger = logger;
             _factory = factory;
             _origin = origin;
-            _reflectionMarker = new ReflectionMarker(logger, factory, annotations, typeHierarchyDataFlow: false, enabled: false);
+            _reflectionMarker = new ReflectionMarker(logger, factory, annotations, typeHierarchyDataFlowOrigin: null, enabled: false);
             TrimAnalysisPatterns = new TrimAnalysisPatternStore(MultiValueLattice, logger);
         }
 
@@ -86,7 +86,7 @@ namespace ILCompiler.Dataflow
             base.InterproceduralScan(methodBody);
 
             // Replace the reflection marker with one which actually marks
-            _reflectionMarker = new ReflectionMarker(_logger, _factory, _annotations, typeHierarchyDataFlow: false, enabled: true);
+            _reflectionMarker = new ReflectionMarker(_logger, _factory, _annotations, typeHierarchyDataFlowOrigin: null, enabled: true);
             TrimAnalysisPatterns.MarkAndProduceDiagnostics(_reflectionMarker);
         }
 
@@ -100,7 +100,7 @@ namespace ILCompiler.Dataflow
                 var method = methodBody.OwningMethod;
                 var methodReturnValue = _annotations.GetMethodReturnValue(method);
                 if (methodReturnValue.DynamicallyAccessedMemberTypes != 0)
-                    HandleAssignmentPattern(_origin, ReturnValue, methodReturnValue, new MethodOrigin(method));
+                    HandleAssignmentPattern(_origin, ReturnValue, methodReturnValue, method.GetDisplayName());
             }
         }
 
@@ -117,8 +117,8 @@ namespace ILCompiler.Dataflow
         {
             DynamicallyAccessedMemberTypes annotation = flowAnnotations.GetTypeAnnotation(type);
             Debug.Assert(annotation != DynamicallyAccessedMemberTypes.None);
-            var reflectionMarker = new ReflectionMarker(logger, factory, flowAnnotations, typeHierarchyDataFlow: true, enabled: true);
-            reflectionMarker.MarkTypeForDynamicallyAccessedMembers(new MessageOrigin(type), type, annotation, new TypeOrigin(type));
+            var reflectionMarker = new ReflectionMarker(logger, factory, flowAnnotations, typeHierarchyDataFlowOrigin: type, enabled: true);
+            reflectionMarker.MarkTypeForDynamicallyAccessedMembers(new MessageOrigin(type), type, annotation, type.GetDisplayName());
             return reflectionMarker.Dependencies;
         }
 
@@ -141,24 +141,36 @@ namespace ILCompiler.Dataflow
 
         protected override MultiValue GetFieldValue(FieldDesc field) => _annotations.GetFieldValue(field);
 
-        private void HandleStoreValueWithDynamicallyAccessedMembers(MethodIL methodBody, int offset, ValueWithDynamicallyAccessedMembers targetValue, MultiValue sourceValue, Origin memberWithRequirements)
+        private void HandleStoreValueWithDynamicallyAccessedMembers(MethodIL methodBody, int offset, ValueWithDynamicallyAccessedMembers targetValue, MultiValue sourceValue, string reason)
         {
             // We must record all field accesses since we need to check RUC/RDC/RAF attributes on them regardless of annotations
             if (targetValue.DynamicallyAccessedMemberTypes != 0 || targetValue is FieldValue)
             {
                 _origin = _origin.WithInstructionOffset(methodBody, offset);
-                HandleAssignmentPattern(_origin, sourceValue, targetValue, memberWithRequirements);
+                HandleAssignmentPattern(_origin, sourceValue, targetValue, reason);
             }
         }
 
         protected override void HandleStoreField(MethodIL methodBody, int offset, FieldValue field, MultiValue valueToStore)
-            => HandleStoreValueWithDynamicallyAccessedMembers(methodBody, offset, field, valueToStore, new FieldOrigin(field.Field));
+            => HandleStoreValueWithDynamicallyAccessedMembers(methodBody, offset, field, valueToStore, field.Field.GetDisplayName());
 
         protected override void HandleStoreParameter(MethodIL methodBody, int offset, MethodParameterValue parameter, MultiValue valueToStore)
-            => HandleStoreValueWithDynamicallyAccessedMembers(methodBody, offset, parameter, valueToStore, parameter.ParameterOrigin);
+            => HandleStoreValueWithDynamicallyAccessedMembers(methodBody, offset, parameter, valueToStore, parameter.Parameter.Method.GetDisplayName());
 
         protected override void HandleStoreMethodReturnValue(MethodIL methodBody, int offset, MethodReturnValue returnValue, MultiValue valueToStore)
-            => HandleStoreValueWithDynamicallyAccessedMembers(methodBody, offset, returnValue, valueToStore, new MethodOrigin(returnValue.Method));
+            => HandleStoreValueWithDynamicallyAccessedMembers(methodBody, offset, returnValue, valueToStore, returnValue.Method.GetDisplayName());
+
+        protected override void HandleMethodReflectionAccess(MethodIL methodBody, int offset, MethodDesc accessedMethod)
+        {
+            _origin = _origin.WithInstructionOffset(methodBody, offset);
+            TrimAnalysisPatterns.Add(new TrimAnalysisReflectionAccessPattern(accessedMethod, _origin));
+        }
+
+        protected override void HandleFieldReflectionAccess(MethodIL methodBody, int offset, FieldDesc accessedField)
+        {
+            _origin = _origin.WithInstructionOffset(methodBody, offset);
+            TrimAnalysisPatterns.Add(new TrimAnalysisReflectionAccessPattern(accessedField, _origin));
+        }
 
         public override bool HandleCall(MethodIL callingMethodBody, MethodDesc calledMethod, ILOpcode operation, int offset, ValueNodeList methodParams, out MultiValue methodReturnValue)
         {
@@ -220,7 +232,7 @@ namespace ILCompiler.Dataflow
 
             MultiValue? maybeMethodReturnValue = null;
 
-            var handleCallAction = new HandleCallAction(reflectionMarker.Annotations, reflectionMarker, diagnosticContext, callingMethodDefinition, new MethodOrigin(calledMethod));
+            var handleCallAction = new HandleCallAction(reflectionMarker.Annotations, reflectionMarker, diagnosticContext, callingMethodDefinition, calledMethod.GetDisplayName());
 
             var intrinsicId = Intrinsics.GetIntrinsicIdForMethod(calledMethod);
             switch (intrinsicId)
@@ -617,9 +629,9 @@ namespace ILCompiler.Dataflow
             in MessageOrigin origin,
             in MultiValue value,
             ValueWithDynamicallyAccessedMembers targetValue,
-            Origin memberWithRequirements)
+            string reason)
         {
-            TrimAnalysisPatterns.Add(new TrimAnalysisAssignmentPattern(value, targetValue, origin, memberWithRequirements));
+            TrimAnalysisPatterns.Add(new TrimAnalysisAssignmentPattern(value, targetValue, origin, reason));
         }
 
         private static bool IsPInvokeDangerous(MethodDesc calledMethod, out bool comDangerousMethod, out bool aotUnsafeDelegate)
index b4eb5fa48eec13a5825a8c05eb704cfc927790e0..43e01852b31abaef6c8961d90524cfa926e86c88 100644 (file)
@@ -13,21 +13,21 @@ namespace ILLink.Shared.TrimAnalysis
     internal partial struct RequireDynamicallyAccessedMembersAction
     {
         private readonly ReflectionMarker _reflectionMarker;
-        private readonly Origin _memberWithRequirements;
+        private readonly string _reason;
 
         public RequireDynamicallyAccessedMembersAction(
             ReflectionMarker reflectionMarker,
             in DiagnosticContext diagnosticContext,
-            Origin memberWithRequirements)
+            string reason)
         {
             _reflectionMarker = reflectionMarker;
             _diagnosticContext = diagnosticContext;
-            _memberWithRequirements = memberWithRequirements;
+            _reason = reason;
         }
 
         public partial bool TryResolveTypeNameAndMark(string typeName, bool needsAssemblyName, out TypeProxy type)
         {
-            if (_reflectionMarker.TryResolveTypeNameAndMark(typeName, _diagnosticContext, needsAssemblyName, _memberWithRequirements, out TypeDesc? foundType))
+            if (_reflectionMarker.TryResolveTypeNameAndMark(typeName, _diagnosticContext, needsAssemblyName, _reason, out TypeDesc? foundType))
             {
                 type = new(foundType);
                 return true;
@@ -41,7 +41,7 @@ namespace ILLink.Shared.TrimAnalysis
 
         private partial void MarkTypeForDynamicallyAccessedMembers(in TypeProxy type, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
         {
-            _reflectionMarker.MarkTypeForDynamicallyAccessedMembers(_diagnosticContext.Origin, type.Type, dynamicallyAccessedMemberTypes, _memberWithRequirements);
+            _reflectionMarker.MarkTypeForDynamicallyAccessedMembers(_diagnosticContext.Origin, type.Type, dynamicallyAccessedMemberTypes, _reason);
         }
     }
 }
index 0ceead7dcb856dc65ca232f0d95fa832b5a9d8f4..2e1bd4cd1c18fd42c7e130ac70c67c3a1ee32023 100644 (file)
@@ -18,14 +18,14 @@ namespace ILCompiler.Dataflow
         public MultiValue Source { init; get; }
         public MultiValue Target { init; get; }
         public MessageOrigin Origin { init; get; }
-        internal Origin MemberWithRequirements { init; get; }
+        internal string Reason { init; get; }
 
-        internal TrimAnalysisAssignmentPattern(MultiValue source, MultiValue target, MessageOrigin origin, Origin memberWithRequirements)
+        internal TrimAnalysisAssignmentPattern(MultiValue source, MultiValue target, MessageOrigin origin, string reason)
         {
             Source = source.Clone();
             Target = target.Clone();
             Origin = origin;
-            MemberWithRequirements = memberWithRequirements;
+            Reason = reason;
         }
 
         public TrimAnalysisAssignmentPattern Merge(ValueSetLattice<SingleValue> lattice, TrimAnalysisAssignmentPattern other)
@@ -36,7 +36,7 @@ namespace ILCompiler.Dataflow
                 lattice.Meet(Source, other.Source),
                 lattice.Meet(Target, other.Target),
                 Origin,
-                MemberWithRequirements);
+                Reason);
         }
 
         public void MarkAndProduceDiagnostics(ReflectionMarker reflectionMarker, Logger logger)
@@ -65,7 +65,7 @@ namespace ILCompiler.Dataflow
                     if (targetValue is not ValueWithDynamicallyAccessedMembers targetWithDynamicallyAccessedMembers)
                         throw new NotImplementedException();
 
-                    var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(reflectionMarker, diagnosticContext, MemberWithRequirements);
+                    var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(reflectionMarker, diagnosticContext, Reason);
                     requireDynamicallyAccessedMembersAction.Invoke(sourceValue, targetWithDynamicallyAccessedMembers);
                 }
             }
index 44ff8eabf39ab5c6c3991f4925cd01715ff60e3f..85c9aa72eee383eccaacef933bb1197b2f529338 100644 (file)
@@ -5,6 +5,7 @@ using System.Collections.Generic;
 using ILCompiler.Logging;
 using ILLink.Shared.DataFlow;
 using ILLink.Shared.TrimAnalysis;
+using Internal.TypeSystem;
 
 #nullable enable
 
@@ -14,6 +15,7 @@ namespace ILCompiler.Dataflow
     {
         private readonly Dictionary<(MessageOrigin, bool), TrimAnalysisAssignmentPattern> AssignmentPatterns;
         private readonly Dictionary<MessageOrigin, TrimAnalysisMethodCallPattern> MethodCallPatterns;
+        private readonly Dictionary<(MessageOrigin, TypeSystemEntity), TrimAnalysisReflectionAccessPattern> ReflectionAccessPatterns;
         private readonly ValueSetLattice<SingleValue> Lattice;
         private readonly Logger _logger;
 
@@ -21,6 +23,7 @@ namespace ILCompiler.Dataflow
         {
             AssignmentPatterns = new Dictionary<(MessageOrigin, bool), TrimAnalysisAssignmentPattern>();
             MethodCallPatterns = new Dictionary<MessageOrigin, TrimAnalysisMethodCallPattern>();
+            ReflectionAccessPatterns = new Dictionary<(MessageOrigin, TypeSystemEntity), TrimAnalysisReflectionAccessPattern>();
             Lattice = lattice;
             _logger = logger;
         }
@@ -53,6 +56,14 @@ namespace ILCompiler.Dataflow
             MethodCallPatterns[pattern.Origin] = pattern.Merge(Lattice, existingPattern);
         }
 
+        public void Add(TrimAnalysisReflectionAccessPattern pattern)
+        {
+            ReflectionAccessPatterns.TryAdd((pattern.Origin, pattern.Entity), pattern);
+
+            // No Merge - there's nothing to merge since this pattern is unequily identified by both the origin and the entity
+            // and there's only one way to "reflection access" an entity.
+        }
+
         public void MarkAndProduceDiagnostics(ReflectionMarker reflectionMarker)
         {
             foreach (var pattern in AssignmentPatterns.Values)
@@ -60,6 +71,9 @@ namespace ILCompiler.Dataflow
 
             foreach (var pattern in MethodCallPatterns.Values)
                 pattern.MarkAndProduceDiagnostics(reflectionMarker, _logger);
+
+            foreach (var pattern in ReflectionAccessPatterns.Values)
+                pattern.MarkAndProduceDiagnostics(reflectionMarker, _logger);
         }
     }
 }
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisReflectionAccessPattern.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisReflectionAccessPattern.cs
new file mode 100644 (file)
index 0000000..8a07621
--- /dev/null
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using ILCompiler.Logging;
+using Internal.TypeSystem;
+
+namespace ILCompiler.Dataflow
+{
+    public readonly record struct TrimAnalysisReflectionAccessPattern
+    {
+        public TypeSystemEntity Entity { init; get; }
+        public MessageOrigin Origin { init; get; }
+
+        internal TrimAnalysisReflectionAccessPattern(TypeSystemEntity entity, MessageOrigin origin)
+        {
+            Entity = entity;
+            Origin = origin;
+        }
+
+        // No Merge - there's nothing to merge since this pattern is unequily identified by both the origin and the entity
+        // and there's only one way to "reflection access" an entity.
+
+        public void MarkAndProduceDiagnostics(ReflectionMarker reflectionMarker, Logger logger)
+        {
+            reflectionMarker.CheckAndWarnOnReflectionAccess(Origin, Entity);
+        }
+    }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DynamicDependencyAttributeAlgorithm.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DynamicDependencyAttributeAlgorithm.cs
deleted file mode 100644 (file)
index 8f7130c..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-// 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;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Reflection.Metadata;
-
-using Internal.TypeSystem;
-using Internal.TypeSystem.Ecma;
-
-using ILCompiler.Logging;
-
-using ILLink.Shared;
-
-using static ILCompiler.Dataflow.DynamicallyAccessedMembersBinder;
-
-using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
-
-namespace ILCompiler.DependencyAnalysis
-{
-    /// <summary>
-    /// Computes the list of dependencies from DynamicDependencyAttribute.
-    /// https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.dynamicdependencyattribute
-    /// </summary>
-    internal static class DynamicDependencyAttributeAlgorithm
-    {
-        public static void AddDependenciesDueToDynamicDependencyAttribute(ref DependencyList dependencies, NodeFactory factory, EcmaMethod method)
-        {
-            foreach (var attribute in method.GetDecodedCustomAttributes("System.Diagnostics.CodeAnalysis", "DynamicDependencyAttribute"))
-            {
-                AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, method, method.OwningType, attribute);
-            }
-        }
-
-        public static void AddDependenciesDueToDynamicDependencyAttribute(ref DependencyList dependencies, NodeFactory factory, EcmaField field)
-        {
-            foreach (var attribute in field.GetDecodedCustomAttributes("System.Diagnostics.CodeAnalysis", "DynamicDependencyAttribute"))
-            {
-                AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, field, field.OwningType, attribute);
-            }
-        }
-
-        private static void AddDependenciesDueToDynamicDependencyAttribute(
-            ref DependencyList dependencies,
-            NodeFactory factory,
-            TypeSystemEntity entity,
-            TypeDesc owningType,
-            CustomAttributeValue<TypeDesc> attribute)
-        {
-            IEnumerable<TypeSystemEntity> members;
-
-            static MetadataType Linkerify(TypeDesc type)
-            {
-                // IL Linker compatibility: illink will call Resolve() that will strip parameter types and genericness
-                // and operate on the definition.
-                while (type.IsParameterizedType)
-                    type = ((ParameterizedType)type).ParameterType;
-                return (MetadataType)type.GetTypeDefinition();
-            }
-
-            // First figure out the list of members that this maps to.
-            // These are the ways to specify the members:
-            //
-            // * A string that contains a documentation signature
-            // * DynamicallyAccessedMembers enum
-
-            var fixedArgs = attribute.FixedArguments;
-            TypeDesc targetType;
-
-            if (fixedArgs.Length > 0 && fixedArgs[0].Value is string sigFromAttribute)
-            {
-                switch (fixedArgs.Length)
-                {
-                    // DynamicDependencyAttribute(String)
-                    case 1:
-                        targetType = owningType;
-                        break;
-
-                    // DynamicDependencyAttribute(String, Type)
-                    case 2 when fixedArgs[1].Value is TypeDesc typeFromAttribute:
-                        targetType = typeFromAttribute;
-                        break;
-
-                    // DynamicDependencyAttribute(String, String, String)
-                    case 3 when fixedArgs[1].Value is string typeStringFromAttribute
-                        && fixedArgs[2].Value is string assemblyStringFromAttribute:
-                        ModuleDesc asm = factory.TypeSystemContext.ResolveAssembly(new System.Reflection.AssemblyName(assemblyStringFromAttribute), throwIfNotFound: false);
-                        if (asm == null)
-                        {
-                            ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
-                                new MessageOrigin(entity),
-                                DiagnosticId.UnresolvedAssemblyInDynamicDependencyAttribute,
-                                assemblyStringFromAttribute);
-                            return;
-                        }
-
-                        targetType = DocumentationSignatureParser.GetTypeByDocumentationSignature((IAssemblyDesc)asm, typeStringFromAttribute);
-                        if (targetType == null)
-                        {
-                            ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
-                                new MessageOrigin(entity),
-                                DiagnosticId.UnresolvedTypeInDynamicDependencyAttribute,
-                                typeStringFromAttribute);
-                            return;
-                        }
-                        break;
-
-                    default:
-                        Debug.Fail("Did we introduce a new overload?");
-                        return;
-                }
-
-                members = DocumentationSignatureParser.GetMembersByDocumentationSignature(Linkerify(targetType), sigFromAttribute, acceptName: true);
-
-                if (!members.Any())
-                {
-                    ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
-                        new MessageOrigin(entity),
-                        DiagnosticId.NoMembersResolvedForMemberSignatureOrType,
-                        sigFromAttribute,
-                        targetType.GetDisplayName());
-                    return;
-                }
-            }
-            else if (fixedArgs.Length > 0 && fixedArgs[0].Value is int memberTypesFromAttribute)
-            {
-                if (fixedArgs.Length == 2 && fixedArgs[1].Value is TypeDesc typeFromAttribute)
-                {
-                    // DynamicDependencyAttribute(DynamicallyAccessedMemberTypes, Type)
-                    targetType = typeFromAttribute;
-                }
-                else if (fixedArgs.Length == 3 && fixedArgs[1].Value is string typeStringFromAttribute
-                    && fixedArgs[2].Value is string assemblyStringFromAttribute)
-                {
-                    // DynamicDependencyAttribute(DynamicallyAccessedMemberTypes, String, String)
-                    ModuleDesc asm = factory.TypeSystemContext.ResolveAssembly(new System.Reflection.AssemblyName(assemblyStringFromAttribute), throwIfNotFound: false);
-                    if (asm == null)
-                    {
-                        ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
-                            new MessageOrigin(entity),
-                            DiagnosticId.UnresolvedAssemblyInDynamicDependencyAttribute,
-                            assemblyStringFromAttribute);
-                        return;
-                    }
-
-                    targetType = DocumentationSignatureParser.GetTypeByDocumentationSignature((IAssemblyDesc)asm, typeStringFromAttribute);
-                    if (targetType == null)
-                    {
-                        ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
-                            new MessageOrigin(entity),
-                            DiagnosticId.UnresolvedTypeInDynamicDependencyAttribute,
-                            typeStringFromAttribute);
-                        return;
-                    }
-                }
-                else
-                {
-                    Debug.Fail("Did we introduce a new overload?");
-                    return;
-                }
-
-                members = Linkerify(targetType).GetDynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)memberTypesFromAttribute);
-
-                if (!members.Any())
-                {
-                    ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
-                    new MessageOrigin(entity),
-                        DiagnosticId.NoMembersResolvedForMemberSignatureOrType,
-                        memberTypesFromAttribute.ToString(),
-                        targetType.GetDisplayName());
-                    return;
-                }
-            }
-            else
-            {
-                Debug.Fail("Did we introduce a new overload?");
-                return;
-            }
-
-            Debug.Assert(members.Any());
-
-            const string reason = "DynamicDependencyAttribute";
-
-            // Now root the discovered members
-            foreach (var member in members)
-            {
-                switch (member)
-                {
-                    case MethodDesc m:
-                        RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, m, reason);
-                        break;
-                    case FieldDesc field:
-                        RootingHelpers.TryGetDependenciesForReflectedField(ref dependencies, factory, field, reason);
-                        break;
-                    case MetadataType nestedType:
-                        RootingHelpers.TryGetDependenciesForReflectedType(ref dependencies, factory, nestedType, reason);
-                        break;
-                    case PropertyPseudoDesc property:
-                        if (property.GetMethod != null)
-                            RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, property.GetMethod, reason);
-                        if (property.SetMethod != null)
-                            RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, property.SetMethod, reason);
-                        break;
-                    case EventPseudoDesc @event:
-                        if (@event.AddMethod != null)
-                            RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, @event.AddMethod, reason);
-                        if (@event.RemoveMethod != null)
-                            RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, @event.RemoveMethod, reason);
-                        break;
-                    default:
-                        Debug.Fail(member.GetType().ToString());
-                        break;
-                }
-            }
-        }
-    }
-}
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DynamicDependencyAttributesOnEntityNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DynamicDependencyAttributesOnEntityNode.cs
new file mode 100644 (file)
index 0000000..95fcd87
--- /dev/null
@@ -0,0 +1,249 @@
+// 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;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Reflection.Metadata;
+
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+using ILCompiler.Dataflow;
+using ILCompiler.DependencyAnalysisFramework;
+using ILCompiler.Logging;
+
+using ILLink.Shared;
+
+using static ILCompiler.Dataflow.DynamicallyAccessedMembersBinder;
+
+namespace ILCompiler.DependencyAnalysis
+{
+    /// <summary>
+    /// Computes the list of dependencies from DynamicDependencyAttribute.
+    /// https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.dynamicdependencyattribute
+    /// </summary>
+    public class DynamicDependencyAttributesOnEntityNode : DependencyNodeCore<NodeFactory>
+    {
+        private readonly TypeSystemEntity _entity;
+
+        public DynamicDependencyAttributesOnEntityNode(TypeSystemEntity entity)
+        {
+            Debug.Assert(entity is EcmaMethod || entity is EcmaField);
+            _entity = entity;
+        }
+
+        public static void AddDependenciesDueToDynamicDependencyAttribute(ref DependencyList dependencies, NodeFactory factory, EcmaMethod method)
+        {
+            if (method.HasCustomAttribute("System.Diagnostics.CodeAnalysis", "DynamicDependencyAttribute"))
+            {
+                dependencies ??= new DependencyList();
+                dependencies.Add(factory.DynamicDependencyAttributesOnEntity(method), "DynamicDependencyAttribute present");
+            }
+        }
+
+        public static void AddDependenciesDueToDynamicDependencyAttribute(ref DependencyList dependencies, NodeFactory factory, EcmaField field)
+        {
+            if (field.HasCustomAttribute("System.Diagnostics.CodeAnalysis", "DynamicDependencyAttribute"))
+            {
+                dependencies ??= new DependencyList();
+                dependencies.Add(factory.DynamicDependencyAttributesOnEntity(field), "DynamicDependencyAttribute present");
+            }
+        }
+
+        public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
+        {
+            DependencyList dependencies = null;
+            switch (_entity)
+            {
+                case EcmaMethod method:
+                    foreach (var attribute in method.GetDecodedCustomAttributes("System.Diagnostics.CodeAnalysis", "DynamicDependencyAttribute"))
+                    {
+                        AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, method, method.OwningType, attribute);
+                    }
+                    break;
+
+                case EcmaField field:
+                    foreach (var attribute in field.GetDecodedCustomAttributes("System.Diagnostics.CodeAnalysis", "DynamicDependencyAttribute"))
+                    {
+                        AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, field, field.OwningType, attribute);
+                    }
+                    break;
+            }
+
+            return dependencies;
+        }
+
+        private static void AddDependenciesDueToDynamicDependencyAttribute(
+            ref DependencyList dependencies,
+            NodeFactory factory,
+            TypeSystemEntity entity,
+            TypeDesc owningType,
+            CustomAttributeValue<TypeDesc> attribute)
+        {
+            IEnumerable<TypeSystemEntity> members;
+
+            static MetadataType Linkerify(TypeDesc type)
+            {
+                // IL Linker compatibility: illink will call Resolve() that will strip parameter types and genericness
+                // and operate on the definition.
+                while (type.IsParameterizedType)
+                    type = ((ParameterizedType)type).ParameterType;
+                return (MetadataType)type.GetTypeDefinition();
+            }
+
+            // First figure out the list of members that this maps to.
+            // These are the ways to specify the members:
+            //
+            // * A string that contains a documentation signature
+            // * DynamicallyAccessedMembers enum
+
+            var fixedArgs = attribute.FixedArguments;
+            TypeDesc targetType;
+
+            UsageBasedMetadataManager metadataManager = (UsageBasedMetadataManager)factory.MetadataManager;
+
+            if (fixedArgs.Length > 0 && fixedArgs[0].Value is string sigFromAttribute)
+            {
+                switch (fixedArgs.Length)
+                {
+                    // DynamicDependencyAttribute(String)
+                    case 1:
+                        targetType = owningType;
+                        break;
+
+                    // DynamicDependencyAttribute(String, Type)
+                    case 2 when fixedArgs[1].Value is TypeDesc typeFromAttribute:
+                        targetType = typeFromAttribute;
+                        break;
+
+                    // DynamicDependencyAttribute(String, String, String)
+                    case 3 when fixedArgs[1].Value is string typeStringFromAttribute
+                        && fixedArgs[2].Value is string assemblyStringFromAttribute:
+                        ModuleDesc asm = factory.TypeSystemContext.ResolveAssembly(new System.Reflection.AssemblyName(assemblyStringFromAttribute), throwIfNotFound: false);
+                        if (asm == null)
+                        {
+                            metadataManager.Logger.LogWarning(
+                                new MessageOrigin(entity),
+                                DiagnosticId.UnresolvedAssemblyInDynamicDependencyAttribute,
+                                assemblyStringFromAttribute);
+                            return;
+                        }
+
+                        targetType = DocumentationSignatureParser.GetTypeByDocumentationSignature((IAssemblyDesc)asm, typeStringFromAttribute);
+                        if (targetType == null)
+                        {
+                            metadataManager.Logger.LogWarning(
+                                new MessageOrigin(entity),
+                                DiagnosticId.UnresolvedTypeInDynamicDependencyAttribute,
+                                typeStringFromAttribute);
+                            return;
+                        }
+                        break;
+
+                    default:
+                        Debug.Fail("Did we introduce a new overload?");
+                        return;
+                }
+
+                members = DocumentationSignatureParser.GetMembersByDocumentationSignature(Linkerify(targetType), sigFromAttribute, acceptName: true);
+
+                if (!members.Any())
+                {
+                    metadataManager.Logger.LogWarning(
+                        new MessageOrigin(entity),
+                        DiagnosticId.NoMembersResolvedForMemberSignatureOrType,
+                        sigFromAttribute,
+                        targetType.GetDisplayName());
+                    return;
+                }
+            }
+            else if (fixedArgs.Length > 0 && fixedArgs[0].Value is int memberTypesFromAttribute)
+            {
+                if (fixedArgs.Length == 2 && fixedArgs[1].Value is TypeDesc typeFromAttribute)
+                {
+                    // DynamicDependencyAttribute(DynamicallyAccessedMemberTypes, Type)
+                    targetType = typeFromAttribute;
+                }
+                else if (fixedArgs.Length == 3 && fixedArgs[1].Value is string typeStringFromAttribute
+                    && fixedArgs[2].Value is string assemblyStringFromAttribute)
+                {
+                    // DynamicDependencyAttribute(DynamicallyAccessedMemberTypes, String, String)
+                    ModuleDesc asm = factory.TypeSystemContext.ResolveAssembly(new System.Reflection.AssemblyName(assemblyStringFromAttribute), throwIfNotFound: false);
+                    if (asm == null)
+                    {
+                        metadataManager.Logger.LogWarning(
+                            new MessageOrigin(entity),
+                            DiagnosticId.UnresolvedAssemblyInDynamicDependencyAttribute,
+                            assemblyStringFromAttribute);
+                        return;
+                    }
+
+                    targetType = DocumentationSignatureParser.GetTypeByDocumentationSignature((IAssemblyDesc)asm, typeStringFromAttribute);
+                    if (targetType == null)
+                    {
+                        metadataManager.Logger.LogWarning(
+                            new MessageOrigin(entity),
+                            DiagnosticId.UnresolvedTypeInDynamicDependencyAttribute,
+                            typeStringFromAttribute);
+                        return;
+                    }
+                }
+                else
+                {
+                    Debug.Fail("Did we introduce a new overload?");
+                    return;
+                }
+
+                members = Linkerify(targetType).GetDynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)memberTypesFromAttribute);
+
+                if (!members.Any())
+                {
+                    metadataManager.Logger.LogWarning(
+                        new MessageOrigin(entity),
+                        DiagnosticId.NoMembersResolvedForMemberSignatureOrType,
+                        memberTypesFromAttribute.ToString(),
+                        targetType.GetDisplayName());
+                    return;
+                }
+            }
+            else
+            {
+                Debug.Fail("Did we introduce a new overload?");
+                return;
+            }
+
+            Debug.Assert(members.Any());
+
+            const string reason = "DynamicDependencyAttribute";
+
+            // Now root the discovered members
+            ReflectionMarker reflectionMarker = new ReflectionMarker(
+                metadataManager.Logger,
+                factory,
+                metadataManager.FlowAnnotations,
+                typeHierarchyDataFlowOrigin: null,
+                enabled: true);
+            foreach (var member in members)
+            {
+                reflectionMarker.MarkTypeSystemEntity(new MessageOrigin(entity), member, reason);
+            }
+
+            dependencies ??= new DependencyList();
+            dependencies.AddRange(reflectionMarker.Dependencies);
+        }
+
+        protected override string GetName(NodeFactory factory)
+        {
+            return "DynamicDependencyAttribute analysis for " + _entity.GetDisplayName();
+        }
+
+        public override bool InterestingForDynamicDependencyAnalysis => false;
+        public override bool HasDynamicDependencies => false;
+        public override bool HasConditionalStaticDependencies => false;
+        public override bool StaticDependenciesAreComputed => true;
+        public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context) => null;
+        public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context) => null;
+    }
+}
index c9b6fdf74023484f63eb1bb336d94926847c27f3..3c98314c9d9d372429947c17ac5e01d026b71289 100644 (file)
@@ -42,7 +42,7 @@ namespace ILCompiler.DependencyAnalysis
 
             if (_field is EcmaField ecmaField)
             {
-                DynamicDependencyAttributeAlgorithm.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaField);
+                DynamicDependencyAttributesOnEntityNode.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaField);
             }
 
             return dependencies;
index 9912ab27621c84eb91b226597fe10b90cc0ca99d..f52615dc369951bc6d2357a1cd66122643253611 100644 (file)
@@ -50,7 +50,7 @@ namespace ILCompiler.DependencyAnalysis
 
             if (_method is EcmaMethod ecmaMethod)
             {
-                DynamicDependencyAttributeAlgorithm.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaMethod);
+                DynamicDependencyAttributesOnEntityNode.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaMethod);
             }
 
             return dependencies;
index efa72b9bcd929d99969377080518f3d9af1e3064..196a51ea2c31f5bc4eb6d0e748d261b818f81aa9 100644 (file)
@@ -378,6 +378,11 @@ namespace ILCompiler.DependencyAnalysis
                 return new DataflowAnalyzedMethodNode(il.MethodIL);
             });
 
+            _dynamicDependencyAttributesOnEntities = new NodeCache<TypeSystemEntity, DynamicDependencyAttributesOnEntityNode>((TypeSystemEntity entity) =>
+            {
+                return new DynamicDependencyAttributesOnEntityNode(entity);
+            });
+
             _embeddedTrimmingDescriptors = new NodeCache<EcmaModule, EmbeddedTrimmingDescriptorNode>((module) =>
             {
                 return new EmbeddedTrimmingDescriptorNode(module);
@@ -699,6 +704,13 @@ namespace ILCompiler.DependencyAnalysis
             return _dataflowAnalyzedMethods.GetOrAdd(new MethodILKey(methodIL));
         }
 
+        private NodeCache<TypeSystemEntity, DynamicDependencyAttributesOnEntityNode> _dynamicDependencyAttributesOnEntities;
+
+        public DynamicDependencyAttributesOnEntityNode DynamicDependencyAttributesOnEntity(TypeSystemEntity entity)
+        {
+            return _dynamicDependencyAttributesOnEntities.GetOrAdd(entity);
+        }
+
         private NodeCache<EcmaModule, EmbeddedTrimmingDescriptorNode> _embeddedTrimmingDescriptors;
 
         public EmbeddedTrimmingDescriptorNode EmbeddedTrimmingDescriptor(EcmaModule module)
index 755f98239e8c6dff9a0ff29eadbbdafcd87fee26..4a3a9312e3747c91e098a545f7195372149d77d5 100644 (file)
@@ -300,6 +300,9 @@ namespace ILCompiler
                 method.IsInRequiresScope(requiresAttribute))
                 return true;
 
+            if (originMember.GetOwningType() == null)  // Basically a way to test if the entity is a member (type, method, field, ...)
+                return false;
+
             MethodDesc owningMethod;
             if (_compilerGeneratedState != null)
             {
index 2f8c2efd84f5453183d3b55524ac3f6a03be1ca9..3b8d78ce20f40b7561427fd34cb5508450482849 100644 (file)
@@ -171,7 +171,7 @@ namespace ILCompiler.Logging
                 _ => null,
             };
 
-            ModuleDesc declaringAssembly = (declaringType as MetadataType)?.Module;
+            ModuleDesc declaringAssembly = (declaringType as MetadataType)?.Module ?? (origin.MemberDefinition as ModuleDesc);
             Debug.Assert(declaringAssembly != null);
             if (declaringAssembly == null)
                 return false;
index 7113962a2764d5314f69ef3d13b499f7877ae4e5..04d765c00e4c788fe37df85695a29d4c19644acf 100644 (file)
@@ -600,7 +600,7 @@ namespace ILCompiler
 
             if (method.GetTypicalMethodDefinition() is Internal.TypeSystem.Ecma.EcmaMethod ecmaMethod)
             {
-                DynamicDependencyAttributeAlgorithm.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaMethod);
+                DynamicDependencyAttributesOnEntityNode.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaMethod);
             }
 
             // Presence of code might trigger the reflectability dependencies.
@@ -752,7 +752,7 @@ namespace ILCompiler
 
             if (writtenField.GetTypicalFieldDefinition() is EcmaField ecmaField)
             {
-                DynamicDependencyAttributeAlgorithm.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaField);
+                DynamicDependencyAttributesOnEntityNode.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaField);
             }
         }
 
index 1c5c06d2c3cb8347fb8e04096aad94686c54c8b7..aedbfc76902ef1a747a98ac9eaf159d01a983e76 100644 (file)
@@ -940,6 +940,9 @@ namespace Internal.IL
             else if (obj is MethodDesc)
             {
                 var method = (MethodDesc)obj;
+
+                _factory.MetadataManager.GetDependenciesDueToAccess(ref _dependencies, _factory, _methodIL, (MethodDesc)_canonMethodIL.GetObject(token));
+
                 if (method.IsRuntimeDeterminedExactMethod)
                 {
                     _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.MethodHandle, method), "ldtoken");
@@ -953,7 +956,9 @@ namespace Internal.IL
             }
             else
             {
-                Debug.Assert(obj is FieldDesc);
+                var field = (FieldDesc)obj;
+
+                _factory.MetadataManager.GetDependenciesDueToAccess(ref _dependencies, _factory, _methodIL, (FieldDesc)_canonMethodIL.GetObject(token));
 
                 // First check if this is a ldtoken Field followed by InitializeArray or CreateSpan.
                 BasicBlock nextBasicBlock = _basicBlocks[_currentOffset];
@@ -971,7 +976,6 @@ namespace Internal.IL
                     }
                 }
 
-                var field = (FieldDesc)obj;
                 if (field.OwningType.IsRuntimeDeterminedSubtype)
                 {
                     _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.FieldHandle, field), "ldtoken");
index 4d1e29a84239ed8bee578ca374a6d4a17d558789..33c4e33bde641b92c20e9351e5d803f070735a25 100644 (file)
     <Compile Include="Compiler\Dataflow\MethodBodyScanner.cs" />
     <Compile Include="Compiler\Dataflow\MethodParameterValue.cs" />
     <Compile Include="Compiler\Dataflow\MethodReturnValue.cs" />
-    <Compile Include="Compiler\Dataflow\Origin.cs" />
     <Compile Include="Compiler\Dataflow\ParameterReferenceValue.cs" />
     <Compile Include="Compiler\Dataflow\ReferenceValue.cs" />
     <Compile Include="Compiler\Dataflow\ReflectionMethodBodyScanner.cs" />
     <Compile Include="Compiler\Dataflow\TrimAnalysisAssignmentPattern.cs" />
     <Compile Include="Compiler\Dataflow\TrimAnalysisMethodCallPattern.cs" />
     <Compile Include="Compiler\Dataflow\TrimAnalysisPatternStore.cs" />
+    <Compile Include="Compiler\Dataflow\TrimAnalysisReflectionAccessPattern.cs" />
     <Compile Include="Compiler\Dataflow\ValueNode.cs" />
     <Compile Include="Compiler\DebugInformationProvider.cs" />
     <Compile Include="Compiler\DependencyAnalysis\CustomAttributeMetadataNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\DataflowAnalyzedMethodNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\DefaultConstructorMapNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\DelegateMarshallingDataNode.cs" />
-    <Compile Include="Compiler\DependencyAnalysis\DynamicDependencyAttributeAlgorithm.cs" />
+    <Compile Include="Compiler\DependencyAnalysis\DynamicDependencyAttributesOnEntityNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\ExternSymbolsImportedNodeProvider.cs" />
     <Compile Include="Compiler\DependencyAnalysis\FieldRvaDataNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\GenericStaticBaseInfoNode.cs" />
index 632959a6d5f4a542edc51707d5c5b066f98098d3..2e239a0a0355a04fe8c972ec1c4d30bd5ae1248a 100644 (file)
@@ -4,6 +4,7 @@
 using System;
 using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
+using System.Linq.Expressions;
 using System.Text;
 using Mono.Linker.Tests.Cases.Expectations.Assertions;
 using Mono.Linker.Tests.Cases.Expectations.Helpers;
@@ -42,6 +43,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow
 
                        WriteArrayField.Test ();
                        AccessReturnedInstanceField.Test ();
+
+                       FieldLdTokenOnGenericType<string>.Test ();
                }
 
                [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
@@ -313,5 +316,27 @@ namespace Mono.Linker.Tests.Cases.DataFlow
                                TestCoalescingAssignment ();
                        }
                }
+
+               /// <summary>
+               /// This doesn't actually test any data flow as such. This is a regression test for a problem found in NativeAOT
+               /// where the combination of a generic type with an ldtoken leads to interesting code paths in the compiler.
+               /// </summary>
+               class FieldLdTokenOnGenericType<T>
+               {
+                       static T FieldOne;
+
+                       static void TestField(T value)
+                       {
+                               FieldOne = value;
+
+                               Expression<Func<T>> e = () => FieldOne;
+                               e.Compile () ();
+                       }
+
+                       public static void Test ()
+                       {
+                               TestField (default (T));
+                       }
+               }
        }
 }
index 230b67dfb5215d8b45e4ab5e194e03b9e8b8fcce..6eb21dceda827482e3020a12644fb6492212afd5 100644 (file)
@@ -174,12 +174,21 @@ namespace Mono.Linker.Tests.Cases.DataFlow
                                i.GetFields (BindingFlags.Instance | BindingFlags.Public);
 
 #if NATIVEAOT
+                               MarkIReflect ();
+#endif
+                       }
+
+#if NATIVEAOT
+                       [UnconditionalSuppressMessage ("test", "IL2111")]
+                       [Kept]
+                       static void MarkIReflect ()
+                       {
                                // In Native AOT the test infra doesn't setup the compiler in a way where it will force preserve
                                // all external types. Like here, it will actually track usage of methods on IReflect
                                // and remove any which are not used. We don't want that for this test.
                                typeof (IReflect).RequiresAll ();
-#endif
                        }
+#endif
                }
        }
 }
index b7e43bb1eaee4356881e12ddcbc3a38abf8d5d54..fb89f21acf2298429fdbc20833bf0a430fe12a3f 100644 (file)
@@ -4,6 +4,7 @@
 using System;
 using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
+using System.Linq.Expressions;
 using System.Text;
 using Mono.Linker.Tests.Cases.Expectations.Assertions;
 using Mono.Linker.Tests.Cases.Expectations.Helpers;
@@ -48,6 +49,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow
 #endif
 
                        WriteCapturedParameter.Test ();
+
+                       MethodLdTokenOnGenericType<string>.Test ();
                }
 
                // Validate the error message when annotated parameter is passed to another annotated parameter
@@ -292,5 +295,26 @@ namespace Mono.Linker.Tests.Cases.DataFlow
                {
                        return null;
                }
+
+               /// <summary>
+               /// This doesn't actually test any data flow as such. This is a regression test for a problem found in NativeAOT
+               /// where the combination of a generic type with an ldtoken leads to interesting code paths in the compiler.
+               /// </summary>
+               class MethodLdTokenOnGenericType<T>
+               {
+                       static T MethodOne() => default (T);
+
+                       static void TestField (T value)
+                       {
+                               Expression<Func<T>> e = () => MethodOne();
+                               e.Compile () ();
+                       }
+
+                       public static void Test ()
+                       {
+                               TestField (default (T));
+                       }
+               }
+
        }
 }
index 25275f426c56bc37fc1991afe8e007d4ea137b28..8e4fc1f914fc594b4512773cf5435bb1b0364355 100644 (file)
@@ -188,8 +188,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                public static void GenericTypeWithStaticMethodWhichRequires () { }
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "--GenericTypeWithStaticMethodWhichRequires--")]
                        [ExpectedWarning ("IL3002", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer)]
                        public static void GenericTypeWithStaticMethodViaLdftn ()
index f6b1d9484c304094e72c9d404243b74e10f22565..1585e53a6a482a374b8b69333636675797d4a518 100644 (file)
@@ -225,7 +225,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                        // NativeAOT should produce diagnostics when using Func
                        // https://github.com/dotnet/runtime/issues/73321
                        [ExpectedWarning ("IL2026", "--PropertyWithLdToken.get--")]
-                       [ExpectedWarning ("IL2026", "--PropertyWithLdToken.get--", ProducedBy = ProducedBy.Trimmer)]
+                       [ExpectedWarning ("IL2026", "--PropertyWithLdToken.get--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
                        [ExpectedWarning ("IL3002", "--PropertyWithLdToken.get--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "--PropertyWithLdToken.get--", ProducedBy = ProducedBy.Analyzer)]
                        public static void Test ()
index f77d373825512ccb3ec43b00beb7f012c5fd94d9..3b408b2404ba1a05d1b7f6d3ddadba2bd44b7184 100644 (file)
@@ -77,8 +77,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                        }
 
 #if !RELEASE
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)]
+                       [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
 #else
                        // In release mode, the compiler optimizes away the unused Action (and reference to MethodWithRequires)
 #endif
@@ -93,8 +92,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                        }
 
                        // Cannot annotate fields either with RUC nor RAF therefore the warning persists
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)]
                        [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        public static Lazy<string> _default = new Lazy<string> (MethodWithRequiresAndReturns);
@@ -161,8 +159,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                        }
 
                        // Cannot annotate fields either with RUC nor RAF therefore the warning persists
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)]
                        [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        public static Lazy<string> _default = new Lazy<string> (MethodWithRequiresAndReturns);
@@ -262,8 +259,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                        }
 
 #if !RELEASE
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)]
+                       [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
 #endif
                        [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
@@ -274,8 +270,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                var action = new Action (MethodWithRequires);
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)]
                        [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        public static Lazy<string> _default = new Lazy<string> (MethodWithRequiresAndReturns);
@@ -339,8 +334,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                        }
 
                        // Cannot annotate fields either with RUC nor RAF therefore the warning persists
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)]
                        [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        public static Lazy<string> _default = new Lazy<string> (MethodWithRequiresAndReturns);
@@ -442,8 +436,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                        }
 
 #if !RELEASE
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Trimmer, CompilerGeneratedCode = true)]
+                       [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
 #endif
                        [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
@@ -455,8 +448,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                var action = new Action (MethodWithRequires);
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)]
                        [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        public static Lazy<string> _default = new Lazy<string> (MethodWithRequiresAndReturns);
@@ -526,8 +518,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                        }
 
                        // Cannot annotate fields either with RUC nor RAF therefore the warning persists
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)]
                        [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        public static Lazy<string> _default = new Lazy<string> (MethodWithRequiresAndReturns);
@@ -675,8 +666,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                LocalFunction ();
 
 #if !RELEASE
-                               // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                               [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
+                               [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
 #endif
                                [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
                                [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
@@ -687,8 +677,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                }
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)]
                        [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        public static Lazy<string> _default = new Lazy<string> (MethodWithRequiresAndReturns);
@@ -791,8 +780,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                }
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)]
                        [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        public static Lazy<string> _default = new Lazy<string> (MethodWithRequiresAndReturns);
@@ -1140,8 +1128,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                lambda ();
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "--LambdaWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "--LambdaWithRequires--")]
                        [ExpectedWarning ("IL3002", "--LambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "--LambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
                        static void TestLambdaWithRequires ()
@@ -1164,8 +1151,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                () => MethodWithRequires ();
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "--LambdaWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "--LambdaWithRequires--")]
                        [ExpectedWarning ("IL3002", "--LambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "--LambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
                        static void TestLambdaWithRequiresUnused ()
@@ -1223,8 +1209,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                        {
                                Action _ =
 #if !RELEASE
-                               // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                               [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
+                               [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
 #endif
                                [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
                                [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
@@ -1234,8 +1219,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                };
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)]
                        [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        public static Lazy<string> _default = new Lazy<string> (MethodWithRequiresAndReturns);
@@ -1338,8 +1322,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                };
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)]
                        [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
                        public static Lazy<string> _default = new Lazy<string> (MethodWithRequiresAndReturns);
@@ -1396,8 +1379,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                };
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026")]
                        [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.Analyzer)]
                        static void TestSuppressionOnLambda ()
@@ -1411,8 +1393,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                lambda (); // This will produce a warning since the lambda has Requires on it
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026")]
                        [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.Analyzer)]
                        static void TestSuppressionOnLambdaWithNestedLambda ()
@@ -2045,8 +2026,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
 
                class LambdasReferencedViaReflection
                {
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "--TestLambdaWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "--TestLambdaWithRequires--")]
                        [ExpectedWarning ("IL3002", "--TestLambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "--TestLambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
                        static void TestLambdaWithRequires ()
@@ -2060,8 +2040,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                                lambda ();
                        }
 
-                       // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
-                       [ExpectedWarning ("IL2026", "Lambda", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+                       [ExpectedWarning ("IL2026", "Lambda")]
                        [ExpectedWarning ("IL3002", "Lambda", ProducedBy = ProducedBy.Analyzer)]
                        [ExpectedWarning ("IL3050", "Lambda", ProducedBy = ProducedBy.Analyzer)]
                        static void TestLambdaWithClosureWithRequires (int p = 0)
index 775b581878b0ee9285e7e1105195c0884a8883aa..d424dd926f9209acb401b4d7d0c5042a975208dc 100644 (file)
@@ -67,7 +67,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
                }
 
                [ExpectedWarning ("IL2026", "--RequiresInDynamicDependency--")]
-               [ExpectedWarning ("IL2026", "--RequiresInDynamicDependency--", ProducedBy = ProducedBy.Trimmer)]
+               [ExpectedWarning ("IL2026", "--RequiresInDynamicDependency--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
                [ExpectedWarning ("IL3002", "--RequiresInDynamicDependency--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
                [ExpectedWarning ("IL3050", "--RequiresInDynamicDependency--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
                [DynamicDependency ("RequiresInDynamicDependency")]