From 9b38f2ab7440b551e294ff43eea20ef8866c931a Mon Sep 17 00:00:00 2001 From: Vitek Karas <10670590+vitek-karas@users.noreply.github.com> Date: Mon, 27 Mar 2023 04:28:03 -0700 Subject: [PATCH] Implement checking for Requires* on attributes for NativeAOT (#83550) Any of the RUC/RDC/RAF attributes can be added to an attribute (either the type or the .ctor or properties). The compiler needs to check for these and produce warnings if such attribute is instantiated somewhere. This was added to "Dataflow" existing class, while it's not exactly data flow, adding a new abstraction didn't seem worth it. Also does a simple dedupe of RUC/RDC/RAF checks in some places. Adapt the tests to the new behavior. The most notable change is that NativeAOT will only look at attributes for reflection enabled members, so had to modify the tests to reflection access basically everything. Use GetDisplayName for anything which is supported by that extension method - this fixes wrong origin printed out for property/event (we would print out 'PropertyPseudoDescriptor'). Mapping IL offset to source file/line number - if the PDB specifies that line as "hidden", then don't use it, instead look for the begining of the method - so first non-hidden sequence point in the method's body. This is a copy of the logic implemented in illink already. --- .../Common/Compiler/DisplayNameHelpers.cs | 3 +- .../Compiler/Dataflow/AttributeDataFlow.cs | 22 +++- .../Dataflow/ReflectionMethodBodyScanner.cs | 11 +- .../TrimAnalysisFieldAccessPattern.cs | 4 +- .../Compiler/Logging/MessageContainer.cs | 6 +- .../Compiler/Logging/MessageOrigin.cs | 30 +++-- .../RequiresCapability/RequiresOnAttribute.cs | 105 ++++++++++++++---- .../RequiresOnAttributeCtor.cs | 8 +- .../RequiresCapability/RequiresOnClass.cs | 18 ++- 9 files changed, 150 insertions(+), 57 deletions(-) diff --git a/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs b/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs index 31ae384844d762..3dac7c151b6fe6 100644 --- a/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs +++ b/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Diagnostics; using System.Text; @@ -23,7 +22,7 @@ public static string GetDisplayName(this TypeSystemEntity entity) PropertyPseudoDesc property => property.GetDisplayName(), EventPseudoDesc @event => @event.GetDisplayName(), #endif - _ => throw new InvalidOperationException(), + _ => null, }; } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/AttributeDataFlow.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/AttributeDataFlow.cs index c37e954d15f8ac..40fe1df4b26a18 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/AttributeDataFlow.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/AttributeDataFlow.cs @@ -28,6 +28,7 @@ public readonly struct AttributeDataFlow private readonly NodeFactory _factory; private readonly FlowAnnotations _annotations; private readonly MessageOrigin _origin; + private readonly DiagnosticContext _diagnosticContext; public AttributeDataFlow(Logger logger, NodeFactory factory, FlowAnnotations annotations, in MessageOrigin origin) { @@ -35,12 +36,21 @@ public AttributeDataFlow(Logger logger, NodeFactory factory, FlowAnnotations ann _factory = factory; _logger = logger; _origin = origin; + + _diagnosticContext = new DiagnosticContext( + _origin, + _logger.ShouldSuppressAnalysisWarningsForRequires(_origin.MemberDefinition, DiagnosticUtilities.RequiresUnreferencedCodeAttribute), + _logger.ShouldSuppressAnalysisWarningsForRequires(_origin.MemberDefinition, DiagnosticUtilities.RequiresDynamicCodeAttribute), + _logger.ShouldSuppressAnalysisWarningsForRequires(_origin.MemberDefinition, DiagnosticUtilities.RequiresAssemblyFilesAttribute), + _logger); } public DependencyList? ProcessAttributeDataflow(MethodDesc method, CustomAttributeValue arguments) { DependencyList? result = null; + ReflectionMethodBodyScanner.CheckAndReportAllRequires(_diagnosticContext, method); + // First do the dataflow for the constructor parameters if necessary. if (_annotations.RequiresDataflowAnalysisDueToSignature(method)) { @@ -62,6 +72,8 @@ public AttributeDataFlow(Logger logger, NodeFactory factory, FlowAnnotations ann FieldDesc field = attributeType.GetField(namedArgument.Name); if (field != null) { + ReflectionMethodBodyScanner.CheckAndReportAllRequires(_diagnosticContext, field); + ProcessAttributeDataflow(field, namedArgument.Value, ref result); } } @@ -72,6 +84,8 @@ public AttributeDataFlow(Logger logger, NodeFactory factory, FlowAnnotations ann MethodDesc setter = property.SetMethod; if (setter != null && setter.Signature.Length > 0 && !setter.Signature.IsStatic) { + ReflectionMethodBodyScanner.CheckAndReportAllRequires(_diagnosticContext, setter); + ProcessAttributeDataflow(setter, ImmutableArray.Create(namedArgument.Value), ref result); } } @@ -88,21 +102,19 @@ private void ProcessAttributeDataflow(MethodDesc method, ImmutableArray if (parameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) { MultiValue value = GetValueForCustomAttributeArgument(arguments[parameter.MetadataIndex]); - var diagnosticContext = new DiagnosticContext(_origin, diagnosticsEnabled: true, _logger); - RequireDynamicallyAccessedMembers(diagnosticContext, value, parameterValue, method.GetDisplayName(), ref result); + RequireDynamicallyAccessedMembers(_diagnosticContext, value, parameterValue, method.GetDisplayName(), ref result); } } } - public void ProcessAttributeDataflow(FieldDesc field, object? value, ref DependencyList? result) + private void ProcessAttributeDataflow(FieldDesc field, object? value, ref DependencyList? result) { var fieldValueCandidate = _annotations.GetFieldValue(field); if (fieldValueCandidate is ValueWithDynamicallyAccessedMembers fieldValue && fieldValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) { MultiValue valueNode = GetValueForCustomAttributeArgument(value); - var diagnosticContext = new DiagnosticContext(_origin, diagnosticsEnabled: true, _logger); - RequireDynamicallyAccessedMembers(diagnosticContext, valueNode, fieldValue, field.GetDisplayName(), ref result); + RequireDynamicallyAccessedMembers(_diagnosticContext, valueNode, fieldValue, field.GetDisplayName(), ref result); } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs index 265d84f375eed5..b0979861ef166a 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs @@ -57,6 +57,13 @@ public static bool RequiresReflectionMethodBodyScannerForAccess(FlowAnnotations field.DoesFieldRequire(DiagnosticUtilities.RequiresDynamicCodeAttribute, out _); } + internal static void CheckAndReportAllRequires(in DiagnosticContext diagnosticContext, TypeSystemEntity calledMember) + { + CheckAndReportRequires(diagnosticContext, calledMember, DiagnosticUtilities.RequiresUnreferencedCodeAttribute); + CheckAndReportRequires(diagnosticContext, calledMember, DiagnosticUtilities.RequiresDynamicCodeAttribute); + CheckAndReportRequires(diagnosticContext, calledMember, DiagnosticUtilities.RequiresAssemblyFilesAttribute); + } + internal static void CheckAndReportRequires(in DiagnosticContext diagnosticContext, TypeSystemEntity calledMember, string requiresAttributeName) { if (!calledMember.DoesMemberRequire(requiresAttributeName, out var requiresAttribute)) @@ -358,9 +365,7 @@ public static bool HandleCall( } } - CheckAndReportRequires(diagnosticContext, calledMethod, DiagnosticUtilities.RequiresUnreferencedCodeAttribute); - CheckAndReportRequires(diagnosticContext, calledMethod, DiagnosticUtilities.RequiresDynamicCodeAttribute); - CheckAndReportRequires(diagnosticContext, calledMethod, DiagnosticUtilities.RequiresAssemblyFilesAttribute); + CheckAndReportAllRequires(diagnosticContext, calledMethod); return handleCallAction.Invoke(calledMethod, instanceValue, argumentValues, intrinsicId, out methodReturnValue); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisFieldAccessPattern.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisFieldAccessPattern.cs index 3b0f976272d2ff..b0ecb0ef0b6d7b 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisFieldAccessPattern.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/TrimAnalysisFieldAccessPattern.cs @@ -30,9 +30,7 @@ public void MarkAndProduceDiagnostics(ReflectionMarker reflectionMarker, Logger 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); + ReflectionMethodBodyScanner.CheckAndReportAllRequires(diagnosticContext, Field); } } } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/MessageContainer.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/MessageContainer.cs index c4cf5c8edba330..0d7f824599a002 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/MessageContainer.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/MessageContainer.cs @@ -300,11 +300,7 @@ public string ToMSBuildString() if (Origin?.MemberDefinition != null) { - if (Origin?.MemberDefinition is MethodDesc method) - sb.Append(method.GetDisplayName()); - else - sb.Append(Origin?.MemberDefinition.ToString()); - + sb.Append(Origin?.MemberDefinition?.GetDisplayName() ?? Origin?.MemberDefinition?.ToString()); sb.Append(": "); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/MessageOrigin.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/MessageOrigin.cs index 5e4b8249928d2d..561efc10390623 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/MessageOrigin.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Logging/MessageOrigin.cs @@ -25,6 +25,8 @@ public struct MessageOrigin : public int? SourceColumn { get; } public int? ILOffset { get; } + private const int HiddenLineNumber = 0xfeefee; + public MessageOrigin(string fileName, int? sourceLine = null, int? sourceColumn = null) { FileName = fileName; @@ -56,9 +58,7 @@ public MessageOrigin(string fileName, int sourceLine, int sourceColumn, ModuleDe public MessageOrigin(MethodIL methodBody, int ilOffset) { - string? document = null; - int? lineNumber = null; - + ILSequencePoint? correspondingSequencePoint = null; IEnumerable? sequencePoints = methodBody.GetDebugInfo()?.GetSequencePoints(); if (sequencePoints != null) { @@ -66,14 +66,30 @@ public MessageOrigin(MethodIL methodBody, int ilOffset) { if (sequencePoint.Offset <= ilOffset) { - document = sequencePoint.Document; - lineNumber = sequencePoint.LineNumber; + correspondingSequencePoint = sequencePoint; + } + } + + // If the warning comes from hidden line (compiler generated code typically) + // search for any sequence point with non-hidden line number and report that as a best effort. + if (correspondingSequencePoint?.LineNumber == HiddenLineNumber) + { + // Reset the information as we don't want to use any of the info in the hidden sequence point + correspondingSequencePoint = null; + foreach (var sequencePoint in sequencePoints) + { + if (sequencePoint.LineNumber != HiddenLineNumber) + { + correspondingSequencePoint = sequencePoint; + break; + } } } + } - FileName = document; + FileName = correspondingSequencePoint?.Document; MemberDefinition = methodBody.OwningMethod; - SourceLine = lineNumber; + SourceLine = correspondingSequencePoint?.LineNumber; SourceColumn = null; ILOffset = ilOffset; } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs index 18fc51fccc5f98..86edad4fa7db7e 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttribute.cs @@ -8,14 +8,19 @@ using System.Text; using System.Threading.Tasks; using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; namespace Mono.Linker.Tests.Cases.RequiresCapability { - [IgnoreTestCase ("Ignore in NativeAOT, see https://github.com/dotnet/runtime/issues/82447", IgnoredBy = Tool.NativeAot)] [SkipKeptItemsValidation] [ExpectedNoWarnings] class RequiresOnAttribute { + // Using these as a simple way to suppress all warning in Main + // it causes lot of warning due to DAM marking everything in the class. + [RequiresUnreferencedCode ("main")] + [RequiresDynamicCode ("main")] + [RequiresAssemblyFiles ("main")] public static void Main () { TestRequiresOnAttributeOnGenericParameter (); @@ -24,7 +29,15 @@ public static void Main () _fieldWithAttributeWhichRequires = 0; PropertyWithAttributeWhichRequires = false; TestMethodWhichRequiresWithAttributeWhichRequires (); + RequiresTriggeredByAttributeUsage.Test (); + + // Accessing the members to test via direct calls/access is not enough + // in NativeAOT custom attributes are only looked at if the member is + // reflection enabled - so there has to be a reflection access to it somewhere. + // On the other hand the analyzer reports RDC/RAF only on direct access. So we need to have "both" + typeof (RequiresOnAttribute).RequiresAll (); } + class AttributeWhichRequiresAttribute : Attribute { [RequiresUnreferencedCode ("Message for --AttributeWhichRequiresAttribute.ctor--")] @@ -52,16 +65,16 @@ public bool PropertyWhichRequires { } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] class GenericTypeWithAttributedParameter<[AttributeWhichRequires] T> { public static void TestMethod () { } } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] static void GenericMethodWithAttributedParameter<[AttributeWhichRequires] T> () { } static void TestRequiresOnAttributeOnGenericParameter () @@ -71,11 +84,11 @@ static void TestRequiresOnAttributeOnGenericParameter () } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] class TypeWithAttributeWhichRequires @@ -83,31 +96,36 @@ class TypeWithAttributeWhichRequires } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static void MethodWithAttributeWhichRequires () { } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static int _fieldWithAttributeWhichRequires; [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer)] + // https://github.com/dotnet/runtime/issues/83581 + [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Trimmer)] // Trimmer can produce duplicate warnings for property access + [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Trimmer)] // Trimmer can produce duplicate warnings for property access + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] - [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Trimmer)] // Trimmer can produce duplicate warnings for property access + [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Trimmer)] // Trimmer can produce duplicate warnings for property access + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static bool PropertyWithAttributeWhichRequires { get; set; } @@ -120,11 +138,52 @@ static void MethodWithAttributeWhichRequires () { } static void MethodWhichRequiresWithAttributeWhichRequires () { } [ExpectedWarning ("IL2026", "--MethodWhichRequiresWithAttributeWhichRequires--")] - [ExpectedWarning ("IL3002", "--MethodWhichRequiresWithAttributeWhichRequires--", ProducedBy = Tool.Analyzer)] - [ExpectedWarning ("IL3050", "--MethodWhichRequiresWithAttributeWhichRequires--", ProducedBy = Tool.Analyzer)] + [ExpectedWarning ("IL3002", "--MethodWhichRequiresWithAttributeWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--MethodWhichRequiresWithAttributeWhichRequires--", ProducedBy = Tool.Analyzer | Tool.NativeAot)] static void TestMethodWhichRequiresWithAttributeWhichRequires () { MethodWhichRequiresWithAttributeWhichRequires (); } + + class RequiresTriggeredByAttributeUsage + { + class AttributeWhichMarksPublicMethods : Attribute + { + public AttributeWhichMarksPublicMethods ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { } + } + + class TypeWithMethodWhichRequires + { + [RequiresUnreferencedCode ("--TypeWithMethodWhichRequires--")] + [RequiresDynamicCode ("--TypeWithMethodWhichRequires--")] + [RequiresAssemblyFiles ("--TypeWithMethodWhichRequires--")] + public void MethodWhichRequires () { } + } + + [ExpectedWarning ("IL2026", "--TypeWithMethodWhichRequires--")] + [ExpectedWarning ("IL3002", "--TypeWithMethodWhichRequires--", ProducedBy = Tool.NativeAot)] + [ExpectedWarning ("IL3050", "--TypeWithMethodWhichRequires--", ProducedBy = Tool.NativeAot)] + [AttributeWhichMarksPublicMethods (typeof(TypeWithMethodWhichRequires))] + static void ShouldWarn() + { + } + + [RequiresUnreferencedCode ("test")] + [RequiresDynamicCode ("test")] + [RequiresAssemblyFiles ("test")] + [AttributeWhichMarksPublicMethods (typeof (TypeWithMethodWhichRequires))] + static void SuppressedDueToRequires() + { + } + + [UnconditionalSuppressMessage("test", "IL2026")] + [UnconditionalSuppressMessage ("test", "IL3002")] + [UnconditionalSuppressMessage ("test", "IL3050")] + public static void Test() + { + ShouldWarn (); + SuppressedDueToRequires (); + } + } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttributeCtor.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttributeCtor.cs index b794c979932cba..2e0c92c8d11fc0 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttributeCtor.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnAttributeCtor.cs @@ -4,20 +4,20 @@ using System; using System.Diagnostics.CodeAnalysis; using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; using Mono.Linker.Tests.Cases.Expectations.Metadata; using Mono.Linker.Tests.Cases.RequiresCapability.Dependencies; namespace Mono.Linker.Tests.Cases.RequiresCapability { - [IgnoreTestCase ("Ignore in NativeAOT, see https://github.com/dotnet/runtime/issues/82447", IgnoredBy = Tool.NativeAot)] [SetupLinkerAction ("link", "test.exe")] [SetupCompileBefore ("RequiresOnAttributeCtor.dll", new[] { "Dependencies/RequiresOnAttributeCtorAttribute.cs" })] [SkipKeptItemsValidation] [ExpectedNoWarnings] public class RequiresOnAttributeCtor { - [ExpectedWarning ("IL2026", "RUC on MethodAnnotatedWithRequires")] - [ExpectedWarning ("IL2026", "RUC on TestTypeWithRequires")] + // Simple way to suppress all warnings in Main + [RequiresUnreferencedCode ("main")] public static void Main () { var type = new Type (); @@ -31,6 +31,8 @@ public static void Main () Type.Interface annotatedInterface = new Type.NestedType (); TestTypeWithRequires (); + + typeof (RequiresOnAttributeCtor).RequiresAll (); } [RequiresUnreferencedCode ("RUC on TestTypeWithRequires")] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs index 822c1a9c129b8b..edad84489b4ecc 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs @@ -1061,11 +1061,18 @@ public int PropertyOnAttribute { } } - // https://github.com/dotnet/runtime/issues/82447 [AttributeWithRequires (PropertyOnAttribute = 42)] - [ExpectedWarning ("IL2026", "AttributeWithRequires.AttributeWithRequires()", ProducedBy = Tool.Trimmer | Tool.Analyzer)] - [ExpectedWarning ("IL3050", "AttributeWithRequires.AttributeWithRequires()", ProducedBy = Tool.Analyzer)] - static void KeepFieldOnAttribute () { } + [ExpectedWarning ("IL2026", "AttributeWithRequires.AttributeWithRequires()")] + [ExpectedWarning ("IL3050", "AttributeWithRequires.AttributeWithRequires()", ProducedBy = Tool.Analyzer | Tool.NativeAot)] + static void KeepFieldOnAttributeInner () { } + + static void KeepFieldOnAttribute () + { + KeepFieldOnAttributeInner (); + + // NativeAOT only considers attribute on reflection visible members + typeof (RequiresOnClass).GetMethod (nameof (KeepFieldOnAttributeInner), BindingFlags.NonPublic | BindingFlags.Static).Invoke (null, new object[] { }); + } public class AttributeParametersAndProperties { @@ -1166,9 +1173,8 @@ public ClassWithWarning () } } - // https://github.com/dotnet/runtime/issues/82447 // NOTE: The enclosing RUC does not apply to nested types. - [ExpectedWarning ("IL2026", "--RequiresOnCtorAttribute--", ProducedBy = Tool.Trimmer | Tool.Analyzer)] + [ExpectedWarning ("IL2026", "--RequiresOnCtorAttribute--")] [RequiresOnCtor] public class ClassWithAttribute {