diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs index d1e870a011654..bbaeff53f0c59 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DataFlow/LocalDataFlowVisitor.cs @@ -560,15 +560,15 @@ public override TValue VisitDelegateCreation (IDelegateCreationOperation operati targetMethodSymbol = lambda.Symbol; break; case IMethodReferenceOperation methodReference: - IMethodSymbol method = methodReference.Method.OriginalDefinition; - if (method.ContainingSymbol is IMethodSymbol) { + IMethodSymbol methodDefinition = methodReference.Method.OriginalDefinition; + if (methodDefinition.ContainingSymbol is IMethodSymbol) { // Track references to local functions - var localFunction = method; + var localFunction = methodDefinition; Debug.Assert (localFunction.MethodKind == MethodKind.LocalFunction); var localFunctionCFG = ControlFlowGraph.GetLocalFunctionControlFlowGraphInScope (localFunction); InterproceduralState.TrackMethod (new MethodBodyValue (localFunction, localFunctionCFG)); } - targetMethodSymbol = method; + targetMethodSymbol = methodReference.Method; break; case IMemberReferenceOperation: case IInvocationOperation: @@ -585,7 +585,7 @@ public override TValue VisitDelegateCreation (IDelegateCreationOperation operati return HandleDelegateCreation (targetMethodSymbol, operation, state.Current.Context); } - public abstract TValue HandleDelegateCreation (IMethodSymbol methodReference, IOperation operation, TContext context); + public abstract TValue HandleDelegateCreation (IMethodSymbol methodReference, IOperation operation, in TContext context); public override TValue VisitPropertyReference (IPropertyReferenceOperation operation, LocalDataFlowState state) { diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs index 231b418f814f7..173bb667a4d17 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs @@ -8,13 +8,9 @@ using System.Diagnostics.CodeAnalysis; using ILLink.RoslynAnalyzer.TrimAnalysis; using ILLink.Shared; -using ILLink.Shared.DataFlow; using ILLink.Shared.TrimAnalysis; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Operations; namespace ILLink.RoslynAnalyzer { @@ -106,85 +102,24 @@ public override void Initialize (AnalysisContext context) // Examine generic instantiations in base types and interface list context.RegisterSymbolAction (context => { var type = (INamedTypeSymbol) context.Symbol; - var location = GetPrimaryLocation (type.Locations); // RUC on type doesn't silence DAM warnings about generic base/interface types. // This knowledge lives in IsInRequiresUnreferencedCodeAttributeScope, // which we still call for consistency here, but it is expected to return false. if (type.IsInRequiresUnreferencedCodeAttributeScope (out _)) return; - if (type.BaseType is INamedTypeSymbol baseType) { - foreach (var diagnostic in ProcessGenericParameters (baseType, location)) - context.ReportDiagnostic (diagnostic); - } - - foreach (var interfaceType in type.Interfaces) { - foreach (var diagnostic in ProcessGenericParameters (interfaceType, location)) - context.ReportDiagnostic (diagnostic); - } - }, SymbolKind.NamedType); - // Examine generic instantiations in method return type and parameters. - // This includes property getters and setters. - context.RegisterSymbolAction (context => { - var method = (IMethodSymbol) context.Symbol; - if (method.IsInRequiresUnreferencedCodeAttributeScope (out _)) - return; - - var returnType = method.ReturnType; - foreach (var diagnostic in ProcessGenericParameters (returnType, GetPrimaryLocation (method.Locations))) - context.ReportDiagnostic (diagnostic); - - foreach (var parameter in method.Parameters) { - foreach (var diagnostic in ProcessGenericParameters (parameter.Type, GetPrimaryLocation (parameter.Locations))) - context.ReportDiagnostic (diagnostic); - } - }, SymbolKind.Method); - // Examine generic instantiations in field type. - context.RegisterSymbolAction (context => { - var field = (IFieldSymbol) context.Symbol; - if (field.IsInRequiresUnreferencedCodeAttributeScope (out _)) - return; - - foreach (var diagnostic in ProcessGenericParameters (field.Type, GetPrimaryLocation (field.Locations))) - context.ReportDiagnostic (diagnostic); - }, SymbolKind.Field); - // Examine generic instantiations in invocations of generically instantiated methods, - // or methods on generically instantiated types. - context.RegisterOperationAction (context => { - if (context.ContainingSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _)) - return; - - var invocation = (IInvocationOperation) context.Operation; - var methodSymbol = invocation.TargetMethod; - foreach (var diagnostic in ProcessMethodGenericParameters (methodSymbol, invocation.Syntax.GetLocation ())) - context.ReportDiagnostic (diagnostic); - }, OperationKind.Invocation); - // Examine generic instantiations in delegate creation of generically instantiated methods. - context.RegisterOperationAction (context => { - if (context.ContainingSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _)) - return; - - var delegateCreation = (IDelegateCreationOperation) context.Operation; - if (delegateCreation.Target is not IMethodReferenceOperation methodReference) - return; + var location = GetPrimaryLocation (type.Locations); + DiagnosticContext diagnosticContext = new (location); - if (methodReference.Method is not IMethodSymbol methodSymbol) - return; - foreach (var diagnostic in ProcessMethodGenericParameters (methodSymbol, delegateCreation.Syntax.GetLocation())) - context.ReportDiagnostic (diagnostic); - }, OperationKind.DelegateCreation); - // Examine generic instantiations in object creation of generically instantiated types. - context.RegisterOperationAction (context => { - if (context.ContainingSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _)) - return; + if (type.BaseType is INamedTypeSymbol baseType) + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, baseType); - var objectCreation = (IObjectCreationOperation) context.Operation; - if (objectCreation.Type is not ITypeSymbol typeSymbol) - return; + foreach (var interfaceType in type.Interfaces) + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, interfaceType); - foreach (var diagnostic in ProcessGenericParameters (typeSymbol, objectCreation.Syntax.GetLocation())) + foreach (var diagnostic in diagnosticContext.Diagnostics) context.ReportDiagnostic (diagnostic); - }, OperationKind.ObjectCreation); + }, SymbolKind.NamedType); context.RegisterSymbolAction (context => { VerifyMemberOnlyApplyToTypesOrStrings (context, context.Symbol); VerifyDamOnPropertyAndAccessorMatch (context, (IMethodSymbol) context.Symbol); @@ -202,66 +137,6 @@ public override void Initialize (AnalysisContext context) }); } - static IEnumerable ProcessMethodGenericParameters (IMethodSymbol methodSymbol, Location location) - { - foreach (var diagnostic in ProcessGenericParameters (methodSymbol, location)) - yield return diagnostic; - - if (methodSymbol.IsStatic && methodSymbol.ContainingType is not null) { - foreach (var diagnostic in ProcessGenericParameters (methodSymbol.ContainingType, location)) - yield return diagnostic; - } - } - - static IEnumerable ProcessGenericParameters (ISymbol symbol, Location location) - { - // Avoid unnecessary execution if not NamedType or Method - if (symbol is not INamedTypeSymbol && symbol is not IMethodSymbol) - yield break; - - ImmutableArray typeParams = default; - ImmutableArray typeArgs = default; - switch (symbol) { - case INamedTypeSymbol type: - typeParams = type.TypeParameters; - typeArgs = type.TypeArguments; - break; - case IMethodSymbol targetMethod: - typeParams = targetMethod.TypeParameters; - typeArgs = targetMethod.TypeArguments; - break; - } - - if (typeParams != null) { - Debug.Assert (typeParams.Length == typeArgs.Length); - - for (int i = 0; i < typeParams.Length; i++) { - // Syntax like typeof (Foo<>) will have an ErrorType as the type argument. - // These uninstantiated generics should not produce warnings. - if (typeArgs[i].Kind == SymbolKind.ErrorType) - continue; - var sourceValue = SingleValueExtensions.FromTypeSymbol (typeArgs[i])!; - var targetValue = new GenericParameterValue (typeParams[i]); - foreach (var diagnostic in GetDynamicallyAccessedMembersDiagnostics (sourceValue, targetValue, location)) - yield return diagnostic; - } - } - } - - static List GetDynamicallyAccessedMembersDiagnostics (SingleValue sourceValue, SingleValue targetValue, Location location) - { - // The target should always be an annotated value, but the visitor design currently prevents - // declaring this in the type system. - if (targetValue is not ValueWithDynamicallyAccessedMembers targetWithDynamicallyAccessedMembers) - throw new NotImplementedException (); - - var diagnosticContext = new DiagnosticContext (location); - var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (diagnosticContext, default (ReflectionAccessAnalyzer)); - requireDynamicallyAccessedMembersAction.Invoke (sourceValue, targetWithDynamicallyAccessedMembers); - - return diagnosticContext.Diagnostics; - } - static void VerifyMemberOnlyApplyToTypesOrStrings (SymbolAnalysisContext context, ISymbol member) { var location = GetPrimaryLocation (member.Locations); diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs new file mode 100644 index 0000000000000..6ef16f07a9c0b --- /dev/null +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs @@ -0,0 +1,105 @@ +// 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.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; +using ILLink.Shared.DataFlow; +using ILLink.Shared.TrimAnalysis; +using ILLink.Shared.TypeSystemProxy; + +namespace ILLink.RoslynAnalyzer.TrimAnalysis +{ + internal static class GenericArgumentDataFlow + { + public static void ProcessGenericArgumentDataFlow (DiagnosticContext diagnosticContext, INamedTypeSymbol type) + { + ProcessGenericArgumentDataFlow (diagnosticContext, type.TypeArguments, type.TypeParameters); + } + + public static void ProcessGenericArgumentDataFlow (DiagnosticContext diagnosticContext, IMethodSymbol method) + { + ProcessGenericArgumentDataFlow (diagnosticContext, method.TypeArguments, method.TypeParameters); + + ProcessGenericArgumentDataFlow (diagnosticContext, method.ContainingType); + } + + public static void ProcessGenericArgumentDataFlow (DiagnosticContext diagnosticContext, IFieldSymbol field) + { + ProcessGenericArgumentDataFlow (diagnosticContext, field.ContainingType); + } + + static void ProcessGenericArgumentDataFlow ( + DiagnosticContext diagnosticContext, + ImmutableArray typeArguments, + ImmutableArray typeParameters) + { + for (int i = 0; i < typeArguments.Length; i++) { + var typeArgument = typeArguments[i]; + // Apply annotations to the generic argument + var genericParameterValue = new GenericParameterValue (typeParameters[i]); + if (genericParameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) { + SingleValue genericArgumentValue = SingleValueExtensions.FromTypeSymbol (typeArgument)!; + var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (diagnosticContext, default (ReflectionAccessAnalyzer)); + requireDynamicallyAccessedMembersAction.Invoke (genericArgumentValue, genericParameterValue); + } + + // Recursively process generic argument data flow on the generic argument if it itself is generic + if (typeArgument is INamedTypeSymbol namedTypeArgument && namedTypeArgument.IsGenericType) { + ProcessGenericArgumentDataFlow (diagnosticContext, namedTypeArgument); + } + } + } + + public static bool RequiresGenericArgumentDataFlow (INamedTypeSymbol type) + { + if (type.IsGenericType) { + if (RequiresGenericArgumentDataFlow (type.TypeParameters)) + return true; + + foreach (var typeArgument in type.TypeArguments) { + if (typeArgument is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.IsGenericType + && RequiresGenericArgumentDataFlow (namedTypeSymbol)) + return true; + } + } + + return false; + } + + public static bool RequiresGenericArgumentDataFlow (IMethodSymbol method) + { + if (method.IsGenericMethod) { + if (RequiresGenericArgumentDataFlow (method.TypeParameters)) + return true; + + foreach (var typeArgument in method.TypeArguments) { + if (typeArgument is INamedTypeSymbol namedTypeSymbol && namedTypeSymbol.IsGenericType + && RequiresGenericArgumentDataFlow (namedTypeSymbol)) + return true; + } + } + + return RequiresGenericArgumentDataFlow (method.ContainingType); + } + + public static bool RequiresGenericArgumentDataFlow (IFieldSymbol field) + { + return RequiresGenericArgumentDataFlow (field.ContainingType); + } + + static bool RequiresGenericArgumentDataFlow (ImmutableArray typeParameters) + { + foreach (var typeParameter in typeParameters) { + var genericParameterValue = new GenericParameterValue (typeParameter); + if (genericParameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) + return true; + } + + return false; + } + } +} diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisGenericInstantiationPattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisGenericInstantiationPattern.cs new file mode 100644 index 0000000000000..8d484e66036b9 --- /dev/null +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisGenericInstantiationPattern.cs @@ -0,0 +1,70 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Diagnostics; +using ILLink.RoslynAnalyzer.DataFlow; +using ILLink.Shared.TrimAnalysis; +using Microsoft.CodeAnalysis; + +namespace ILLink.RoslynAnalyzer.TrimAnalysis +{ + public readonly record struct TrimAnalysisGenericInstantiationPattern + { + public ISymbol GenericInstantiation { get; init; } + public IOperation Operation { get; init; } + public ISymbol OwningSymbol { get; init; } + public FeatureContext FeatureContext { get; init; } + + public TrimAnalysisGenericInstantiationPattern ( + ISymbol genericInstantiation, + IOperation operation, + ISymbol owningSymbol, + FeatureContext featureContext) + { + GenericInstantiation = genericInstantiation; + Operation = operation; + OwningSymbol = owningSymbol; + FeatureContext = featureContext.DeepCopy (); + } + + public TrimAnalysisGenericInstantiationPattern Merge ( + FeatureContextLattice featureContextLattice, + TrimAnalysisGenericInstantiationPattern other) + { + Debug.Assert (Operation == other.Operation); + Debug.Assert (SymbolEqualityComparer.Default.Equals (GenericInstantiation, other.GenericInstantiation)); + Debug.Assert (SymbolEqualityComparer.Default.Equals (OwningSymbol, other.OwningSymbol)); + + return new TrimAnalysisGenericInstantiationPattern ( + GenericInstantiation, + Operation, + OwningSymbol, + featureContextLattice.Meet (FeatureContext, other.FeatureContext)); + } + + public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext context) + { + DiagnosticContext diagnosticContext = new (Operation.Syntax.GetLocation ()); + if (context.EnableTrimAnalyzer && + !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) && + !FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.UnreferencedCode)) { + switch (GenericInstantiation) { + case INamedTypeSymbol type: + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, type); + break; + + case IMethodSymbol method: + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, method); + break; + + case IFieldSymbol field: + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (diagnosticContext, field); + break; + } + } + + return diagnosticContext.Diagnostics; + } + } +} diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisPatternStore.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisPatternStore.cs index d957ec61ad63c..78de8fdf4235c 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisPatternStore.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisPatternStore.cs @@ -14,6 +14,7 @@ public readonly struct TrimAnalysisPatternStore { readonly Dictionary<(IOperation, bool), TrimAnalysisAssignmentPattern> AssignmentPatterns; readonly Dictionary FieldAccessPatterns; + readonly Dictionary GenericInstantiationPatterns; readonly Dictionary MethodCallPatterns; readonly Dictionary ReflectionAccessPatterns; readonly ValueSetLattice Lattice; @@ -23,6 +24,7 @@ public TrimAnalysisPatternStore (ValueSetLattice lattice, FeatureCo { AssignmentPatterns = new Dictionary<(IOperation, bool), TrimAnalysisAssignmentPattern> (); FieldAccessPatterns = new Dictionary (); + GenericInstantiationPatterns = new Dictionary (); MethodCallPatterns = new Dictionary (); ReflectionAccessPatterns = new Dictionary (); Lattice = lattice; @@ -57,6 +59,16 @@ public void Add (TrimAnalysisFieldAccessPattern pattern) FieldAccessPatterns[pattern.Operation] = pattern.Merge (Lattice, FeatureContextLattice, existingPattern); } + public void Add (TrimAnalysisGenericInstantiationPattern pattern) + { + if (!GenericInstantiationPatterns.TryGetValue (pattern.Operation, out var existingPattern)) { + GenericInstantiationPatterns.Add (pattern.Operation, pattern); + return; + } + + GenericInstantiationPatterns[pattern.Operation] = pattern.Merge (FeatureContextLattice, existingPattern); + } + public void Add (TrimAnalysisMethodCallPattern pattern) { if (!MethodCallPatterns.TryGetValue (pattern.Operation, out var existingPattern)) { @@ -89,6 +101,11 @@ public IEnumerable CollectDiagnostics (DataFlowAnalyzerContext conte yield return diagnostic; } + foreach (var genericInstantiationPattern in GenericInstantiationPatterns.Values) { + foreach (var diagnostic in genericInstantiationPattern.CollectDiagnostics (context)) + yield return diagnostic; + } + foreach (var methodCallPattern in MethodCallPatterns.Values) { foreach (var diagnostic in methodCallPattern.CollectDiagnostics (context)) yield return diagnostic; diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs index 22459c17ad267..6f118ac8c4792 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using ILLink.RoslynAnalyzer.DataFlow; +using ILLink.RoslynAnalyzer.TrimAnalysis; using ILLink.Shared.DataFlow; using ILLink.Shared.TrimAnalysis; using ILLink.Shared.TypeSystemProxy; @@ -214,6 +215,8 @@ public override MultiValue GetFieldTargetValue (IFieldSymbol field, IFieldRefere new TrimAnalysisFieldAccessPattern (field, fieldReferenceOperation, OwningSymbol, featureContext) ); + ProcessGenericArgumentDataFlow (field, fieldReferenceOperation, featureContext); + return new FieldValue (field); } @@ -296,6 +299,8 @@ public override MultiValue HandleMethodCall ( OwningSymbol, featureContext)); + ProcessGenericArgumentDataFlow (calledMethod, operation, featureContext); + foreach (var argument in arguments) { foreach (var argumentValue in argument.AsEnumerable ()) { if (argumentValue is ArrayValue arrayValue) @@ -421,7 +426,7 @@ public override void HandleReturnValue (MultiValue returnValue, IOperation opera } } - public override MultiValue HandleDelegateCreation (IMethodSymbol method, IOperation operation, FeatureContext featureContext) + public override MultiValue HandleDelegateCreation (IMethodSymbol method, IOperation operation, in FeatureContext featureContext) { TrimAnalysisPatterns.Add (new TrimAnalysisReflectionAccessPattern ( method, @@ -430,9 +435,44 @@ public override MultiValue HandleDelegateCreation (IMethodSymbol method, IOperat featureContext )); + ProcessGenericArgumentDataFlow (method, operation, featureContext); + return TopValue; } + private void ProcessGenericArgumentDataFlow (IMethodSymbol method, IOperation operation, in FeatureContext featureContext) + { + // We only need to validate static methods and then all generic methods + // Instance non-generic methods don't need validation because the creation of the instance + // is the place where the validation will happen. + if (!method.IsStatic && !method.IsGenericMethod && !method.IsConstructor ()) + return; + + if (GenericArgumentDataFlow.RequiresGenericArgumentDataFlow (method)) { + TrimAnalysisPatterns.Add (new TrimAnalysisGenericInstantiationPattern ( + method, + operation, + OwningSymbol, + featureContext)); + } + } + + private void ProcessGenericArgumentDataFlow (IFieldSymbol field, IOperation operation, in FeatureContext featureContext) + { + // We only need to validate static field accesses, instance field accesses don't need generic parameter validation + // because the create of the instance would do that instead. + if (!field.IsStatic) + return; + + if (GenericArgumentDataFlow.RequiresGenericArgumentDataFlow (field)) { + TrimAnalysisPatterns.Add (new TrimAnalysisGenericInstantiationPattern ( + field, + operation, + OwningSymbol, + featureContext)); + } + } + static bool TryGetConstantValue (IOperation operation, out MultiValue constValue) { if (operation.ConstantValue.HasValue) { diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs index 3194dde84bda5..a06c8115c3158 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersAnalyzerTests.cs @@ -1407,7 +1407,6 @@ public Task AssignmentTargetHasNestedInvalidOperation () public Task CRefGenericParameterAnalysis () { var Source = """ - using System; using System.Diagnostics.CodeAnalysis; class C @@ -1417,16 +1416,16 @@ class C /// /// /// - static CRequires Value => throw new Exception(); + static CRequires Value => new CRequires (); } class CRequires<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] TInner> { public static bool IsIt => false; } """; - // The actual usage (return value) should warn, about missing annotation, but the cref should not. + // The actual usage (ctor call) should warn, about missing annotation, but the cref should not. return VerifyDynamicallyAccessedMembersAnalyzer (Source, consoleApplication: false, - // (11,9): warning IL2091: 'TInner' generic argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in 'CRequires'. The generic parameter 'TOuter' of 'C' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. - VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter).WithSpan (11, 36, 11, 57).WithSpan (4, 9, 4, 15).WithArguments ("TInner", "CRequires", "TOuter", "C", "'DynamicallyAccessedMemberTypes.PublicMethods'")); + // (10,36): warning IL2091: 'TInner' generic argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicMethods' in 'CRequires'. The generic parameter 'TOuter' of 'C' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. + VerifyCS.Diagnostic (DiagnosticId.DynamicallyAccessedMembersMismatchTypeArgumentTargetsGenericParameter).WithSpan (10, 36, 10, 60).WithSpan (3, 9, 3, 15).WithArguments ("TInner", "CRequires", "TOuter", "C", "'DynamicallyAccessedMemberTypes.PublicMethods'")); } [Fact] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedTypes.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedTypes.cs index 324e2cbb505f3..c9cc432c84660 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedTypes.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedTypes.cs @@ -361,9 +361,7 @@ public static class Container<[DynamicallyAccessedMembers (DynamicallyAccessedMe (Func x) => v => x(v); } - [ExpectedWarning ("IL2091", "T", nameof (Container), nameof (DynamicallyAccessedMemberTypes.PublicMethods), - // https://github.com/dotnet/runtime/issues/84918 - ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", "T", nameof (Container), nameof (DynamicallyAccessedMemberTypes.PublicMethods))] public static void Test () { Container.NestedLambda ((T t) => t) (default (T)); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs index 669b40c5beebb..29f18ea706389 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs @@ -673,8 +673,6 @@ static void FieldAccess () } } - // TODO: move generic analysis to dataflow analyzer to support this if it is an actual scenario. - [ExpectedWarning ("IL2091", nameof (RequiresAllGeneric), ProducedBy = Tool.Analyzer)] static void GenericRequirement () { if (TestFeatures.IsUnreferencedCodeSupported) { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs index a030aa31f6564..fb4088a0e27f4 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs @@ -8,10 +8,10 @@ namespace Mono.Linker.Tests.Cases.DataFlow { - // NativeAOT differences in behavior: + // NativeAOT/analyzer differences in behavior compared to ILLink: // // See the description on top of GenericParameterWarningLocation for the expected differences in behavior - // for NativeAOT. + // for NativeAOT and the analyzer. // The tests affected by this are marked with "NativeAOT_StorageSpaceType" // @@ -202,7 +202,7 @@ class DerivedTypeWithInstantiationOverSelfOnBase : GenericBaseTypeWithRequiremen class DerivedTypeWithOpenGenericOnBase : GenericBaseTypeWithRequirements { // Analyzer does not see the base class constructor - [ExpectedWarning ("IL2091", nameof (GenericBaseTypeWithRequirements), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", nameof (GenericBaseTypeWithRequirements))] public DerivedTypeWithOpenGenericOnBase () { } } @@ -216,7 +216,7 @@ static void TestDerivedTypeWithOpenGenericOnBaseWithRUCOnBase () [ExpectedWarning ("IL2091", nameof (IGenericInterfaceTypeWithRequirements))] class DerivedTypeWithOpenGenericOnBaseWithRUCOnBase : BaseTypeWithOpenGenericDAMTAndRUC, IGenericInterfaceTypeWithRequirements { - [ExpectedWarning ("IL2091", nameof (DerivedTypeWithOpenGenericOnBaseWithRUCOnBase), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", nameof (DerivedTypeWithOpenGenericOnBaseWithRUCOnBase))] [ExpectedWarning ("IL2026", nameof (BaseTypeWithOpenGenericDAMTAndRUC))] public DerivedTypeWithOpenGenericOnBaseWithRUCOnBase () { } } @@ -406,7 +406,7 @@ class TypeGenericRequirementsOnMembers<[DynamicallyAccessedMembers (DynamicallyA { public TypeRequiresPublicFields PublicFieldsField; - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType public TypeRequiresPublicMethods PublicMethodsField; public TypeRequiresPublicFields PublicFieldsProperty { @@ -415,23 +415,23 @@ public TypeRequiresPublicFields PublicFieldsProperty { } public TypeRequiresPublicMethods PublicMethodsProperty { - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType get => null; - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType set { } } - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.Analyzer, CompilerGeneratedCode = true)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer, CompilerGeneratedCode = true)] // NativeAOT_StorageSpaceType public TypeRequiresPublicMethods PublicMethodsImplicitGetter => null; public void PublicFieldsMethodParameter (TypeRequiresPublicFields param) { } - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType public void PublicMethodsMethodParameter (TypeRequiresPublicMethods param) { } public TypeRequiresPublicFields PublicFieldsMethodReturnValue () { return null; } [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeRequiresPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType public TypeRequiresPublicMethods PublicMethodsMethodReturnValue () { return null; } public void PublicFieldsMethodLocalVariable () @@ -475,8 +475,7 @@ class FullyInstantiatedOverPartiallyInstantiatedFields class PartialyInstantiatedMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TOuter> : BaseForPartialInstantiation { - // Analyzer does not see the base class constructor - [ExpectedWarning ("IL2091", nameof (BaseForPartialInstantiation), "'TMethods'", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", nameof (BaseForPartialInstantiation), "'TMethods'")] public PartialyInstantiatedMethods () { } } @@ -829,9 +828,9 @@ static void TestNoWarningsInRUCMethod () [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields")] // RUCTypeRequiresPublicFields ctor [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields", ProducedBy = Tool.Trimmer)] // RUCTypeRequiresPublicFields local, // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields", ProducedBy = Tool.Trimmer)] // InstanceMethod, // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // InstanceMethodRequiresPublicMethods + [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields")] // InstanceMethodRequiresPublicMethods [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields", ProducedBy = Tool.Trimmer)] // VirtualMethod, // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // VirtualMethodRequiresPublicMethods + [ExpectedWarning ("IL2091", "RUCTypeRequiresPublicFields")] // VirtualMethodRequiresPublicMethods static void TestNoWarningsInRUCType () { RUCTypeRequiresPublicFields.StaticMethod (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterWarningLocation.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterWarningLocation.cs index 84e558af20072..d4acbe6a90ed4 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterWarningLocation.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterWarningLocation.cs @@ -9,7 +9,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow { - // NativeAOT differences in behavior: + // NativeAOT/analyzer differences in behavior compared to ILLink: // // Validation of generic parameters only matters if the instantiation can be used to run code with the substituted type. // So for generic methods the validation has to happen basically always (since any access to the method can lead to the code @@ -17,11 +17,11 @@ namespace Mono.Linker.Tests.Cases.DataFlow // For generic types though the situation is different. Code on the type can only run if the type is instantiated (new) // or if static members are accessed on it (method calls, or fields accesses both can lead to static .cctor execution). // Others usages of the type cannot themselves lead to code execution in the type, and thus don't need to be validated. - // Currently linker and analyzer both validate every time there's a type occurrence in the code. - // NativeAOT on the other hand only validates the cases which can lead to code execution (this is partially because the compiler - // doesn't care about the type in other situations really). + // Currently linker validates every time there's a type occurrence in the code. + // NativeAOT and the analyzer on the other hand only validate the cases which can lead to code execution (this is partially + // because the compiler doesn't care about the type in other situations really). // So for example local variables of a given type, or method parameters of that type alone will not cause code execution - // inside that type and thus won't be validated by NativeAOT compiler. + // inside that type and thus won't be validated by NativeAOT compiler or the analyzer. // // Below this explanation/fact is referred to as "NativeAOT_StorageSpaceType" // Storage space - declaring a storage space as having a specific type doesn't in itself do anything with that type as per @@ -72,7 +72,7 @@ class DerivedWithMatchingAnnotation<[DynamicallyAccessedMembers (DynamicallyAcce class DerivedWithNoAnnotations : BaseWithPublicMethods { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] // Compiler generates an implicit call to BaseWithPublicMethods..ctor + [ExpectedWarning ("IL2091")] // Compiler generates an implicit call to BaseWithPublicMethods..ctor. Also visible in analyzer CFG. public DerivedWithNoAnnotations () { } } @@ -190,11 +190,11 @@ interface IWithTwo< static void MethodWithSpecificType (TypeWithPublicMethods one, IWithTwo two) { } - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void MethodWithOneMismatch (TypeWithPublicMethods one) { } - [ExpectedWarning ("IL2091", nameof (IWithTwo), ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", nameof (TypeWithPublicMethods), ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (IWithTwo), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", nameof (TypeWithPublicMethods), ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void MethodWithTwoMismatches< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -205,11 +205,11 @@ static void MethodWithTwoMismatches< static TypeWithPublicMethods MethodWithMatchingReturn<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> () => null; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static TypeWithPublicMethods MethodWithOneMismatchReturn () => null; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static IWithTwo MethodWithTwoMismatchesInReturn< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -217,7 +217,7 @@ static IWithTwo MethodWithTwoMismatchesInReturn< class ConstructorWithOneMatchAndOneMismatch<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TMethods> { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType public ConstructorWithOneMatchAndOneMismatch (IWithTwo two) { } } @@ -236,6 +236,10 @@ public static void Test () } } + // NativeAot warns for members accessed by reflection as a workaround for an incorrect suppression + // in DI: https://github.com/dotnet/runtime/issues/81358 + // ILLink doesn't differentiate between reflection and non-reflection access, so it warns in both cases. + // Analyzer doesn't implement the workaround, so it warns in neither case. class MethodParametersAndReturnAccessedViaReflection { class TypeWithPublicMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -248,11 +252,11 @@ interface IWithTwo< static void MethodWithSpecificType (TypeWithPublicMethods one, IWithTwo two) { } - [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091", ProducedBy = Tool.NativeAot | Tool.Trimmer)] static void MethodWithOneMismatch (TypeWithPublicMethods one) { } - [ExpectedWarning ("IL2091", nameof (IWithTwo))] - [ExpectedWarning ("IL2091", nameof (TypeWithPublicMethods))] + [ExpectedWarning ("IL2091", nameof (IWithTwo), ProducedBy = Tool.NativeAot | Tool.Trimmer)] + [ExpectedWarning ("IL2091", nameof (TypeWithPublicMethods), ProducedBy = Tool.NativeAot | Tool.Trimmer)] static void MethodWithTwoMismatches< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -263,11 +267,11 @@ static void MethodWithTwoMismatches< static TypeWithPublicMethods MethodWithMatchingReturn<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> () => null; - [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091", ProducedBy = Tool.NativeAot | Tool.Trimmer)] static TypeWithPublicMethods MethodWithOneMismatchReturn () => null; - [ExpectedWarning ("IL2091")] - [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091", ProducedBy = Tool.NativeAot | Tool.Trimmer)] + [ExpectedWarning ("IL2091", ProducedBy = Tool.NativeAot | Tool.Trimmer)] static IWithTwo MethodWithTwoMismatchesInReturn< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -275,7 +279,7 @@ static IWithTwo MethodWithTwoMismatchesInReturn< class ConstructorWithOneMatchAndOneMismatch<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TMethods> { - [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091", ProducedBy = Tool.NativeAot | Tool.Trimmer)] public ConstructorWithOneMatchAndOneMismatch (IWithTwo two) { } } @@ -321,10 +325,10 @@ public static void Test () class MultipleReferencesToTheSameType<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static TypeWithPublicMethods _field1; static TypeWithPublicMethods _field2; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static TypeWithPublicMethods _field3; public static void Test () @@ -339,8 +343,8 @@ class TwoMismatchesInOne< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields> { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static IWithTwo _field; public static void Test () @@ -358,6 +362,10 @@ public static void Test () } } + // NativeAot warns for members accessed by reflection as a workaround for an incorrect suppression + // in DI: https://github.com/dotnet/runtime/issues/81358 + // ILLink doesn't differentiate between reflection and non-reflection access, so it warns in both cases. + // Analyzer doesn't implement the workaround, so it warns in neither case. class FieldDefinitionViaReflection { class TypeWithPublicMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -380,10 +388,10 @@ class OneMatchingAnnotation<[DynamicallyAccessedMembers (DynamicallyAccessedMemb class MultipleReferencesToTheSameType<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> { - [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] static TypeWithPublicMethods _field1; static TypeWithPublicMethods _field2; - [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] static TypeWithPublicMethods _field3; } @@ -391,8 +399,8 @@ class TwoMismatchesInOne< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields> { - [ExpectedWarning ("IL2091")] - [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] static IWithTwo _field; } @@ -444,10 +452,10 @@ class MultipleReferencesToTheSameType<[DynamicallyAccessedMembers (DynamicallyAc // The warning is generated on the backing field [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static TypeWithPublicMethods Property1 { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType get; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType set; } @@ -459,10 +467,10 @@ static TypeWithPublicMethods Property2 { // The warning is generated on the backing field [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static TypeWithPublicMethods Property3 { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType get; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType set; } @@ -479,14 +487,14 @@ class TwoMismatchesInOne< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields> { // The warnings are generated on the backing field - [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static IWithTwo Property { // Getter is trimmed and doesn't produce any warning get; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType set; } @@ -546,7 +554,7 @@ static void MethodWithTwo< static MethodBody GetInstance () => null; - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.Analyzer)] // return type // NativeAOT_StorageSpaceType + [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // return type // NativeAOT_StorageSpaceType static TypeWithPublicMethods GetInstanceForTypeWithPublicMethods () => null; class TypeOf @@ -569,7 +577,7 @@ static void SpecificType () Type t = typeof (TypeWithPublicMethods); } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 + // Analyzer doesn't warn on typeof [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] static void MultipleReferencesToTheSameType< @@ -581,7 +589,7 @@ static void MultipleReferencesToTheSameType< t = typeof (TypeWithPublicMethods); // Warn } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 + // Analyzer doesn't warn on typeof [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] static void TwoMismatchesInOneStatement< @@ -686,7 +694,6 @@ static void TwoMismatchesInOneStatement< IWithTwo.Method (); } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // local variable // NativeAOT_StorageSpaceType static void InstanceMethodMismatch () @@ -718,9 +725,8 @@ static void SpecificType () _ = TypeWithPublicMethods.Field; } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091")] static void MultipleReferencesToTheSameField< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods, TUnknown> () @@ -730,9 +736,8 @@ static void MultipleReferencesToTheSameField< TypeWithPublicMethods.Field = ""; // Warn } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091")] static void TwoMismatchesInOneStatement< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] TPublicFields, [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> @@ -741,8 +746,6 @@ static void TwoMismatchesInOneStatement< _ = IWithTwo.Field; } - // The local variable - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // access to the field // NativeAOT_StorageSpaceType static void InstanceFieldMismatch () @@ -776,7 +779,6 @@ static void SpecificType () TypeWithPublicMethods t = null; } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void MultipleReferencesToTheSameType< @@ -788,7 +790,6 @@ static void MultipleReferencesToTheSameType< TypeWithPublicMethods t3 = null; // Warn } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void TwoMismatchesInOneStatement< @@ -1000,13 +1001,12 @@ static void SpecificType () Expression> a = () => TypeWithPublicMethods.Field; } + [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091")] // There are two warnings per "callsite" in this case because the generated IL does // ldtoken field // ldtoken owningtype // In order to call the right Expression APIs. - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] static void MultipleReferencesToTheSameField< @@ -1018,13 +1018,12 @@ static void MultipleReferencesToTheSameField< a = () => TypeWithPublicMethods.Field; // Warn } + [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091")] // There are two warnings per "callsite" in this case because the generated IL does // ldtoken field // ldtoken owningtype // In order to call the right Expression APIs. - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] static void TwoMismatchesInOneStatement< @@ -1056,13 +1055,12 @@ static void SpecificType () Expression> a = () => TypeWithPublicMethods.Property; } + [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091")] // There are two warnings per "callsite" in this case because the generated IL does // ldtoken method (getter) // ldtoken owningtype // In order to call the right Expression APIs. - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] static void MultipleReferencesToTheSameProperty< @@ -1074,13 +1072,12 @@ static void MultipleReferencesToTheSameProperty< a = () => TypeWithPublicMethods.Property; // Warn } + [ExpectedWarning ("IL2091")] + [ExpectedWarning ("IL2091")] // There are two warnings per "callsite" in this case because the generated IL does // ldtoken method (getter) // ldtoken owningtype // In order to call the right Expression APIs. - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] static void TwoMismatchesInOneStatement< @@ -1158,7 +1155,6 @@ static void SpecificType () bool a = _value is TypeWithPublicMethods; } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void MultipleReferencesToTheSameMethod< @@ -1170,7 +1166,6 @@ static void MultipleReferencesToTheSameMethod< bool a3 = _value is TypeWithPublicMethods; // Warn } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void TwoMismatchesInOneStatement< @@ -1205,7 +1200,6 @@ static void SpecificType () object a = _value as TypeWithPublicMethods; } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void MultipleReferencesToTheSameMethod< @@ -1217,7 +1211,6 @@ static void MultipleReferencesToTheSameMethod< object a3 = _value as TypeWithPublicMethods; // Warn } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void TwoMismatchesInOneStatement< @@ -1258,7 +1251,6 @@ static void SpecificType () } } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void MultipleReferencesToTheSameType< @@ -1281,7 +1273,6 @@ static void MultipleReferencesToTheSameType< } } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void TwoMismatchesInOneStatement< @@ -1323,7 +1314,6 @@ static void SpecificType () } } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void MultipleReferencesToTheSameType< @@ -1346,7 +1336,6 @@ static void MultipleReferencesToTheSameType< } } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer)] // NativeAOT_StorageSpaceType static void TwoMismatchesInOneStatement< @@ -1521,9 +1510,8 @@ class TypeWithRUCMethod public static void RUCMethod () { } } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", "--RUCMethod--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields))] + [ExpectedWarning ("IL2026", "--RUCMethod--")] static void GenericMethodNesting () { GenericMethodNoRequirements>> (); // No warning @@ -1531,9 +1519,8 @@ static void GenericMethodNesting () GenericMethodNoRequirements>>> (); // IL2026 } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", "--RUCMethod--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields))] + [ExpectedWarning ("IL2026", "--RUCMethod--")] static void GenericMethodNestingAccessToT () { GenericMethodNoRequirementsAccessToT>> (); // No warning @@ -1541,9 +1528,8 @@ static void GenericMethodNestingAccessToT () GenericMethodNoRequirementsAccessToT>>> (); // IL2026 } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", "--RUCMethod--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields))] + [ExpectedWarning ("IL2026", "--RUCMethod--")] static void GenericInstanceMethodNesting () { GenericTypeWithMethodAndField instance = new (); @@ -1552,11 +1538,10 @@ static void GenericInstanceMethodNesting () instance.GenericInstanceMethod>>> (); // IL2026 } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2091", "TUnknown", "RequiresMethods", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", "--RUCMethod--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", "--RUCMethod--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields")] + [ExpectedWarning ("IL2091", "TUnknown", "RequiresMethods")] + [ExpectedWarning ("IL2026", "--RUCMethod--")] + [ExpectedWarning ("IL2026", "--RUCMethod--")] static void MethodOnGenericTypeNesting () { GenericTypeWithMethodAndField>>.GenericMethod (); // No warning @@ -1566,9 +1551,8 @@ static void MethodOnGenericTypeNesting () .GenericMethod>>> (); // IL2026 } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] - [ExpectedWarning ("IL2026", "--RUCMethod--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields))] + [ExpectedWarning ("IL2026", "--RUCMethod--")] static void FieldOnGenericTypeNesting () { GenericTypeWithMethodAndField>>.Field = 0; // No warning @@ -1587,8 +1571,7 @@ class DerivedWithNothing : Base>> { } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields))] class DerivedWithFields : Base>>> { @@ -1597,8 +1580,7 @@ static DerivedWithFields () } } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2026", "--RUCMethod--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--RUCMethod--")] class DerivedWithRUC : Base>>> { } @@ -1622,8 +1604,7 @@ class DerivedWithNothing : IBase>> { } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields), ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091", "TUnknown", "RequiresFields", nameof (DynamicallyAccessedMemberTypes.PublicFields))] class DerivedWithFields : IBase>>> { @@ -1632,8 +1613,7 @@ static DerivedWithFields () } } - // Analyzer: https://github.com/dotnet/runtime/issues/95121 - [ExpectedWarning ("IL2026", "--RUCMethod--", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2026", "--RUCMethod--")] class DerivedWithRUC : IBase>>> { } 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 633e1bed4195d..3f8a078eb84ce 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 @@ -1175,7 +1175,7 @@ public void InstanceMethodWithAttribute () { } [ExpectedWarning ("IL2091")] public class ClassWithWarning : RequiresAll { - [ExpectedWarning ("IL2091", ProducedBy = Tool.Trimmer | Tool.NativeAot)] + [ExpectedWarning ("IL2091")] public ClassWithWarning () { }