diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs index 66b71ab4f9c38..c9342122aa6de 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/DynamicallyAccessedMembersAnalyzer.cs @@ -52,6 +52,7 @@ public static ImmutableArray GetSupportedDiagnostics () diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.UnrecognizedTypeNameInTypeGetType)); diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.UnrecognizedParameterInMethodCreateInstance)); diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.ParametersOfAssemblyCreateInstanceCannotBeAnalyzed)); + diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.TypeNameIsNotAssemblyQualified)); diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.ReturnValueDoesNotMatchFeatureGuards)); diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.InvalidFeatureGuard)); @@ -117,11 +118,12 @@ public override void Initialize (AnalysisContext context) var location = GetPrimaryLocation (type.Locations); + var typeNameResolver = new TypeNameResolver (context.Compilation); if (type.BaseType is INamedTypeSymbol baseType) - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, baseType, context.ReportDiagnostic); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (typeNameResolver, location, baseType, context.ReportDiagnostic); foreach (var interfaceType in type.Interfaces) - GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, interfaceType, context.ReportDiagnostic); + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (typeNameResolver, location, interfaceType, context.ReportDiagnostic); }, SymbolKind.NamedType); context.RegisterSymbolAction (context => { VerifyMemberOnlyApplyToTypesOrStrings (context, context.Symbol); diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/ILLink.RoslynAnalyzer.csproj b/src/tools/illink/src/ILLink.RoslynAnalyzer/ILLink.RoslynAnalyzer.csproj index bc410523d5d71..c3b0b1d1847b4 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/ILLink.RoslynAnalyzer.csproj +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/ILLink.RoslynAnalyzer.csproj @@ -15,10 +15,13 @@ optimize the analyzer even in Debug builds. Note: we still use the Debug configuration to get Debug asserts. --> true + true + + @@ -28,6 +31,7 @@ all contentfiles + diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs index 8eac76a299339..84a6d31d3fa85 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/GenericArgumentDataFlow.cs @@ -12,28 +12,29 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis { internal static class GenericArgumentDataFlow { - public static void ProcessGenericArgumentDataFlow (Location location, INamedTypeSymbol type, Action reportDiagnostic) + public static void ProcessGenericArgumentDataFlow (TypeNameResolver typeNameResolver, Location location, INamedTypeSymbol type, Action? reportDiagnostic) { - ProcessGenericArgumentDataFlow (location, type.TypeArguments, type.TypeParameters, reportDiagnostic); + ProcessGenericArgumentDataFlow (typeNameResolver, location, type.TypeArguments, type.TypeParameters, reportDiagnostic); } - public static void ProcessGenericArgumentDataFlow (Location location, IMethodSymbol method, Action reportDiagnostic) + public static void ProcessGenericArgumentDataFlow (TypeNameResolver typeNameResolver, Location location, IMethodSymbol method, Action? reportDiagnostic) { - ProcessGenericArgumentDataFlow (location, method.TypeArguments, method.TypeParameters, reportDiagnostic); + ProcessGenericArgumentDataFlow (typeNameResolver, location, method.TypeArguments, method.TypeParameters, reportDiagnostic); - ProcessGenericArgumentDataFlow (location, method.ContainingType, reportDiagnostic); + ProcessGenericArgumentDataFlow (typeNameResolver, location, method.ContainingType, reportDiagnostic); } - public static void ProcessGenericArgumentDataFlow (Location location, IFieldSymbol field, Action reportDiagnostic) + public static void ProcessGenericArgumentDataFlow (TypeNameResolver typeNameResolver, Location location, IFieldSymbol field, Action? reportDiagnostic) { - ProcessGenericArgumentDataFlow (location, field.ContainingType, reportDiagnostic); + ProcessGenericArgumentDataFlow (typeNameResolver, location, field.ContainingType, reportDiagnostic); } static void ProcessGenericArgumentDataFlow ( + TypeNameResolver typeNameResolver, Location location, ImmutableArray typeArguments, ImmutableArray typeParameters, - Action reportDiagnostic) + Action? reportDiagnostic) { var diagnosticContext = new DiagnosticContext (location, reportDiagnostic); for (int i = 0; i < typeArguments.Length; i++) { @@ -42,14 +43,14 @@ 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 requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (diagnosticContext, reflectionAccessAnalyzer); + var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic, typeNameResolver); + var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (typeNameResolver, location, reportDiagnostic, 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 (location, namedTypeArgument, reportDiagnostic); + ProcessGenericArgumentDataFlow (typeNameResolver, location, namedTypeArgument, reportDiagnostic); } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs index 3e8d00d5d050f..53294dc3c32a9 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/HandleCallAction.cs @@ -28,6 +28,7 @@ internal partial struct HandleCallAction ValueSetLattice _multiValueLattice; public HandleCallAction ( + TypeNameResolver typeNameResolver, Location location, ISymbol owningSymbol, IOperation operation, @@ -39,8 +40,8 @@ public HandleCallAction ( _isNewObj = operation.Kind == OperationKind.ObjectCreation; _diagnosticContext = new DiagnosticContext (location, reportDiagnostic); _annotations = FlowAnnotations.Instance; - _reflectionAccessAnalyzer = new (reportDiagnostic); - _requireDynamicallyAccessedMembersAction = new (_diagnosticContext, _reflectionAccessAnalyzer); + _reflectionAccessAnalyzer = new (reportDiagnostic, typeNameResolver); + _requireDynamicallyAccessedMembersAction = new (typeNameResolver, location, reportDiagnostic, _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 51d684816418d..c53e28ff336fd 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/ReflectionAccessAnalyzer.cs @@ -15,8 +15,15 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis readonly struct ReflectionAccessAnalyzer { readonly Action? _reportDiagnostic; + readonly TypeNameResolver _typeNameResolver; - public ReflectionAccessAnalyzer (Action? reportDiagnostic) => _reportDiagnostic = reportDiagnostic; + public ReflectionAccessAnalyzer ( + Action? reportDiagnostic, + TypeNameResolver typeNameResolver) + { + _reportDiagnostic = reportDiagnostic; + _typeNameResolver = typeNameResolver; + } #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) @@ -138,5 +145,10 @@ void GetDiagnosticsForField (Location location, IFieldSymbol fieldSymbol) diagnosticContext.AddDiagnostic (DiagnosticId.DynamicallyAccessedMembersFieldAccessedViaReflection, fieldSymbol.GetDisplayName ()); } } + + internal bool TryResolveTypeNameAndMark (string typeName, in DiagnosticContext diagnosticContext, bool needsAssemblyName, [NotNullWhen (true)] out ITypeSymbol? type) + { + return _typeNameResolver.TryResolveTypeName (typeName, diagnosticContext, out type, needsAssemblyName); + } } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs index 5226aad4f0320..91fdb54ef8394 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/RequireDynamicallyAccessedMembersAction.cs @@ -1,40 +1,55 @@ // 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; using System.Diagnostics.CodeAnalysis; +using System.Reflection.Metadata; +using Microsoft.CodeAnalysis; using ILLink.RoslynAnalyzer.TrimAnalysis; using ILLink.Shared.TypeSystemProxy; +using System.Collections.Immutable; namespace ILLink.Shared.TrimAnalysis { internal partial struct RequireDynamicallyAccessedMembersAction { + readonly Location _location; + readonly Action? _reportDiagnostic; readonly ReflectionAccessAnalyzer _reflectionAccessAnalyzer; + readonly TypeNameResolver _typeNameResolver; #pragma warning disable CA1822 // Mark members as static - the other partial implementations might need to be instance methods #pragma warning disable IDE0060 // Unused parameters - should be removed once methods are actually implemented public RequireDynamicallyAccessedMembersAction ( - DiagnosticContext diagnosticContext, + TypeNameResolver typeNameResolver, + Location location, + Action? reportDiagnostic, ReflectionAccessAnalyzer reflectionAccessAnalyzer) { - _diagnosticContext = diagnosticContext; + _typeNameResolver = typeNameResolver; + _location = location; + _reportDiagnostic = reportDiagnostic; _reflectionAccessAnalyzer = reflectionAccessAnalyzer; + _diagnosticContext = new (location, reportDiagnostic); } public partial bool TryResolveTypeNameAndMark (string typeName, bool needsAssemblyName, out TypeProxy type) { - // TODO: Implement type name resolution to type symbol - // https://github.com/dotnet/runtime/issues/95118 + var diagnosticContext = new DiagnosticContext (_location, _reportDiagnostic); + if (_reflectionAccessAnalyzer.TryResolveTypeNameAndMark (typeName, diagnosticContext, needsAssemblyName, out ITypeSymbol? foundType)) { + if (foundType is INamedTypeSymbol namedType && namedType.IsGenericType) + GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (_typeNameResolver, _location, namedType, _reportDiagnostic); - // Important corner cases: - // IL2105 (see it's occurences in the tests) - non-assembly qualified type name which doesn't resolve warns - // - will need to figure out what analyzer should do around this. + type = new TypeProxy (foundType); + return true; + } type = default; return false; } private partial void MarkTypeForDynamicallyAccessedMembers (in TypeProxy type, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) => - _reflectionAccessAnalyzer.GetReflectionAccessDiagnostics (_diagnosticContext.Location, type.Type, dynamicallyAccessedMemberTypes); + _reflectionAccessAnalyzer.GetReflectionAccessDiagnostics (_location, type.Type, dynamicallyAccessedMemberTypes); } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs index 46793d6b448c6..7f410b7e7c4bc 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisAssignmentPattern.cs @@ -55,7 +55,7 @@ public TrimAnalysisAssignmentPattern Merge ( public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { - var diagnosticContext = new DiagnosticContext (Operation.Syntax.GetLocation (), reportDiagnostic); + var location = Operation.Syntax.GetLocation (); if (context.EnableTrimAnalyzer && !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) && !FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) { @@ -66,8 +66,9 @@ public void ReportDiagnostics (DataFlowAnalyzerContext context, Action reportDiagnostic) { var location = Operation.Syntax.GetLocation (); - var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic); + var typeNameResolver = new TypeNameResolver (context.Compilation); + var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic, typeNameResolver); if (context.EnableTrimAnalyzer && !OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) && !FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) { diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs index 58c3c97c55020..d98d172296aae 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TrimAnalysisVisitor.cs @@ -43,6 +43,8 @@ internal sealed class TrimAnalysisVisitor : LocalDataFlowVisitor< FeatureChecksVisitor _featureChecksVisitor; + readonly TypeNameResolver _typeNameResolver; + public TrimAnalysisVisitor ( Compilation compilation, LocalStateAndContextLattice, FeatureContextLattice> lattice, @@ -57,6 +59,7 @@ public TrimAnalysisVisitor ( _multiValueLattice = lattice.LocalStateLattice.Lattice.ValueLattice; TrimAnalysisPatterns = trimAnalysisPatterns; _featureChecksVisitor = new FeatureChecksVisitor (dataFlowAnalyzerContext); + _typeNameResolver = new TypeNameResolver (compilation); } public override FeatureChecksValue GetConditionValue (IOperation branchValueOperation, StateValue state) @@ -291,7 +294,7 @@ public override MultiValue HandleMethodCall ( // Especially with DAM on type, this can lead to incorrectly analyzed code (as in unknown type which leads // to noise). ILLink has the same problem currently: https://github.com/dotnet/linker/issues/1952 - HandleCall (operation, OwningSymbol, calledMethod, instance, arguments, Location.None, null, _multiValueLattice, out MultiValue methodReturnValue); + HandleCall (_typeNameResolver, operation, OwningSymbol, calledMethod, instance, arguments, Location.None, null, _multiValueLattice, out MultiValue methodReturnValue); // This will copy the values if necessary TrimAnalysisPatterns.Add (new TrimAnalysisMethodCallPattern ( @@ -315,6 +318,7 @@ public override MultiValue HandleMethodCall ( } internal static void HandleCall( + TypeNameResolver typeNameResolver, IOperation operation, ISymbol owningSymbol, IMethodSymbol calledMethod, @@ -325,7 +329,7 @@ internal static void HandleCall( ValueSetLattice multiValueLattice, out MultiValue methodReturnValue) { - var handleCallAction = new HandleCallAction (location, owningSymbol, operation, multiValueLattice, reportDiagnostic); + var handleCallAction = new HandleCallAction (typeNameResolver, location, owningSymbol, operation, multiValueLattice, reportDiagnostic); MethodProxy method = new (calledMethod); var intrinsicId = Intrinsics.GetIntrinsicIdForMethod (method); if (!handleCallAction.Invoke (method, instance, arguments, intrinsicId, out methodReturnValue)) diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TypeNameResolver.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TypeNameResolver.cs new file mode 100644 index 0000000000000..a91797e4316eb --- /dev/null +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/TypeNameResolver.cs @@ -0,0 +1,149 @@ +// 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; +using System.Diagnostics.CodeAnalysis; +using System.Reflection.Metadata; +using Microsoft.CodeAnalysis; +using ILLink.RoslynAnalyzer.TrimAnalysis; +using ILLink.Shared.TypeSystemProxy; +using System.Collections.Immutable; + +namespace ILLink.Shared.TrimAnalysis +{ + internal struct TypeNameResolver + { + readonly Compilation _compilation; + + static readonly TypeNameParseOptions s_typeNameParseOptions = new () { MaxNodes = int.MaxValue }; + + public TypeNameResolver (Compilation compilation) + { + _compilation = compilation; + } + + public bool TryResolveTypeName ( + string typeNameString, + in DiagnosticContext diagnosticContext, + out ITypeSymbol? type, + bool needsAssemblyName) + { + type = null; + if (!TypeName.TryParse (typeNameString.AsSpan (), out TypeName? typeName, s_typeNameParseOptions)) + return false; + + if (needsAssemblyName && !IsFullyQualified (typeName)) { + diagnosticContext.AddDiagnostic (DiagnosticId.TypeNameIsNotAssemblyQualified, typeNameString); + return false; + } + + type = ResolveTypeName (_compilation.Assembly, typeName); + return type != null; + + static bool IsFullyQualified (TypeName typeName) + { + if (typeName.AssemblyName is null) + return false; + + if (typeName.IsArray || typeName.IsPointer || typeName.IsByRef) + return IsFullyQualified (typeName.GetElementType ()); + + if (typeName.IsConstructedGenericType) { + foreach (var arg in typeName.GetGenericArguments ()) { + if (!IsFullyQualified (arg)) + return false; + } + } + + return true; + } + } + + ITypeSymbol? ResolveTypeName (IAssemblySymbol assembly, TypeName typeName) + { + if (typeName.IsSimple) + return GetSimpleType (assembly, typeName); + + if (typeName.IsConstructedGenericType) + return GetGenericType (assembly, typeName); + + if (typeName.IsArray || typeName.IsPointer || typeName.IsByRef) + { + if (ResolveTypeName (assembly, typeName.GetElementType ()) is not ITypeSymbol type) + return null; + + if (typeName.IsArray) + return typeName.IsSZArray ? _compilation.CreateArrayTypeSymbol (type) : _compilation.CreateArrayTypeSymbol (type, typeName.GetArrayRank ()); + + // Roslyn doesn't have a representation for byref types + // (the byrefness is considered part of the symbol, not its type) + if (typeName.IsByRef) + return null; + + if (typeName.IsPointer) + return _compilation.CreatePointerTypeSymbol (type); + + Debug.Fail ("Unreachable"); + return null; + } + + return null; + } + + private ITypeSymbol? GetSimpleType (IAssemblySymbol assembly, TypeName typeName) + { + IAssemblySymbol module = assembly; + if (typeName.AssemblyName is AssemblyNameInfo assemblyName) { + if (ResolveAssembly (assemblyName) is not IAssemblySymbol resolvedAssembly) + return null; + module = resolvedAssembly; + } + + if (GetSimpleTypeFromModule (typeName, module) is ITypeSymbol type) + return type; + + // The analyzer doesn't see the core library, so can't fall back to lookup up types in corelib. + return null; + } + + private static ITypeSymbol? GetSimpleTypeFromModule (TypeName typeName, IAssemblySymbol module) + { + string fullName = TypeNameHelpers.Unescape (typeName.FullName); + return module.GetTypeByMetadataName (fullName); + } + + private ITypeSymbol? GetGenericType (IAssemblySymbol assembly, TypeName typeName) + { + if (ResolveTypeName (assembly, typeName.GetGenericTypeDefinition ()) is not INamedTypeSymbol typeDefinition) + return null; + + ImmutableArray typeArguments = typeName.GetGenericArguments (); + ITypeSymbol[] instantiation = new ITypeSymbol[typeArguments.Length]; + for (int i = 0; i < typeArguments.Length; i++) + { + if (ResolveTypeName (assembly, typeArguments[i]) is not ITypeSymbol type) + return null; + instantiation[i] = type; + } + return typeDefinition.Construct (instantiation); + } + + IAssemblySymbol? ResolveAssembly (AssemblyNameInfo? assemblyName) + { + if (assemblyName is null) + return null; + + if (_compilation.Assembly.Name == assemblyName.Name) + return _compilation.Assembly; + + foreach (var metadataReference in _compilation.References) { + if (_compilation.GetAssemblyOrModuleSymbol (metadataReference) is not IAssemblySymbol asmSym) + continue; + if (asmSym.Name == assemblyName.Name) + return asmSym; + } + return null; + } + } +} diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersCodeFixTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersCodeFixTests.cs index 1f7017bff311b..9468360d24111 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersCodeFixTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DynamicallyAccessedMembersCodeFixTests.cs @@ -101,7 +101,7 @@ class C [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] static string M(Type t) { M2(t); - return "Foo"; + return "Foo, test"; } static void M2([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) {} @@ -117,7 +117,7 @@ class C [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] static string M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) { M2(t); - return "Foo"; + return "Foo, test"; } static void M2([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) {} @@ -187,7 +187,7 @@ class C [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] static string M([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] Type t) { M2(t); - return "Foo"; + return "Foo, test"; } static void M2([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) {} @@ -1067,7 +1067,7 @@ await VerifyDynamicallyAccessedMembersCodeFix ( } [Fact] - public async Task CodeFix_IL2075_ReutrnAttributeLeavesOnCodeFix () + public async Task CodeFix_IL2075_ReturnAttributeLeavesOnCodeFix () { var test = $$$""" namespace System @@ -1078,7 +1078,7 @@ class C : TestSystemTypeBase public static string Main() { GetC().GetMethod("Foo"); - return "Foo"; + return "Foo, test"; } private static Type GetC () @@ -1097,7 +1097,7 @@ class C : TestSystemTypeBase public static string Main() { GetC().GetMethod("Foo"); - return "Foo"; + return "Foo, test"; } [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] @@ -1608,7 +1608,7 @@ public static void Main() private string M1() { M2(this); - return "Foo"; + return "Foo, test"; } private static void M2([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) @@ -1633,7 +1633,7 @@ public static void Main() private string M1() { M2(this); - return "Foo"; + return "Foo, test"; } private static void M2([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) @@ -1676,7 +1676,7 @@ class C : TestSystemTypeBase { public static void Main() { - new C().M1("Foo"); + new C().M1("Foo, test"); } [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] @@ -1700,7 +1700,7 @@ class C : TestSystemTypeBase { public static void Main() { - new C().M1("Foo"); + new C().M1("Foo, test"); } [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)] @@ -1736,7 +1736,7 @@ await VerifyDynamicallyAccessedMembersCodeFix ( // /0/Test0.cs(193,4): warning IL2065: Value passed to implicit 'this' parameter of method 'System.C.M1()' can not be statically determined // and may not meet 'DynamicallyAccessedMembersAttribute' requirements. VerifyCS.Diagnostic(DiagnosticId.ImplicitThisCannotBeStaticallyDetermined) - .WithSpan(193, 4, 193, 21) + .WithSpan(193, 4, 193, 27) .WithArguments("System.C.M1(String)") }); } @@ -1858,7 +1858,7 @@ class C : TestSystemTypeBase { public static void Main() { - new C().M1("Foo"); + new C().M1("Foo, test"); } [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] @@ -1878,7 +1878,7 @@ class C : TestSystemTypeBase { public static void Main() { - new C().M1("Foo"); + new C().M1("Foo, test"); } [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] @@ -1907,7 +1907,7 @@ await VerifyDynamicallyAccessedMembersCodeFix ( // /0/Test0.cs(193,4): warning IL2065: Value passed to implicit 'this' parameter of method 'System.C.M1()' can not be statically determined // and may not meet 'DynamicallyAccessedMembersAttribute' requirements. VerifyCS.Diagnostic(DiagnosticId.ImplicitThisCannotBeStaticallyDetermined) - .WithSpan(193, 4, 193, 21) + .WithSpan(193, 4, 193, 27) .WithArguments("System.C.M1(String)") }); } diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs index 1a51ba8408328..58c57155aaada 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs @@ -44,7 +44,7 @@ public static (CompilationWithAnalyzers Compilation, SemanticModel SemanticModel var sources = new List () { src }; sources.AddRange (additionalSources ?? Array.Empty ()); var comp = CSharpCompilation.Create ( - assemblyName: Guid.NewGuid ().ToString ("N"), + assemblyName: "test", syntaxTrees: sources, references: SourceGenerators.Tests.LiveReferencePack.GetMetadataReferences().Add(mdRef).AddRange(additionalReferences), new CSharpCompilationOptions (consoleApplication ? OutputKind.ConsoleApplication : OutputKind.DynamicallyLinkedLibrary)); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs index c32a472e625bc..85330b4b7e60f 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AssemblyQualifiedNameDataflow.cs @@ -58,7 +58,7 @@ static void TestConstructors () RequireNothing (type); } - [ExpectedWarning ("IL2122", "Type 'System.Invalid.TypeName' is not assembly qualified. " + "Type name strings used for dynamically accessing a type should be assembly qualified.", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2122", "Type 'System.Invalid.TypeName' is not assembly qualified. Type name strings used for dynamically accessing a type should be assembly qualified.")] static void TestUnqualifiedTypeNameWarns () { RequirePublicConstructors ("System.Invalid.TypeName"); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs index b6d5eed8170f1..04746ae30a4dd 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeConstructorDataflow.cs @@ -25,7 +25,7 @@ class AttributeConstructorDataflow [KeepsPublicMethods ("Mono.Linker.Tests.Cases.DataFlow.AttributeConstructorDataflow+ClassWithKeptPublicMethods, test")] [KeepsPublicFields (null, null)] [TypeArray (new Type[] { typeof (AttributeConstructorDataflow) })] - [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/linker/issues/2273")] + [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--")] public static void Main () { typeof (AttributeConstructorDataflow).GetMethod ("Main").GetCustomAttribute (typeof (KeepsPublicConstructorAttribute)); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs index e7683d1f33806..bb3c1d4bebb1a 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributeFieldDataflow.cs @@ -40,7 +40,7 @@ public static void TestKeepsPublicMethods () [Kept] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] - [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--")] [KeepsPublicMethods (TypeName = "Mono.Linker.Tests.Cases.DataFlow.AttributeFieldDataflow+ClassWithKeptPublicMethods, test")] public static void TestKeepsPublicMethodsString () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs index de7186fc7f54a..ba094199740ea 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/AttributePropertyDataflow.cs @@ -55,8 +55,7 @@ public static void TestKeepsPublicMethods () [Kept] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] - // Trimmer/NativeAot only for now - [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethodsKeptByName--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethodsKeptByName--")] [KeepsPublicMethods (TypeName = "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributesOnMethod+ClassWithKeptPublicMethodsKeptByName, test")] public static void TestKeepsPublicMethodsByName () { @@ -211,8 +210,7 @@ class AttributeWithConditionalExpression { [Kept] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] - // Trimmer/NativeAot only for now - [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--")] [KeepsPublicMethods (TypeName = 1 + 1 == 2 ? "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributeWithConditionalExpression+ClassWithKeptPublicMethodsKeptByName, test" : null)] public static void Test () { @@ -224,7 +222,7 @@ public static void Test () // where the owning symbol is not a method. [Kept] [KeptAttributeAttribute (typeof (KeepsPublicMethodsAttribute))] - [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2026", "--ClassWithKeptPublicMethods--")] [KeepsPublicMethods (TypeName = 1 + 1 == 2 ? "Mono.Linker.Tests.Cases.DataFlow.AttributePropertyDataflow+AttributeWithConditionalExpression+ClassWithKeptPublicMethodsKeptByName, test" : null)] public static int field; 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 f28802c174d11..5809d06283532 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 @@ -1372,7 +1372,7 @@ class AnnotatedString { static void MethodWithAnnotatedParameter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] string typeName) { } - [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod")] static void AnnotatedParameter () { MethodWithAnnotatedParameter ("Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[[" @@ -1380,7 +1380,7 @@ static void AnnotatedParameter () + "]], test"); } - [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod")] [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] static string AnnotatedReturnValue () { @@ -1392,7 +1392,7 @@ static string AnnotatedReturnValue () [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] static string _annotatedField; - [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod")] static void AnnotatedField () { _annotatedField = "Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[[" @@ -1410,7 +1410,7 @@ public static void Test () class TypeGetType { - [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2026", "TypeWithRUCMethod.PrivateRUCMethod")] static void SpecificType () { Type.GetType ("Mono.Linker.Tests.Cases.DataFlow.GenericParameterWarningLocation+MethodBody+TypeWithPrivateMethods`1[[" diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs index 31ef05ef3e55b..5bb64c5e9c2cf 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/GetTypeDataFlow.cs @@ -168,8 +168,8 @@ public void Method1 () { } [RequiresUnreferencedCode ("--Method2--")] public void Method2 () { } - [ExpectedWarning ("IL2026", "--Method1--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] - [ExpectedWarning ("IL2026", "--Method2--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2026", "--Method1--")] + [ExpectedWarning ("IL2026", "--Method2--")] public static void Test () { Type.GetType ("Mono.Linker.Tests.Cases.DataFlow." + nameof (GetTypeDataFlow) + "+" + nameof (TypeWithWarnings)).RequiresPublicMethods (); @@ -183,7 +183,7 @@ class OverConstTypeName [RequiresUnreferencedCode ("--Method1--")] public void Method1 () { } - [ExpectedWarning ("IL2026", "--Method1--", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2026", "--Method1--")] public static void Test () { Type.GetType (s_ConstTypeName).RequiresPublicMethods (); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs index 9dc4df8ff039c..2d0e72e03af83 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs @@ -67,6 +67,7 @@ public static void TestNull () { const string reflectionTypeKeptString = null; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] @@ -74,119 +75,180 @@ public static void TestEmptyString () { const string reflectionTypeKeptString = ""; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (Full))] public class Full { } [Kept] + [ExpectedWarning ("IL2026", nameof (Full))] public static void TestFullString () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+Full, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (Generic))] public class Generic { } [Kept] + [ExpectedWarning ("IL2026", "Generic")] public static void TestGenericString () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+Generic`1, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (GenericInstantiation))] public class GenericInstantiation { } [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (GenericArgument))] public class GenericArgument { } [Kept] + [ExpectedWarning ("IL2026", "GenericInstantiation")] public static void TestGenericInstantiation () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericInstantiation`1[[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericArgument]]"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (GenericInstantiationFullString))] public class GenericInstantiationFullString { } [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (GenericArgumentFullString))] public class GenericArgumentFullString { } [Kept] + [ExpectedWarning ("IL2026", "GenericInstantiationFullString")] public static void TestGenericInstantiationFullString () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericInstantiationFullString`1[" + "[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericArgumentFullString, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]" + "], test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (GenericInstantiationOverCoreLib))] public class GenericInstantiationOverCoreLib { } [Kept] + [ExpectedWarning ("IL2026", "GenericInstantiationOverCoreLib", Tool.Trimmer | Tool.NativeAot, "Analyzer can't resolve type names from corelib")] public static void TestGenericInstantiationOverCoreLib () { // Note: the argument type should not be assembly-qualified for this test, which is checking that // we can resolve non-assembly-qualified generic argument types from corelib. const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericInstantiationOverCoreLib`1[[System.String]], test"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (FullConst))] public class FullConst { } [Kept] + [ExpectedWarning ("IL2026", nameof (FullConst))] public static void TestFullStringConst () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+FullConst, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (TypeAsmName))] public class TypeAsmName { } [Kept] + [ExpectedWarning ("IL2026", nameof (TypeAsmName))] public static void TestTypeAsmName () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+TypeAsmName, test"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (AType))] public class AType { } [Kept] + [ExpectedWarning ("IL2026", nameof (AType))] public static void TestType () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AType"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] +#if !NATIVEAOT + [KeptMember (".ctor()")] +#endif + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (Pointer))] public class Pointer { } [Kept] + [ExpectedWarning ("IL2026", nameof (Pointer), Tool.Trimmer, "https://github.com/dotnet/runtime/issues/106214")] public static void TestPointer () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+Pointer*"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] +#if !NATIVEAOT + [KeptMember (".ctor()")] +#endif + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (Reference))] public class Reference { } [Kept] + [ExpectedWarning ("IL2026", nameof (Reference), Tool.Trimmer, "https://github.com/dotnet/runtime/issues/106214")] public static void TestReference () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+Reference&"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (Array))] public class Array { } [Kept] @@ -194,9 +256,12 @@ public static void TestArray () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+Array[]"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (ArrayOfArray))] public class ArrayOfArray { } [Kept] @@ -204,10 +269,13 @@ public static void TestArrayOfArray () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+ArrayOfArray[][]"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (MultiDimensionalArray))] public class MultiDimensionalArray { } [Kept] @@ -215,9 +283,12 @@ public static void TestMultiDimensionalArray () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+MultiDimensionalArray[,]"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (MultiDimensionalArrayFullString))] public class MultiDimensionalArrayFullString { } [Kept] @@ -225,9 +296,12 @@ public static void TestMultiDimensionalArrayFullString () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+MultiDimensionalArrayFullString[,], test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (MultiDimensionalArrayAsmName))] public class MultiDimensionalArrayAsmName { } [Kept] @@ -235,6 +309,7 @@ public static void TestMultiDimensionalArrayAsmName () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+MultiDimensionalArrayAsmName[,], test"; var typeKept = Type.GetType (reflectionTypeKeptString, false); + RequireConstructor (typeKept); } [Kept] @@ -244,6 +319,9 @@ class Nested1 class N2 { [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (N3))] class N3 { } @@ -251,26 +329,39 @@ class N3 } [Kept] + [ExpectedWarning ("IL2026", "N3")] static void TestDeeplyNested () { var typeKept = Type.GetType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+Nested1+N2+N3"); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] class TypeOfToKeep { } [Kept] static void TestTypeOf () { var typeKept = typeof (TypeOfToKeep); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (TypeFromBranchA))] class TypeFromBranchA { } + [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (TypeFromBranchB))] class TypeFromBranchB { } [Kept] + [ExpectedWarning ("IL2026", nameof (TypeFromBranchA))] + [ExpectedWarning ("IL2026", nameof (TypeFromBranchB))] static void TestTypeFromBranch (int b) { string name = null; @@ -286,6 +377,7 @@ static void TestTypeFromBranch (int b) } var typeKept = Type.GetType (name); + RequireConstructor (typeKept); } public class CaseInsensitive { } @@ -308,6 +400,7 @@ static void TestTypeUsingCaseUnknownByTheLinker () bool hideCase = GetCase (); const string reflectionTypeKeptString = "mono.linker.tests.cases.reflection.TypeUsedViaReflection+CaseUnknown, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; var typeKept = Type.GetType (reflectionTypeKeptString, false, hideCase); + RequireConstructor (typeKept); } [Kept] @@ -327,27 +420,38 @@ static void TestTypeUsingCaseUnknownByTheLinker2 () { const string reflectionTypeKeptString = "mono.linker.tests.cases.reflection.TypeUsedViaReflection+CaseUnknown2, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; var typeKept = Type.GetType (reflectionTypeKeptString, false, fieldHideCase); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (OverloadWith3Parameters))] public class OverloadWith3Parameters { } [Kept] + [ExpectedWarning ("IL2026", nameof (OverloadWith3Parameters))] static void TestTypeOverloadWith3Parameters () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+OverloadWith3Parameters"; var typeKept = Type.GetType (reflectionTypeKeptString, AssemblyResolver, GetTypeFromAssembly); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (OverloadWith4Parameters))] public class OverloadWith4Parameters { } [Kept] + [ExpectedWarning ("IL2026", nameof (OverloadWith4Parameters))] static void TestTypeOverloadWith4Parameters () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+OverloadWith4Parameters"; var typeKept = Type.GetType (reflectionTypeKeptString, AssemblyResolver, GetTypeFromAssembly, false); + RequireConstructor (typeKept); } public class OverloadWith5ParametersWithIgnoreCase { } @@ -361,16 +465,22 @@ static void TestTypeOverloadWith5ParametersWithIgnoreCase () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+OverloadWith5ParametersWithIgnoreCase"; var typeKept = Type.GetType (reflectionTypeKeptString, AssemblyResolver, GetTypeFromAssembly, false, true); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (OverloadWith5ParametersWithIgnoreCase))] public class OverloadWith5ParametersWithoutIgnoreCase { } [Kept] + [ExpectedWarning ("IL2026", nameof (OverloadWith5ParametersWithIgnoreCase))] static void TestTypeOverloadWith5ParametersWithoutIgnoreCase () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+OverloadWith5ParametersWithoutIgnoreCase"; var typeKept = Type.GetType (reflectionTypeKeptString, AssemblyResolver, GetTypeFromAssembly, false, false); + RequireConstructor (typeKept); } /// @@ -415,16 +525,22 @@ static void TestUnknownIgnoreCase5Params (int num) const string reflectionTypeKeptString = "mono.linker.tests.cases.reflection.TypeUsedViaReflection+CaseUnknown2, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; bool unknownValue = num + 1 == 1; var typeKept = Type.GetType (reflectionTypeKeptString, AssemblyResolver, GetTypeFromAssembly, false, unknownValue); + RequireConstructor (typeKept); } [Kept] + [KeptMember (".ctor()")] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode ("GenericTypeWithAnnotations_OuterType")] public class GenericTypeWithAnnotations_OuterType< [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] - [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicProperties)] T> + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicProperties)] T> { } [Kept] + [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] + [RequiresUnreferencedCode (nameof (GenericTypeWithAnnotations_InnerType))] public class GenericTypeWithAnnotations_InnerType { [Kept] @@ -435,12 +551,16 @@ private static void PrivateMethod () { } } [Kept] + [ExpectedWarning ("IL2026", "GenericTypeWithAnnotations_OuterType")] + [ExpectedWarning ("IL2026", nameof (GenericTypeWithAnnotations_InnerType), "PrivateProperty.get")] + [ExpectedWarning ("IL2026", nameof (GenericTypeWithAnnotations_InnerType), "PrivateProperty.set")] static void TestGenericTypeWithAnnotations () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericTypeWithAnnotations_OuterType`1[" + "[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericTypeWithAnnotations_InnerType, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]" + "], test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; - Type.GetType (reflectionTypeKeptString); + var typeKept = Type.GetType (reflectionTypeKeptString); + RequireConstructor (typeKept); } [Kept] @@ -493,33 +613,36 @@ static void TestInvalidTypeCombination () static void TestEscapedTypeName () { var typeKept = Type.GetType ("Library.Not\\+Nested, EscapedTypeNames"); + RequireConstructor (typeKept); typeKept = Type.GetType ("Library.Not\\+Nested+Nes\\\\ted, EscapedTypeNames"); + RequireConstructor (typeKept); typeKept = Type.GetType ("Library.Not\\+Nested+Nes/ted, EscapedTypeNames"); + RequireConstructor (typeKept); } [Kept] class AssemblyTypeResolutionBehavior { [Kept] - [ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2122")] static void TestRequireTypeInSameAssemblyAsGetType () { RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.Dependencies.TypeDefinedInSameAssemblyAsGetType"); } [Kept] - [ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2122")] static void TestRequireTypeInSameAssemblyAsCallToRequireType () { RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+TypeDefinedInSameAssemblyAsCallToRequireType"); } [Kept] - [ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2122")] static void TestRequireTypeWithNonAssemblyQualifiedGenericArguments () { RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+Generic`1[[System.Int32]], test"); } [Kept] - [ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2122")] static void TestRequireTypeWithNonAssemblyQualifiedArrayType () { RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+Generic`1[" + "[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+ArrayElementGenericArgumentType]" @@ -527,7 +650,7 @@ static void TestRequireTypeWithNonAssemblyQualifiedArrayType () { } [Kept] - [ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2122")] static void TestRequireTypeWithNonAssemblyQualifiedPointerType () { RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+Generic`1[" + "[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+PointerElementGenericArgumentType]" @@ -535,7 +658,7 @@ static void TestRequireTypeWithNonAssemblyQualifiedPointerType () { } [Kept] - [ExpectedWarning ("IL2122", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")] + [ExpectedWarning ("IL2122")] static void TestRequireTypeWithNonAssemblyQualifiedByRefType () { RequireHelper.RequireType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+Generic`1[" + "[Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AssemblyTypeResolutionBehavior+ByRefElementGenericArgumentType]" @@ -562,5 +685,11 @@ class PointerElementGenericArgumentType {} class ByRefElementGenericArgumentType {} } + + [Kept] + static void RequireConstructor ( + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] + Type type) { } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs index acf9bf7a2b14d..71f4b173eb30b 100644 --- a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs +++ b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -1045,7 +1045,6 @@ void VerifyLoggedMessages (AssemblyDefinition original, TrimmingTestLogger logge int? unexpectedWarningCodeNumber = unexpectedWarningCode == null ? null : int.Parse (unexpectedWarningCode.Substring (2)); - MessageContainer? unexpectedWarningMessage = null; foreach (var mc in unmatchedMessages) { if (mc.Category != MessageCategory.Warning) continue; @@ -1057,12 +1056,7 @@ void VerifyLoggedMessages (AssemblyDefinition original, TrimmingTestLogger logge if (attrProvider is IMemberDefinition attrMember && (mc.Origin?.Provider is IMemberDefinition member) && member.FullName.Contains (attrMember.FullName) != true) continue; - unexpectedWarningMessage = mc; - break; - } - - if (unexpectedWarningMessage is not null) { - unexpectedMessageWarnings.Add ($"Unexpected warning found: {unexpectedWarningMessage}"); + unexpectedMessageWarnings.Add ($"Unexpected warning found: {mc}"); } }