未验证 提交 5bdc36e1 编写于 作者: V Vitek Karas 提交者: GitHub

Implements Requires*Attribute on class behavior for NativeAOT (#83417)

Implements most of the missing pieces to get Requires on class working correctly in NativeAOT.

Major changes:
* Detect Requires mismatch between derived and base class
* Warn on field access if the owning class has Requires
* Changes to reflection marking to warn on more cases (instance methods on Requires classes for example)

Supportive changes:
* The helpers to detect Requires attributes now return the found attribute view out parameter

Fixes #81158

Still two missing pieces - tracked by https://github.com/dotnet/runtime/issues/82447:
* Requires on attributes - NativeAOT doesn't handle this at all yet, part of it is Requires on the attribute class
* Avoid warning when DAM marking an override method which has Requires (or its class has) - this avoids lot of noise, NativeAOT currently generates these warnings in full
上级 2d828299
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Metadata;
using Internal.TypeSystem;
......@@ -37,7 +36,7 @@ internal static string GetGenericParameterDeclaringMemberDisplayName(GenericPara
internal static bool TryGetRequiresAttribute(TypeSystemEntity member, string requiresAttributeName, [NotNullWhen(returnValue: true)] out CustomAttributeValue<TypeDesc>? attribute)
{
attribute = default;
CustomAttributeValue<TypeDesc>? decoded = default;
CustomAttributeValue<TypeDesc>? decoded;
switch (member)
{
case MethodDesc method:
......@@ -59,8 +58,9 @@ internal static bool TryGetRequiresAttribute(TypeSystemEntity member, string req
decoded = @event.GetDecodedCustomAttribute("System.Diagnostics.CodeAnalysis", requiresAttributeName);
break;
default:
Debug.Fail("Trying to operate with unsupported TypeSystemEntity " + member.GetType().ToString());
break;
// This can happen for a compiler generated method, for example if mark methods on array for reflection (through DAM)
// There are several different types which can occur here, but none should ever have any of Requires* attributes.
return false;
}
if (!decoded.HasValue)
return false;
......@@ -92,21 +92,21 @@ internal static string GetRequiresAttributeUrl(CustomAttributeValue<TypeDesc> at
/// <remarks>Unlike <see cref="DoesMemberRequire(TypeSystemEntity, string, out CustomAttributeValue{TypeDesc}?)"/>
/// if a declaring type has Requires, all methods in that type are considered "in scope" of that Requires. So this includes also
/// instance methods (not just statics and .ctors).</remarks>
internal static bool IsInRequiresScope(this MethodDesc method, string requiresAttribute) =>
method.IsInRequiresScope(requiresAttribute, true);
internal static bool IsInRequiresScope(this MethodDesc method, string requiresAttribute)
=> IsInRequiresScope(method, requiresAttribute, out _);
private static bool IsInRequiresScope(this MethodDesc method, string requiresAttribute, bool checkAssociatedSymbol)
internal static bool IsInRequiresScope(this MethodDesc method, string requiresAttribute, [NotNullWhen(returnValue: true)] out CustomAttributeValue<TypeDesc>? attribute)
{
if (method.HasCustomAttribute("System.Diagnostics.CodeAnalysis", requiresAttribute) && !method.IsStaticConstructor)
if (TryGetRequiresAttribute(method, requiresAttribute, out attribute) && !method.IsStaticConstructor)
return true;
if (method.OwningType is TypeDesc type && TryGetRequiresAttribute(type, requiresAttribute, out _))
if (method.OwningType is TypeDesc type && TryGetRequiresAttribute(type, requiresAttribute, out attribute))
return true;
if (checkAssociatedSymbol && method.GetPropertyForAccessor() is PropertyPseudoDesc property && TryGetRequiresAttribute(property, requiresAttribute, out _))
if (method.GetPropertyForAccessor() is PropertyPseudoDesc property && TryGetRequiresAttribute(property, requiresAttribute, out attribute))
return true;
if (checkAssociatedSymbol && method.GetEventForAccessor() is EventPseudoDesc @event && TryGetRequiresAttribute(@event, requiresAttribute, out _))
if (method.GetEventForAccessor() is EventPseudoDesc @event && TryGetRequiresAttribute(@event, requiresAttribute, out attribute))
return true;
return false;
......@@ -153,6 +153,9 @@ internal static bool DoesFieldRequire(this FieldDesc field, string requiresAttri
internal static bool DoesEventRequire(this EventPseudoDesc @event, string requiresAttribute, [NotNullWhen(returnValue: true)] out CustomAttributeValue<TypeDesc>? attribute) =>
TryGetRequiresAttribute(@event, requiresAttribute, out attribute);
internal static bool DoesTypeRequire(this TypeDesc type, string requiresAttribute, [NotNullWhen(returnValue: true)] out CustomAttributeValue<TypeDesc>? attribute) =>
TryGetRequiresAttribute(type, requiresAttribute, out attribute);
/// <summary>
/// Determines if member requires (and thus any usage of such method should be warned about).
/// </summary>
......
......@@ -203,7 +203,11 @@ internal void CheckAndWarnOnReflectionAccess(in MessageOrigin origin, TypeSystem
if (!_enabled)
return;
if (entity.DoesMemberRequire(DiagnosticUtilities.RequiresUnreferencedCodeAttribute, out CustomAttributeValue<TypeDesc>? requiresAttribute))
// Note that we're using `ShouldSuppressAnalysisWarningsForRequires` instead of `DoesMemberRequire`.
// This is because reflection access is actually problematic on all members which are in a "requires" scope
// so for example even instance methods. See for example https://github.com/dotnet/linker/issues/3140 - it's possible
// to call a method on a "null" instance via reflection.
if (_logger.ShouldSuppressAnalysisWarningsForRequires(entity, DiagnosticUtilities.RequiresUnreferencedCodeAttribute, out CustomAttributeValue<TypeDesc>? requiresAttribute))
{
if (_typeHierarchyDataFlowOrigin is not null)
{
......@@ -215,11 +219,11 @@ internal void CheckAndWarnOnReflectionAccess(in MessageOrigin origin, TypeSystem
}
else
{
ReportRequires(origin, entity, DiagnosticUtilities.RequiresUnreferencedCodeAttribute);
ReportRequires(origin, entity, DiagnosticUtilities.RequiresUnreferencedCodeAttribute, requiresAttribute.Value);
}
}
if (entity.DoesMemberRequire(DiagnosticUtilities.RequiresAssemblyFilesAttribute, out _))
if (_logger.ShouldSuppressAnalysisWarningsForRequires(entity, DiagnosticUtilities.RequiresAssemblyFilesAttribute, out requiresAttribute))
{
if (_typeHierarchyDataFlowOrigin is not null)
{
......@@ -229,11 +233,11 @@ internal void CheckAndWarnOnReflectionAccess(in MessageOrigin origin, TypeSystem
}
else
{
ReportRequires(origin, entity, DiagnosticUtilities.RequiresAssemblyFilesAttribute);
ReportRequires(origin, entity, DiagnosticUtilities.RequiresAssemblyFilesAttribute, requiresAttribute.Value);
}
}
if (entity.DoesMemberRequire(DiagnosticUtilities.RequiresDynamicCodeAttribute, out _))
if (_logger.ShouldSuppressAnalysisWarningsForRequires(entity, DiagnosticUtilities.RequiresDynamicCodeAttribute, out requiresAttribute))
{
if (_typeHierarchyDataFlowOrigin is not null)
{
......@@ -243,7 +247,7 @@ internal void CheckAndWarnOnReflectionAccess(in MessageOrigin origin, TypeSystem
}
else
{
ReportRequires(origin, entity, DiagnosticUtilities.RequiresDynamicCodeAttribute);
ReportRequires(origin, entity, DiagnosticUtilities.RequiresDynamicCodeAttribute, requiresAttribute.Value);
}
}
......@@ -277,7 +281,7 @@ internal void CheckAndWarnOnReflectionAccess(in MessageOrigin origin, TypeSystem
}
}
private void ReportRequires(in MessageOrigin origin, TypeSystemEntity entity, string requiresAttributeName)
private void ReportRequires(in MessageOrigin origin, TypeSystemEntity entity, string requiresAttributeName, in CustomAttributeValue<TypeDesc> requiresAttribute)
{
var diagnosticContext = new DiagnosticContext(
origin,
......@@ -286,7 +290,7 @@ private void ReportRequires(in MessageOrigin origin, TypeSystemEntity entity, st
_logger.ShouldSuppressAnalysisWarningsForRequires(origin.MemberDefinition, DiagnosticUtilities.RequiresAssemblyFilesAttribute),
_logger);
ReflectionMethodBodyScanner.CheckAndReportRequires(diagnosticContext, entity, requiresAttributeName);
ReflectionMethodBodyScanner.ReportRequires(diagnosticContext, entity, requiresAttributeName, requiresAttribute);
}
}
}
......@@ -6,6 +6,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection.Metadata;
using ILCompiler.Logging;
using ILLink.Shared;
using ILLink.Shared.TrimAnalysis;
......@@ -61,6 +62,11 @@ internal static void CheckAndReportRequires(in DiagnosticContext diagnosticConte
if (!calledMember.DoesMemberRequire(requiresAttributeName, out var requiresAttribute))
return;
ReportRequires(diagnosticContext, calledMember, requiresAttributeName, requiresAttribute.Value);
}
internal static void ReportRequires(in DiagnosticContext diagnosticContext, TypeSystemEntity calledMember, string requiresAttributeName, in CustomAttributeValue<TypeDesc> requiresAttribute)
{
DiagnosticId diagnosticId = requiresAttributeName switch
{
DiagnosticUtilities.RequiresUnreferencedCodeAttribute => DiagnosticId.RequiresUnreferencedCode,
......@@ -69,8 +75,8 @@ internal static void CheckAndReportRequires(in DiagnosticContext diagnosticConte
_ => throw new NotImplementedException($"{requiresAttributeName} is not a valid supported Requires attribute"),
};
string arg1 = MessageFormat.FormatRequiresAttributeMessageArg(DiagnosticUtilities.GetRequiresAttributeMessage(requiresAttribute.Value));
string arg2 = MessageFormat.FormatRequiresAttributeUrlArg(DiagnosticUtilities.GetRequiresAttributeUrl(requiresAttribute.Value));
string arg1 = MessageFormat.FormatRequiresAttributeMessageArg(DiagnosticUtilities.GetRequiresAttributeMessage(requiresAttribute));
string arg2 = MessageFormat.FormatRequiresAttributeUrlArg(DiagnosticUtilities.GetRequiresAttributeUrl(requiresAttribute));
diagnosticContext.AddDiagnostic(diagnosticId, calledMember.GetDisplayName(), arg1, arg2);
}
......@@ -152,6 +158,11 @@ protected override MultiValue HandleGetField(MethodIL methodBody, int offset, Fi
{
_origin = _origin.WithInstructionOffset(methodBody, offset);
if (field.DoesFieldRequire(DiagnosticUtilities.RequiresUnreferencedCodeAttribute, out _) ||
field.DoesFieldRequire(DiagnosticUtilities.RequiresDynamicCodeAttribute, out _) ||
field.DoesFieldRequire(DiagnosticUtilities.RequiresAssemblyFilesAttribute, out _))
TrimAnalysisPatterns.Add(new TrimAnalysisFieldAccessPattern(field, _origin));
ProcessGenericArgumentDataFlow(field);
return _annotations.GetFieldValue(field);
......@@ -159,8 +170,7 @@ protected override MultiValue HandleGetField(MethodIL methodBody, int offset, Fi
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)
if (targetValue.DynamicallyAccessedMemberTypes != 0)
{
_origin = _origin.WithInstructionOffset(methodBody, offset);
HandleAssignmentPattern(_origin, sourceValue, targetValue, reason);
......
......@@ -52,16 +52,6 @@ public void MarkAndProduceDiagnostics(ReflectionMarker reflectionMarker, Logger
{
foreach (var targetValue in Target)
{
if (targetValue is FieldValue fieldValue)
{
// Once this is removed, please also cleanup ReflectionMethodBodyScanner.HandleStoreValueWithDynamicallyAccessedMembers
// which has to special case FieldValue right now, should not be needed after removal of this
ReflectionMethodBodyScanner.CheckAndReportRequires(diagnosticContext, fieldValue.Field, DiagnosticUtilities.RequiresUnreferencedCodeAttribute);
ReflectionMethodBodyScanner.CheckAndReportRequires(diagnosticContext, fieldValue.Field, DiagnosticUtilities.RequiresDynamicCodeAttribute);
// ?? Should this be enabled (was not so far)
//ReflectionMethodBodyScanner.CheckAndReportRequires(diagnosticContext, fieldValue.Field, DiagnosticUtilities.RequiresAssemblyFilesAttribute);
}
if (targetValue is not ValueWithDynamicallyAccessedMembers targetWithDynamicallyAccessedMembers)
throw new NotImplementedException();
......
// 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 ILLink.Shared.TrimAnalysis;
using Internal.TypeSystem;
namespace ILCompiler.Dataflow
{
public readonly record struct TrimAnalysisFieldAccessPattern
{
public FieldDesc Field { init; get; }
public MessageOrigin Origin { init; get; }
public TrimAnalysisFieldAccessPattern(FieldDesc field, MessageOrigin origin)
{
Field = field;
Origin = origin;
}
// No Merge - there's nothing to merge since this pattern is uniquely identified by both the origin and the entity
// and there's only one way to "access" a field.
public void MarkAndProduceDiagnostics(ReflectionMarker reflectionMarker, Logger logger)
{
var diagnosticContext = new DiagnosticContext(
Origin,
logger.ShouldSuppressAnalysisWarningsForRequires(Origin.MemberDefinition, DiagnosticUtilities.RequiresUnreferencedCodeAttribute),
logger.ShouldSuppressAnalysisWarningsForRequires(Origin.MemberDefinition, DiagnosticUtilities.RequiresDynamicCodeAttribute),
logger.ShouldSuppressAnalysisWarningsForRequires(Origin.MemberDefinition, DiagnosticUtilities.RequiresAssemblyFilesAttribute),
logger);
ReflectionMethodBodyScanner.CheckAndReportRequires(diagnosticContext, Field, DiagnosticUtilities.RequiresUnreferencedCodeAttribute);
ReflectionMethodBodyScanner.CheckAndReportRequires(diagnosticContext, Field, DiagnosticUtilities.RequiresDynamicCodeAttribute);
ReflectionMethodBodyScanner.CheckAndReportRequires(diagnosticContext, Field, DiagnosticUtilities.RequiresAssemblyFilesAttribute);
}
}
}
......@@ -17,6 +17,7 @@ namespace ILCompiler.Dataflow
private readonly Dictionary<MessageOrigin, TrimAnalysisMethodCallPattern> MethodCallPatterns;
private readonly Dictionary<(MessageOrigin, TypeSystemEntity), TrimAnalysisReflectionAccessPattern> ReflectionAccessPatterns;
private readonly Dictionary<(MessageOrigin, TypeSystemEntity), TrimAnalysisGenericInstantiationAccessPattern> GenericInstantiations;
private readonly Dictionary<(MessageOrigin, FieldDesc), TrimAnalysisFieldAccessPattern> FieldAccessPatterns;
private readonly ValueSetLattice<SingleValue> Lattice;
private readonly Logger _logger;
......@@ -26,6 +27,7 @@ public TrimAnalysisPatternStore(ValueSetLattice<SingleValue> lattice, Logger log
MethodCallPatterns = new Dictionary<MessageOrigin, TrimAnalysisMethodCallPattern>();
ReflectionAccessPatterns = new Dictionary<(MessageOrigin, TypeSystemEntity), TrimAnalysisReflectionAccessPattern>();
GenericInstantiations = new Dictionary<(MessageOrigin, TypeSystemEntity), TrimAnalysisGenericInstantiationAccessPattern>();
FieldAccessPatterns = new Dictionary<(MessageOrigin, FieldDesc), TrimAnalysisFieldAccessPattern>();
Lattice = lattice;
_logger = logger;
}
......@@ -74,6 +76,14 @@ public void Add(TrimAnalysisGenericInstantiationAccessPattern pattern)
// and there's only one way to "access" a generic instantiation.
}
public void Add(TrimAnalysisFieldAccessPattern pattern)
{
FieldAccessPatterns.TryAdd((pattern.Origin, pattern.Field), pattern);
// No Merge - there's nothing to merge since this pattern is uniquely identified by both the origin and the entity
// and there's only one way to "access" a field.
}
public void MarkAndProduceDiagnostics(ReflectionMarker reflectionMarker)
{
foreach (var pattern in AssignmentPatterns.Values)
......@@ -87,6 +97,9 @@ public void MarkAndProduceDiagnostics(ReflectionMarker reflectionMarker)
foreach (var pattern in GenericInstantiations.Values)
pattern.MarkAndProduceDiagnostics(reflectionMarker, _logger);
foreach (var pattern in FieldAccessPatterns.Values)
pattern.MarkAndProduceDiagnostics(reflectionMarker, _logger);
}
}
}
......@@ -8,9 +8,10 @@
using ILCompiler.Dataflow;
using ILCompiler.DependencyAnalysisFramework;
using ILCompiler.Logging;
using ILLink.Shared;
using ILLink.Shared.TrimAnalysis;
using ILCompiler.Logging;
namespace ILCompiler.DependencyAnalysis
{
......@@ -26,7 +27,7 @@ public DataflowAnalyzedTypeDefinitionNode(TypeDesc typeDefinition)
public static void GetDependencies(ref DependencyList dependencies, NodeFactory factory, FlowAnnotations flowAnnotations, TypeDesc type)
{
bool foundGenericParameterAnnotation = false;
bool needsDataflowAnalysis = false;
type = type.GetTypeDefinition();
......@@ -34,14 +35,18 @@ public static void GetDependencies(ref DependencyList dependencies, NodeFactory
{
if (type.HasBaseType)
{
foundGenericParameterAnnotation |= GenericArgumentDataFlow.RequiresGenericArgumentDataFlow(flowAnnotations, type.BaseType);
if (type.BaseType.DoesTypeRequire(DiagnosticUtilities.RequiresUnreferencedCodeAttribute, out _) &&
!type.DoesTypeRequire(DiagnosticUtilities.RequiresUnreferencedCodeAttribute, out _))
needsDataflowAnalysis = true;
needsDataflowAnalysis |= GenericArgumentDataFlow.RequiresGenericArgumentDataFlow(flowAnnotations, type.BaseType);
}
if (type is MetadataType metadataType)
{
foreach (var interfaceType in metadataType.ExplicitlyImplementedInterfaces)
{
foundGenericParameterAnnotation |= GenericArgumentDataFlow.RequiresGenericArgumentDataFlow(flowAnnotations, interfaceType);
needsDataflowAnalysis |= GenericArgumentDataFlow.RequiresGenericArgumentDataFlow(flowAnnotations, interfaceType);
}
}
}
......@@ -51,10 +56,10 @@ public static void GetDependencies(ref DependencyList dependencies, NodeFactory
// This likely won't compile either, so we don't care about missing dependencies.
}
if (foundGenericParameterAnnotation)
if (needsDataflowAnalysis)
{
dependencies ??= new DependencyList();
dependencies.Add(factory.DataflowAnalyzedTypeDefinition(type), "Generic parameter dataflow");
dependencies.Add(factory.DataflowAnalyzedTypeDefinition(type), "Dataflow for type definition");
}
}
......@@ -64,6 +69,15 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
if (_typeDefinition.HasBaseType)
{
if (_typeDefinition.BaseType.DoesTypeRequire(DiagnosticUtilities.RequiresUnreferencedCodeAttribute, out var requiresAttribute) &&
!_typeDefinition.DoesTypeRequire(DiagnosticUtilities.RequiresUnreferencedCodeAttribute, out _))
{
UsageBasedMetadataManager metadataManager = (UsageBasedMetadataManager)factory.MetadataManager;
string arg1 = MessageFormat.FormatRequiresAttributeMessageArg(DiagnosticUtilities.GetRequiresAttributeMessage(requiresAttribute.Value));
string arg2 = MessageFormat.FormatRequiresAttributeUrlArg(DiagnosticUtilities.GetRequiresAttributeUrl(requiresAttribute.Value));
metadataManager.Logger.LogWarning(new MessageOrigin(_typeDefinition), DiagnosticId.RequiresUnreferencedCodeOnBaseClass, _typeDefinition.GetDisplayName(), _typeDefinition.BaseType.GetDisplayName(), arg1, arg2);
}
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(ref dependencies, factory, new MessageOrigin(_typeDefinition), _typeDefinition.BaseType, _typeDefinition);
}
......
......@@ -4,15 +4,18 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection.Metadata;
using Internal.TypeSystem;
using Internal.IL;
using ILCompiler.Dataflow;
using ILCompiler.Logging;
using ILLink.Shared;
using MethodIL = Internal.IL.MethodIL;
using Internal.IL;
namespace ILCompiler
{
......@@ -212,17 +215,26 @@ private static string GetModuleFileName(ModuleDesc module)
}
internal bool ShouldSuppressAnalysisWarningsForRequires(TypeSystemEntity originMember, string requiresAttribute)
=> ShouldSuppressAnalysisWarningsForRequires(originMember, requiresAttribute, out _);
internal bool ShouldSuppressAnalysisWarningsForRequires(TypeSystemEntity originMember, string requiresAttribute, [NotNullWhen(returnValue: true)] out CustomAttributeValue<TypeDesc>? attribute)
{
// Check if the current scope method has Requires on it
// since that attribute automatically suppresses all trim analysis warnings.
// Check both the immediate origin method as well as suppression context method
// since that will be different for compiler generated code.
if (originMember is MethodDesc method &&
method.IsInRequiresScope(requiresAttribute))
method.IsInRequiresScope(requiresAttribute, out attribute))
return true;
if (originMember is FieldDesc field)
return field.DoesFieldRequire(requiresAttribute, out attribute);
if (originMember.GetOwningType() == null) // Basically a way to test if the entity is a member (type, method, field, ...)
{
attribute = null;
return false;
}
MethodDesc owningMethod;
if (_compilerGeneratedState != null)
......@@ -230,12 +242,13 @@ internal bool ShouldSuppressAnalysisWarningsForRequires(TypeSystemEntity originM
while (_compilerGeneratedState.TryGetOwningMethodForCompilerGeneratedMember(originMember, out owningMethod))
{
Debug.Assert(owningMethod != originMember);
if (owningMethod.IsInRequiresScope(requiresAttribute))
if (owningMethod.IsInRequiresScope(requiresAttribute, out attribute))
return true;
originMember = owningMethod;
}
}
attribute = null;
return false;
}
}
......
......@@ -379,6 +379,7 @@
<Compile Include="Compiler\Dataflow\RequireDynamicallyAccessedMembersAction.cs" />
<Compile Include="Compiler\Dataflow\ScannerExtensions.cs" />
<Compile Include="Compiler\Dataflow\TrimAnalysisAssignmentPattern.cs" />
<Compile Include="Compiler\Dataflow\TrimAnalysisFieldAccessPattern.cs" />
<Compile Include="Compiler\Dataflow\TrimAnalysisGenericInstantiationAccessPattern.cs" />
<Compile Include="Compiler\Dataflow\TrimAnalysisMethodCallPattern.cs" />
<Compile Include="Compiler\Dataflow\TrimAnalysisPatternStore.cs" />
......
......@@ -1966,7 +1966,7 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in
MarkType (type.BaseType, new DependencyInfo (DependencyKind.BaseType, type));
// The DynamicallyAccessedMembers hiearchy processing must be done after the base type was marked
// The DynamicallyAccessedMembers hierarchy processing must be done after the base type was marked
// (to avoid inconsistencies in the cache), but before anything else as work done below
// might need the results of the processing here.
DynamicallyAccessedMembersTypeHierarchy.ProcessMarkedTypeForDynamicallyAccessedMembersHierarchy (type);
......
......@@ -209,8 +209,7 @@ static void TestDerivedTypeWithOpenGenericOnBaseWithRUCOnBase ()
new DerivedTypeWithOpenGenericOnBaseWithRUCOnBase<TestType> ();
}
// https://github.com/dotnet/runtime/issues/81158
[ExpectedWarning ("IL2109", nameof (BaseTypeWithOpenGenericDAMTAndRUC<T>), ProducedBy = Tool.Trimmer | Tool.Analyzer)]
[ExpectedWarning ("IL2109", nameof (BaseTypeWithOpenGenericDAMTAndRUC<T>))]
[ExpectedWarning ("IL2091", nameof (BaseTypeWithOpenGenericDAMTAndRUC<T>))]
class DerivedTypeWithOpenGenericOnBaseWithRUCOnBase<T> : BaseTypeWithOpenGenericDAMTAndRUC<T>
{
......
......@@ -1899,14 +1899,57 @@ static async void TestAsyncOnlyReferencedViaReflectionWhichShouldWarn ()
[ExpectedWarning ("IL3050", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
// Analyzer doesn't emit additional warnings about reflection access to the compiler-generated
// state machine members.
[ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.Trimmer)]
[ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
// The MoveNext, Current.get and Reset methods produces warning in NativeAOT
// https://github.com/dotnet/runtime/issues/82447
[ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
#if !RELEASE
[ExpectedWarning ("IL2026", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.Trimmer)]
[ExpectedWarning ("IL2026", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
// In debug mode, the async state machine is a class with a constructor, so a warning is emitted for the constructor.
// The MoveNext method is virtual, so doesn't warn either way.
#else
// In release mode, the async state machine is a struct which doesn't have a constructor, so no warning is emitted.
#endif
// The MoveNext method produces warning in NativeAOT
// https://github.com/dotnet/runtime/issues/82447
[ExpectedWarning ("IL2026", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = Tool.NativeAot)]
// ILLink warns about reflection access to compiler-generated state machine members.
// https://github.com/dotnet/runtime/issues/68786
[ExpectedWarning ("IL2118", nameof (StateMachinesOnlyReferencedViaReflection), "<" + nameof (TestAsyncOnlyReferencedViaReflectionWhichShouldWarn) + ">", "MoveNext()",
......@@ -2033,10 +2076,12 @@ void LocalFunction ()
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestLocalFunctionWithClosureWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestLocalFunctionWithClosureWithRequires--", ProducedBy = Tool.NativeAot)]
// BUG: https://github.com/dotnet/runtime/issues/68786
// NativeAot doesn't associate Requires on method with the local functions it contains.
[ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.Trimmer)]
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.Trimmer)]
[ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
// ILLink warn about reflection access to compiler-generated code
// https://github.com/dotnet/runtime/issues/68786
[ExpectedWarning ("IL2118", nameof (LocalFunctionsReferencedViaReflection), nameof (TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection),
......@@ -2066,10 +2111,12 @@ static void TestAll ()
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestLocalFunctionWithClosureWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestLocalFunctionWithClosureWithRequires--", ProducedBy = Tool.NativeAot)]
// BUG: https://github.com/dotnet/runtime/issues/68786
// NativeAot doesn't associate Requires on method with the local functions it contains.
[ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.Trimmer)]
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.Trimmer)]
[ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
// ILLink warn about reflection access to compiler-generated code
// https://github.com/dotnet/runtime/issues/68786
[ExpectedWarning ("IL2118", nameof (LocalFunctionsReferencedViaReflection), "<" + nameof (TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection) + ">",
......@@ -2158,10 +2205,12 @@ static void TestLambdaWithClosureInMethodWithRequires (int p = 0)
[ExpectedWarning ("IL2026", "--TestLambdaWithClosureWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestLambdaWithClosureWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestLambdaWithClosureWithRequires--", ProducedBy = Tool.NativeAot)]
// BUG: https://github.com/dotnet/runtime/issues/68786
// NativeAot doesn't associate Requires on method with the lambdas it contains.
[ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRequires--", ProducedBy = Tool.Trimmer)]
[ExpectedWarning ("IL2026", "--TestLambdaWithClosureInMethodWithRequires--", ProducedBy = Tool.Trimmer)]
[ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestLambdaInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestLambdaInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL2026", "--TestLambdaWithClosureInMethodWithRequires--", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
[ExpectedWarning ("IL3002", "--TestLambdaWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
[ExpectedWarning ("IL3050", "--TestLambdaWithClosureInMethodWithRequires--", ProducedBy = Tool.NativeAot)]
static void TestAll ()
{
typeof (LambdasReferencedViaReflection).RequiresAll ();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册