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.
MetadataType type => type.ContainingType,
PropertyPseudoDesc property => property.OwningType,
EventPseudoDesc @event => @event.OwningType,
+ ModuleDesc => null,
_ => throw new NotImplementedException("Unexpected type system entity")
};
}
{
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);
}
}
}
{
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);
}
}
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)
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();
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,
_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;
}
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
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)
#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)
{
return false;
}
- _reflectionMarker.MarkProperty(_diagnosticContext.Origin, propertyDefinition, _memberWithRequirements);
+ _reflectionMarker.MarkProperty(_diagnosticContext.Origin, propertyDefinition, _reason);
return true;
}
{
if (methodBody.GetObject(reader.ReadILToken()) is MethodDesc methodOperand)
{
+ HandleMethodReflectionAccess(methodBody, offset, methodOperand);
TrackNestedFunctionReference(methodOperand, ref interproceduralState);
}
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:
case ILOpcode.ldind_u2:
case ILOpcode.ldind_u4:
case ILOpcode.ldlen:
- case ILOpcode.ldvirtftn:
case ILOpcode.localloc:
case ILOpcode.refanytype:
case ILOpcode.refanyval:
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)
{
{
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);
}
}
}
}
+ /// <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,
public override DynamicallyAccessedMemberTypes DynamicallyAccessedMemberTypes { get; }
public TypeDesc? StaticType { get; }
-
- internal ParameterOrigin ParameterOrigin => new ParameterOrigin(Parameter.Method.Method, (int)Parameter.Index);
}
}
+++ /dev/null
-// 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();
- }
-}
{
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;
{
// 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;
}
}
- 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)));
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
{
_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);
}
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);
}
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());
}
}
{
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;
}
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)
{
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)
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)
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;
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);
}
}
}
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)
lattice.Meet(Source, other.Source),
lattice.Meet(Target, other.Target),
Origin,
- MemberWithRequirements);
+ Reason);
}
public void MarkAndProduceDiagnostics(ReflectionMarker reflectionMarker, Logger logger)
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);
}
}
using ILCompiler.Logging;
using ILLink.Shared.DataFlow;
using ILLink.Shared.TrimAnalysis;
+using Internal.TypeSystem;
#nullable enable
{
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;
{
AssignmentPatterns = new Dictionary<(MessageOrigin, bool), TrimAnalysisAssignmentPattern>();
MethodCallPatterns = new Dictionary<MessageOrigin, TrimAnalysisMethodCallPattern>();
+ ReflectionAccessPatterns = new Dictionary<(MessageOrigin, TypeSystemEntity), TrimAnalysisReflectionAccessPattern>();
Lattice = lattice;
_logger = logger;
}
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)
foreach (var pattern in MethodCallPatterns.Values)
pattern.MarkAndProduceDiagnostics(reflectionMarker, _logger);
+
+ foreach (var pattern in ReflectionAccessPatterns.Values)
+ pattern.MarkAndProduceDiagnostics(reflectionMarker, _logger);
}
}
}
--- /dev/null
+// 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);
+ }
+ }
+}
+++ /dev/null
-// 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;
- }
- }
- }
- }
-}
--- /dev/null
+// 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;
+ }
+}
if (_field is EcmaField ecmaField)
{
- DynamicDependencyAttributeAlgorithm.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaField);
+ DynamicDependencyAttributesOnEntityNode.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaField);
}
return dependencies;
if (_method is EcmaMethod ecmaMethod)
{
- DynamicDependencyAttributeAlgorithm.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaMethod);
+ DynamicDependencyAttributesOnEntityNode.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaMethod);
}
return dependencies;
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);
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)
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)
{
_ => 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;
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.
if (writtenField.GetTypicalFieldDefinition() is EcmaField ecmaField)
{
- DynamicDependencyAttributeAlgorithm.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaField);
+ DynamicDependencyAttributesOnEntityNode.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaField);
}
}
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");
}
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];
}
}
- var field = (FieldDesc)obj;
if (field.OwningType.IsRuntimeDeterminedSubtype)
{
_dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.FieldHandle, field), "ldtoken");
<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" />
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;
WriteArrayField.Test ();
AccessReturnedInstanceField.Test ();
+
+ FieldLdTokenOnGenericType<string>.Test ();
}
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
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));
+ }
+ }
}
}
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
}
}
}
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;
#endif
WriteCapturedParameter.Test ();
+
+ MethodLdTokenOnGenericType<string>.Test ();
}
// Validate the error message when annotated parameter is passed to another annotated parameter
{
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));
+ }
+ }
+
}
}
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 ()
// 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 ()
}
#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
}
// 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);
}
// 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);
}
#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)]
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);
}
// 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);
}
#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)]
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);
}
// 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);
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)]
}
}
- // 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);
}
}
- // 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);
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 ()
() => 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 ()
{
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)]
};
}
- // 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);
};
}
- // 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);
};
}
- // 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 ()
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 ()
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 ()
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)
}
[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")]