diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs index 70c856f7ca283f..11881d3f7d15ba 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs @@ -232,7 +232,7 @@ public bool ShouldWarnWhenAccessedForReflection(MethodDesc method) // public override Type GetTypeWithFields() { return typeof(TestType); } // } // - // If TestType from above is trimmed, it may note have all its fields, and there would be no warnings generated. + // If TestType from above is trimmed, it may not have all its fields, and there would be no warnings generated. // But there has to be code like this somewhere in the app, in order to generate the override: // class RuntimeTypeGenerator // { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs index bf966393c0f2ef..83b592554c6c50 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs @@ -325,9 +325,6 @@ static bool IsDeclaredWithinType(TypeSystemEntity member, TypeDesc type) var id = reportOnMember ? DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberWithDynamicallyAccessedMembers : DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithDynamicallyAccessedMembers; _logger.LogWarning(origin, id, _typeHierarchyDataFlowOrigin.GetDisplayName(), entity.GetDisplayName()); } - - // We decided to not warn on reflection access to compiler-generated methods: - // https://github.com/dotnet/runtime/issues/85042 } private void ReportRequires(in MessageOrigin origin, TypeSystemEntity entity, string requiresAttributeName, in CustomAttributeValue requiresAttribute) diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs index 66b71ab4f9c385..b2026100321931 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs @@ -39,6 +39,10 @@ public static ImmutableArray GetSupportedDiagnostics () diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnMethodReturnValueCanOnlyApplyToTypesOrStrings)); diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersFieldAccessedViaReflection)); diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMethodAccessedViaReflection)); + diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberWithRequiresUnreferencedCode)); + diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithRequiresUnreferencedCode)); + diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberWithDynamicallyAccessedMembers)); + diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithDynamicallyAccessedMembers)); diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.UnrecognizedTypeInRuntimeHelpersRunClassConstructor)); diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodReturnValueBetweenOverrides)); diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchOnMethodParameterBetweenOverrides)); @@ -75,7 +79,7 @@ void AddRange (DiagnosticId first, DiagnosticId last) public override ImmutableArray SupportedDiagnostics => GetSupportedDiagnostics (); - static Location GetPrimaryLocation (ImmutableArray? locations) { + internal static Location GetPrimaryLocation (ImmutableArray? locations) { if (locations is null) return Location.None; @@ -122,6 +126,8 @@ public override void Initialize (AnalysisContext context) foreach (var interfaceType in type.Interfaces) GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, interfaceType, context.ReportDiagnostic); + + DynamicallyAccessedMembersTypeHierarchy.ApplyDynamicallyAccessedMembersToTypeHierarchy (location, type, context.ReportDiagnostic); }, SymbolKind.NamedType); context.RegisterSymbolAction (context => { VerifyMemberOnlyApplyToTypesOrStrings (context, context.Symbol); diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersTypeHierarchy.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersTypeHierarchy.cs new file mode 100644 index 00000000000000..9b6ea59ba10459 --- /dev/null +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersTypeHierarchy.cs @@ -0,0 +1,54 @@ +// 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; +using System.Diagnostics.CodeAnalysis; +using Microsoft.CodeAnalysis; +using ILLink.Shared; +using ILLink.Shared.TrimAnalysis; +using ILLink.RoslynAnalyzer.TrimAnalysis; + +namespace ILLink.RoslynAnalyzer +{ + sealed class DynamicallyAccessedMembersTypeHierarchy + { + public static void ApplyDynamicallyAccessedMembersToTypeHierarchy (Location typeLocation, INamedTypeSymbol type, Action reportDiagnostic) + { + var annotation = FlowAnnotations.GetTypeAnnotation (type); + + // We need to apply annotations to this type, and its base/interface types (recursively) + // But the annotations on base/interfaces may already be applied so we don't need to apply those + // again (and should avoid doing so as it would produce extra warnings). + var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic, type); + if (type.BaseType is INamedTypeSymbol baseType) { + var baseAnnotation = FlowAnnotations.GetTypeAnnotation (baseType); + var annotationToApplyToBase = Annotations.GetMissingMemberTypes (annotation, baseAnnotation); + + // Apply any annotations that didn't exist on the base type to the base type. + // This may produce redundant warnings when the annotation is DAMT.All or DAMT.PublicConstructors and the base already has a + // subset of those annotations. + reflectionAccessAnalyzer.GetReflectionAccessDiagnostics (typeLocation, baseType, annotationToApplyToBase, declaredOnly: false); + } + + // Most of the DynamicallyAccessedMemberTypes don't select members on interfaces. We only need to apply + // annotations to interfaces separately if dealing with DAMT.All or DAMT.Interfaces. + if (annotation.HasFlag (DynamicallyAccessedMemberTypes.Interfaces)) + { + var annotationToApplyToInterfaces = annotation == DynamicallyAccessedMemberTypes.All ? annotation : DynamicallyAccessedMemberTypes.Interfaces; + foreach (var iface in type.AllInterfaces) { + if (FlowAnnotations.GetTypeAnnotation (iface).HasFlag (annotationToApplyToInterfaces)) + continue; + + // Apply All or Interfaces to the interface type. + // DAMT.All may produce redundant warnings from implementing types, when the interface type already had some annotations. + reflectionAccessAnalyzer.GetReflectionAccessDiagnostics (typeLocation, iface, annotationToApplyToInterfaces, declaredOnly: false); + } + } + + // The annotations this type inherited from its base types or interfaces should not produce + // warnings on the respective base/interface members, since those are already covered by applying + // the annotations to those types. So we only need to handle the members directly declared on this type. + reflectionAccessAnalyzer.GetReflectionAccessDiagnostics (typeLocation, type, annotation, declaredOnly: true); + } + } +} diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs index 8e5f60179dcd71..c657c7cc6358bc 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs @@ -35,6 +35,97 @@ public static bool RequiresDataFlowAnalysis (IMethodSymbol method) return false; } + internal static bool ShouldWarnWhenAccessedForReflection (ISymbol symbol) => + symbol switch { + IMethodSymbol method => ShouldWarnWhenAccessedForReflection (method), + IFieldSymbol field => ShouldWarnWhenAccessedForReflection (field), + _ => false + }; + + static bool ShouldWarnWhenAccessedForReflection (IMethodSymbol method) + { + bool? hasParameterAnnotation = null; + if (GetMethodReturnValueAnnotation (method) == DynamicallyAccessedMemberTypes.None) { + if (!HasParameterAnnotation (method)) + return false; + hasParameterAnnotation = true; + } + + // If the method only has annotation on the return value and it's not virtual avoid warning. + // Return value annotations are "consumed" by the caller of a method, and as such there is nothing + // wrong calling these dynamically. The only problem can happen if something overrides a virtual + // method with annotated return value at runtime - in this case the trimmer can't validate + // that the method will return only types which fulfill the annotation's requirements. + // For example: + // class BaseWithAnnotation + // { + // [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] + // public abstract Type GetTypeWithFields(); + // } + // + // class UsingTheBase + // { + // public void PrintFields(Base base) + // { + // // No warning here - GetTypeWithFields is correctly annotated to allow GetFields on the return value. + // Console.WriteLine(string.Join(" ", base.GetTypeWithFields().GetFields().Select(f => f.Name))); + // } + // } + // + // If at runtime (through ref emit) something generates code like this: + // class DerivedAtRuntimeFromBase + // { + // // No point in adding annotation on the return value - nothing will look at it anyway + // // Trimming will not see this code, so there are no checks + // public override Type GetTypeWithFields() { return typeof(TestType); } + // } + // + // If TestType from above is trimmed, it may not have all its fields, and there would be no warnings generated. + // But there has to be code like this somewhere in the app, in order to generate the override: + // class RuntimeTypeGenerator + // { + // public MethodInfo GetBaseMethod() + // { + // // This must warn - that the GetTypeWithFields has annotation on the return value + // return typeof(BaseWithAnnotation).GetMethod("GetTypeWithFields"); + // } + // } + + return method.IsVirtual || method.IsOverride || (hasParameterAnnotation ?? HasParameterAnnotation (method)); + + static bool HasParameterAnnotation (IMethodSymbol method) { + foreach (var param in method.GetParameters ()) { + if (GetMethodParameterAnnotation (param) != DynamicallyAccessedMemberTypes.None) + return true; + } + return false; + } + } + + static bool ShouldWarnWhenAccessedForReflection (IFieldSymbol field) + { + return field.GetDynamicallyAccessedMemberTypes () != DynamicallyAccessedMemberTypes.None; + } + + internal static DynamicallyAccessedMemberTypes GetTypeAnnotations (INamedTypeSymbol type) + { + DynamicallyAccessedMemberTypes typeAnnotation = type.GetDynamicallyAccessedMemberTypes (); + + // Also inherit annotation from bases + INamedTypeSymbol? baseType = type.BaseType; + while (baseType is not null) { + typeAnnotation |= baseType.GetDynamicallyAccessedMemberTypes (); + baseType = baseType.BaseType; + } + + // And inherit them from interfaces + foreach (INamedTypeSymbol interfaceType in type.AllInterfaces) { + typeAnnotation |= interfaceType.GetDynamicallyAccessedMemberTypes (); + } + + return typeAnnotation; + } + internal static DynamicallyAccessedMemberTypes GetMethodParameterAnnotation (ParameterProxy param) { IMethodSymbol method = param.Method.Method; diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs index 8eac76a2993396..b3d0a97a4ab5eb 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs @@ -42,7 +42,7 @@ static void ProcessGenericArgumentDataFlow ( var genericParameterValue = new GenericParameterValue (typeParameters[i]); if (genericParameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) { SingleValue genericArgumentValue = SingleValueExtensions.FromTypeSymbol (typeArgument)!; - var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic); + var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic, typeHierarchyType: null); var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (diagnosticContext, reflectionAccessAnalyzer); requireDynamicallyAccessedMembersAction.Invoke (genericArgumentValue, genericParameterValue); } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs index 3e8d00d5d050f8..7a13c46e7fd2c2 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs @@ -39,7 +39,7 @@ public HandleCallAction ( _isNewObj = operation.Kind == OperationKind.ObjectCreation; _diagnosticContext = new DiagnosticContext (location, reportDiagnostic); _annotations = FlowAnnotations.Instance; - _reflectionAccessAnalyzer = new (reportDiagnostic); + _reflectionAccessAnalyzer = new (reportDiagnostic, typeHierarchyType: null); _requireDynamicallyAccessedMembersAction = new (_diagnosticContext, _reflectionAccessAnalyzer); _multiValueLattice = multiValueLattice; } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs index 51d684816418d3..922c64b4e44220 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs @@ -2,7 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using ILLink.RoslynAnalyzer.DataFlow; @@ -15,8 +15,13 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis readonly struct ReflectionAccessAnalyzer { readonly Action? _reportDiagnostic; + readonly INamedTypeSymbol? _typeHierarchyType; - public ReflectionAccessAnalyzer (Action? reportDiagnostic) => _reportDiagnostic = reportDiagnostic; + public ReflectionAccessAnalyzer (Action? reportDiagnostic, INamedTypeSymbol? typeHierarchyType) + { + _reportDiagnostic = reportDiagnostic; + _typeHierarchyType = typeHierarchyType; + } #pragma warning disable CA1822 // Mark members as static - the other partial implementations might need to be instance methods internal void GetReflectionAccessDiagnostics (Location location, ITypeSymbol typeSymbol, DynamicallyAccessedMemberTypes requiredMemberTypes, bool declaredOnly = false) @@ -88,6 +93,11 @@ void ReportRequiresUnreferencedCodeDiagnostic (Location location, AttributeData internal void GetReflectionAccessDiagnosticsForMethod (Location location, IMethodSymbol methodSymbol) { + if (_typeHierarchyType is not null) { + GetTypeHierarchyReflectionAccessDiagnostics (location, methodSymbol); + return; + } + if (methodSymbol.IsInRequiresUnreferencedCodeAttributeScope (out var requiresUnreferencedCodeAttributeData)) { ReportRequiresUnreferencedCodeDiagnostic (location, requiresUnreferencedCodeAttributeData, methodSymbol); } else { @@ -95,6 +105,49 @@ internal void GetReflectionAccessDiagnosticsForMethod (Location location, IMetho } } + internal void GetTypeHierarchyReflectionAccessDiagnostics (Location location, ISymbol member) + { + Debug.Assert (member is IMethodSymbol or IFieldSymbol); + + // Don't check whether the current scope is a RUC type or RUC method because these warnings + // are not suppressed in RUC scopes. Here the scope represents the DynamicallyAccessedMembers + // annotation on a type, not a callsite which uses the annotation. We always want to warn about + // possible reflection access indicated by these annotations. + + Debug.Assert (_typeHierarchyType is not null); + + static bool IsDeclaredWithinType (ISymbol member, INamedTypeSymbol type) + { + INamedTypeSymbol containingType = member.ContainingType; + while (containingType is not null) { + if (SymbolEqualityComparer.Default.Equals (containingType, type)) + return true; + + containingType = containingType.ContainingType; + } + return false; + } + + var reportOnMember = IsDeclaredWithinType (member, _typeHierarchyType!); + if (reportOnMember) + location = DynamicallyAccessedMembersAnalyzer.GetPrimaryLocation (member.Locations); + + var diagnosticContext = new DiagnosticContext (location, _reportDiagnostic); + + if (member.IsInRequiresUnreferencedCodeAttributeScope (out AttributeData? requiresUnreferencedCodeAttribute)) { + var id = reportOnMember ? DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberWithRequiresUnreferencedCode : DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithRequiresUnreferencedCode; + diagnosticContext.AddDiagnostic (id, _typeHierarchyType!.GetDisplayName (), + member.GetDisplayName (), + MessageFormat.FormatRequiresAttributeMessageArg (RequiresUnreferencedCodeUtils.GetMessageFromAttribute (requiresUnreferencedCodeAttribute)), + MessageFormat.FormatRequiresAttributeMessageArg(RequiresAnalyzerBase.GetUrlFromAttribute (requiresUnreferencedCodeAttribute))); + } + + if (FlowAnnotations.ShouldWarnWhenAccessedForReflection (member)) { + var id = reportOnMember ? DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberWithDynamicallyAccessedMembers : DiagnosticId.DynamicallyAccessedMembersOnTypeReferencesMemberOnBaseWithDynamicallyAccessedMembers; + diagnosticContext.AddDiagnostic (id, _typeHierarchyType!.GetDisplayName (), member.GetDisplayName ()); + } + } + internal void GetDiagnosticsForReflectionAccessToDAMOnMethod (Location location, IMethodSymbol methodSymbol) { var diagnosticContext = new DiagnosticContext (location, _reportDiagnostic); @@ -130,6 +183,11 @@ void GetDiagnosticsForEvent (Location location, IEventSymbol eventSymbol) void GetDiagnosticsForField (Location location, IFieldSymbol fieldSymbol) { + if (_typeHierarchyType is not null) { + GetTypeHierarchyReflectionAccessDiagnostics (location, fieldSymbol); + return; + } + if (fieldSymbol.TryGetRequiresUnreferencedCodeAttribute (out var requiresUnreferencedCodeAttributeData)) ReportRequiresUnreferencedCodeDiagnostic (location, requiresUnreferencedCodeAttributeData, fieldSymbol); diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs index 46793d6b448c61..3a40e899277f65 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs @@ -66,7 +66,7 @@ public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { var location = Operation.Syntax.GetLocation (); - var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic); + var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic, typeHierarchyType: null); if (context.EnableTrimAnalyzer && !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) && !FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) { diff --git a/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs index 5f106d831e6754..b49d8628bcedb2 100644 --- a/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/tools/illink/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -130,7 +130,7 @@ public bool ShouldWarnWhenAccessedForReflection (MethodDefinition method) // public override Type GetTypeWithFields() { return typeof(TestType); } // } // - // If TestType from above is trimmed, it may note have all its fields, and there would be no warnings generated. + // If TestType from above is trimmed, it may not have all its fields, and there would be no warnings generated. // But there has to be code like this somewhere in the app, in order to generate the override: // class RuntimeTypeGenerator // { diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs index c3cae702e3e929..4a7d0986aea718 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/ReflectionTests.cs @@ -148,6 +148,12 @@ public Task ObjectGetType () return RunTest (); } + [Fact] + public Task ObjectGetTypeLibraryMode () + { + return RunTest (); + } + [Fact] public Task PropertyUsedViaReflection () { @@ -178,18 +184,22 @@ public Task TypeDelegator () return RunTest (); } + [Fact] + public Task TypeHierarchyLibraryModeSuppressions () + { + return RunTest (); + } + [Fact] public Task TypeHierarchyReflectionWarnings () { - // https://github.com/dotnet/runtime/issues/104742 - return RunTest (allowMissingWarnings: true); + return RunTest (); } [Fact] public Task TypeHierarchySuppressions () { - // https://github.com/dotnet/runtime/issues/104742 - return RunTest (allowMissingWarnings: true); + return RunTest (); } [Fact] diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs index fa45ca4ce1687f..ce2cfe3cc00913 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/ReflectionTests.g.cs @@ -43,12 +43,6 @@ public Task IsAssignableFrom () return RunTest (allowMissingWarnings: true); } - [Fact] - public Task ObjectGetTypeLibraryMode () - { - return RunTest (allowMissingWarnings: true); - } - [Fact] public Task ParametersUsedViaReflection () { @@ -61,12 +55,6 @@ public Task RunClassConstructorUsedViaReflection () return RunTest (allowMissingWarnings: true); } - [Fact] - public Task TypeHierarchyLibraryModeSuppressions () - { - return RunTest (allowMissingWarnings: true); - } - [Fact] public Task UnderlyingSystemType () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs index 2e943bea1fc9ce..eb5a2e7dd79f76 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AnnotatedMembersAccessedViaReflection.cs @@ -953,17 +953,17 @@ public DamOnTypeAccessesMembers() { } [RequiresUnreferencedCode("--AnnotatedType--")] public class AnnotatedType { - [ExpectedWarning("IL2112", [nameof(AnnotatedType), "requires unreferenced code", "--AnnotatedType--"], Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002")] + [ExpectedWarning("IL2112", nameof(AnnotatedType), "requires unreferenced code", "--AnnotatedType--")] public AnnotatedType () { } } - [ExpectedWarning("IL2114", nameof(MethodWithDataflow), nameof(DynamicallyAccessedMembersAttribute), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002")] + [ExpectedWarning("IL2114", nameof(MethodWithDataflow), nameof(DynamicallyAccessedMembersAttribute))] public void MethodWithDataflow ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { } [RequiresDynamicCode ("--MethodWithRequires--")] [RequiresUnreferencedCode("--MethodWithRequires--")] [RequiresAssemblyFiles("--MethodWithRequires--")] - [ExpectedWarning("IL2112", "requires unreferenced code", "--MethodWithRequires--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002")] + [ExpectedWarning("IL2112", "requires unreferenced code", "--MethodWithRequires--")] public void MethodWithRequires () { } public static void Test () diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs index b59683325cdf0d..1c83b288191d02 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/CompilerGeneratedCodeAccessedViaReflection.cs @@ -79,11 +79,11 @@ public static IEnumerable IteratorWithProblematicDataflow () t_IteratorWithProblematicDataflow.RequiresAll (); } - [ExpectedWarning ("IL2112", nameof (RUCTypeWithIterators) + "()", "--RUCTypeWithIterators--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002", CompilerGeneratedCode = true)] // warning about .ctor + [ExpectedWarning ("IL2112", nameof (RUCTypeWithIterators) + "()", "--RUCTypeWithIterators--", CompilerGeneratedCode = true)] // warning about .ctor [RequiresUnreferencedCode ("--RUCTypeWithIterators--")] class RUCTypeWithIterators { - [ExpectedWarning ("IL2112", nameof (StaticIteratorCallsMethodWithRequires) + "()", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002")] + [ExpectedWarning ("IL2112", nameof (StaticIteratorCallsMethodWithRequires) + "()")] [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "NativeAOT Specific Warning", CompilerGeneratedCode = true)] [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "NativeAOT Specific Warning", CompilerGeneratedCode = true)] public static IEnumerable StaticIteratorCallsMethodWithRequires () @@ -92,7 +92,7 @@ public static IEnumerable StaticIteratorCallsMethodWithRequires () MethodWithRequires (); } - [ExpectedWarning ("IL2112", nameof (InstanceIteratorCallsMethodWithRequires) + "()", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002")] + [ExpectedWarning ("IL2112", nameof (InstanceIteratorCallsMethodWithRequires) + "()")] [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "NativeAOT Specific Warning", CompilerGeneratedCode = true)] [ExpectedWarning ("IL3050", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "NativeAOT Specific Warning", CompilerGeneratedCode = true)] public IEnumerable InstanceIteratorCallsMethodWithRequires () @@ -268,11 +268,11 @@ static void LambdaCallsPInvokeTakingObject () lambda (); } - [ExpectedWarning ("IL2112", nameof (RUCTypeWithLambdas) + "()", "--RUCTypeWithLambdas--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2112", nameof (RUCTypeWithLambdas) + "()", "--RUCTypeWithLambdas--", CompilerGeneratedCode = true)] [RequiresUnreferencedCode ("--RUCTypeWithLambdas--")] class RUCTypeWithLambdas { - [ExpectedWarning ("IL2112", [nameof (MethodWithLambdas), "--RUCTypeWithLambdas--"], Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002")] + [ExpectedWarning ("IL2112", nameof (MethodWithLambdas), "--RUCTypeWithLambdas--")] public void MethodWithLambdas () { var lambda = @@ -374,11 +374,11 @@ static void LocalFunctionCallsPInvokeTakingObject () LocalFunction (); } - [ExpectedWarning ("IL2112", nameof (RUCTypeWithLocalFunctions) + "()", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL2112", nameof (RUCTypeWithLocalFunctions) + "()", CompilerGeneratedCode = true)] [RequiresUnreferencedCode ("--RUCTypeWithLocalFunctions--")] class RUCTypeWithLocalFunctions { - [ExpectedWarning ("IL2112", nameof (MethodWithLocalFunctions), "--RUCTypeWithLocalFunctions--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002")] + [ExpectedWarning ("IL2112", nameof (MethodWithLocalFunctions), "--RUCTypeWithLocalFunctions--")] public void MethodWithLocalFunctions () { [ExpectedWarning ("IL3002", "--MethodWithRequires--", Tool.Analyzer | Tool.NativeAot, "NativeAOT Specific Warnings")] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs index c88bd2bfdc9203..8eb3440c853aca 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs @@ -52,19 +52,19 @@ class InstantiatedGenericAsSource [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] class Generic { [Kept] - [ExpectedWarning ("IL2112", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002")] + [ExpectedWarning ("IL2112")] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [RequiresUnreferencedCode (nameof (KeptForMethodParameter))] public void KeptForMethodParameter () {} [Kept] - [ExpectedWarning ("IL2112", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002")] + [ExpectedWarning ("IL2112")] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [RequiresUnreferencedCode (nameof (KeptForField))] public void KeptForField () {} [Kept] - [ExpectedWarning ("IL2112", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/102002")] + [ExpectedWarning ("IL2112")] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [RequiresUnreferencedCode (nameof (KeptJustBecause))] public void KeptJustBecause () {} diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs index 451cf28afbde40..aea71ba48f0628 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs @@ -1427,6 +1427,7 @@ class DataFlowUnusedGetType [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] class AnnotatedType { + [ExpectedWarning ("IL2112", Tool.Analyzer, "Analyzer warns about DAM on type access to members even without call to object.GetType().")] [RequiresUnreferencedCode ("AnnotatedType.Method")] public void Method () { } } @@ -1444,6 +1445,7 @@ class AnnotatedBase class DerivedFromAnnotatedBase : AnnotatedBase { + [ExpectedWarning ("IL2112", Tool.Analyzer, "Analyzer warns about DAM on type access to members even without call to object.GetType().")] [RequiresUnreferencedCode ("DerivedFromAnnotatedBase.Method")] public void Method () { } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs index 63bc3b31c772aa..bded9f86c640ed 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs @@ -266,6 +266,7 @@ interface RequiredInterface { // Removed, because keeping the interface on its own // doesn't apply its type annotations + [ExpectedWarning ("IL2112", nameof (RequiredInterface), nameof (RUCMethod), Tool.Analyzer, "Analyzer warns about DAM on type access to members even without call to object.GetType().")] [RequiresUnreferencedCode ("--RUC on RequiredInterface.UnusedMethod--")] void RUCMethod (); } @@ -313,7 +314,7 @@ class DerivedFromAnnotatedPublicParameterlessConstructor : AnnotatedPublicParame [Kept] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [ExpectedWarning ("IL2112", "--RUC on DerivedFromAnnotatedPublicParameterlessConstructor()--")] - [ExpectedWarning ("IL2112", "--RUC on DerivedFromAnnotatedPublicParameterlessConstructor()--", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2112", "--RUC on DerivedFromAnnotatedPublicParameterlessConstructor()--")] [RequiresUnreferencedCode ("--RUC on DerivedFromAnnotatedPublicParameterlessConstructor()--")] public DerivedFromAnnotatedPublicParameterlessConstructor () { } @@ -701,7 +702,7 @@ public class Base [Kept] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [RequiresUnreferencedCode ("--RUCOnVirtualMethodDerivedAnnotated.Base.RUCVirtualMethod--")] - [ExpectedWarning ("IL2112", "--RUCOnVirtualMethodDerivedAnnotated.Base.RUCVirtualMethod--", Tool.Trimmer, "https://github.com/dotnet/runtime/issues/104740")] + [ExpectedWarning ("IL2112", "--RUCOnVirtualMethodDerivedAnnotated.Base.RUCVirtualMethod--", Tool.Trimmer | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/104740")] public virtual void RUCVirtualMethod () { } } @@ -739,7 +740,7 @@ public interface Interface [Kept] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [RequiresUnreferencedCode ("--RUCOnVirtualOnAnnotatedInterface.Interface.RUCVirtualMethod--")] - [ExpectedWarning ("IL2112", "--RUCOnVirtualOnAnnotatedInterface.Interface.RUCVirtualMethod--", Tool.Trimmer, "https://github.com/dotnet/runtime/issues/104740")] + [ExpectedWarning ("IL2112", "--RUCOnVirtualOnAnnotatedInterface.Interface.RUCVirtualMethod--", Tool.Trimmer | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/104740")] void RUCVirtualMethod () { } } @@ -777,7 +778,7 @@ public interface Interface [Kept] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [RequiresUnreferencedCode ("--RucOnVirtualOnAnnotatedInterfaceUsedByImplementation.Interface.RUCVirtualMethod--")] - [ExpectedWarning ("IL2112", "--RucOnVirtualOnAnnotatedInterfaceUsedByImplementation.Interface.RUCVirtualMethod--", Tool.Trimmer, "https://github.com/dotnet/runtime/issues/104740")] + [ExpectedWarning ("IL2112", "--RucOnVirtualOnAnnotatedInterfaceUsedByImplementation.Interface.RUCVirtualMethod--", Tool.Trimmer | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/104740")] void RUCVirtualMethod () { } } @@ -820,7 +821,7 @@ class AnnotatedBase [RequiresUnreferencedCode ("--AnnotatedBase.VirtualMethodWithRequires--")] [RequiresDynamicCode ("--AnnotatedBase.VirtualMethodWithRequires--")] [RequiresAssemblyFiles ("--AnnotatedBase.VirtualMethodWithRequires--")] - [ExpectedWarning ("IL2112", "--AnnotatedBase.VirtualMethodWithRequires--", Tool.Trimmer, "https://github.com/dotnet/runtime/issues/104740")] + [ExpectedWarning ("IL2112", "--AnnotatedBase.VirtualMethodWithRequires--", Tool.Trimmer | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/104740")] public virtual void VirtualMethodWithRequires () { } } @@ -910,7 +911,8 @@ public class BaseWithField [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] [KeptBaseType (typeof (BaseWithField))] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicFields)] - [ExpectedWarning ("IL2115", nameof (BaseWithField), nameof (BaseWithField.CompilerGeneratedProperty))] + [ExpectedWarning ("IL2115", nameof (BaseWithField), nameof (BaseWithField.CompilerGeneratedProperty), + Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/2628")] public class DerivedWithAnnotation : BaseWithField { } 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 a97312262ede46..f0c854b043bf1d 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 @@ -768,13 +768,13 @@ class BaseForDAMAnnotatedClass [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)] [RequiresUnreferencedCode ("This class is dangerous")] [RequiresDynamicCode ("This class is dangerous")] - [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseField", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseField")] class DAMAnnotatedClass : BaseForDAMAnnotatedClass { - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicField", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicField")] public static int publicField; - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privatefield", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privatefield")] static int privatefield; } @@ -786,7 +786,7 @@ static void TestDAMOnTypeAccess (DAMAnnotatedClass instance) [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] class DAMAnnotatedClassAccessedFromRUCScope { - [ExpectedWarning ("IL2112", "DAMAnnotatedClassAccessedFromRUCScope.RUCMethod", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2112", "DAMAnnotatedClassAccessedFromRUCScope.RUCMethod")] [RequiresUnreferencedCode ("--RUCMethod--")] public static void RUCMethod () { } } @@ -1184,21 +1184,21 @@ class BaseForDAMAnnotatedClass [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] [RequiresUnreferencedCode ("This class is dangerous")] [RequiresDynamicCode ("This class is dangerous")] - [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseProperty.get", Tool.Trimmer | Tool.NativeAot, "")] - [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseProperty.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseProperty.get")] + [ExpectedWarning ("IL2113", "BaseForDAMAnnotatedClass.baseProperty.set")] class DAMAnnotatedClass : BaseForDAMAnnotatedClass { public static int publicProperty { - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicProperty.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicProperty.get")] get; - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicProperty.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.publicProperty.set")] set; } static int privateProperty { - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privateProperty.get", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privateProperty.get")] get; - [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privateProperty.set", Tool.Trimmer | Tool.NativeAot, "")] + [ExpectedWarning ("IL2112", "DAMAnnotatedClass.privateProperty.set")] set; } }