This commit is contained in:
Sven Boemer 2025-07-30 22:31:50 +08:00 committed by GitHub
commit b19f61f17a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 359 additions and 109 deletions

View File

@ -57,6 +57,7 @@ namespace ILLink.RoslynAnalyzer
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));
diagDescriptorsArrayBuilder.Add(DiagnosticDescriptors.GetDiagnosticDescriptor(DiagnosticId.TypeMapGroupTypeCannotBeStaticallyDetermined));
@ -130,13 +131,14 @@ namespace ILLink.RoslynAnalyzer
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);
DynamicallyAccessedMembersTypeHierarchy.ApplyDynamicallyAccessedMembersToTypeHierarchy(location, type, context.ReportDiagnostic);
DynamicallyAccessedMembersTypeHierarchy.ApplyDynamicallyAccessedMembersToTypeHierarchy(typeNameResolver, location, type, context.ReportDiagnostic);
}, SymbolKind.NamedType);
context.RegisterSymbolAction(context =>
{

View File

@ -10,16 +10,20 @@ using Microsoft.CodeAnalysis;
namespace ILLink.RoslynAnalyzer
{
internal sealed class DynamicallyAccessedMembersTypeHierarchy
sealed class DynamicallyAccessedMembersTypeHierarchy
{
public static void ApplyDynamicallyAccessedMembersToTypeHierarchy(Location typeLocation, INamedTypeSymbol type, Action<Diagnostic> reportDiagnostic)
public static void ApplyDynamicallyAccessedMembersToTypeHierarchy(
TypeNameResolver typeNameResolver,
Location typeLocation,
INamedTypeSymbol type,
Action<Diagnostic> 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);
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer(reportDiagnostic, typeNameResolver, type);
if (type.BaseType is INamedTypeSymbol baseType)
{
var baseAnnotation = FlowAnnotations.GetTypeAnnotation(baseType);

View File

@ -15,10 +15,12 @@
optimize the analyzer even in Debug builds. Note: we still use the
Debug configuration to get Debug asserts. -->
<Optimize>true</Optimize>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(CoreLibSharedDir)System/Index.cs" />
<Compile Include="$(LibrariesProjectRoot)\Common\src\System\Text\ValueStringBuilder.cs" />
</ItemGroup>
<ItemGroup>
@ -28,6 +30,7 @@
<PrivateAssets>all</PrivateAssets>
<ExcludeAssets>contentfiles</ExcludeAssets> <!-- We include our own copy of the ClosedAttribute to work in source build -->
</PackageReference>
<PackageReference Include="System.Reflection.Metadata" Version="$(SystemReflectionMetadataVersion)" />
</ItemGroup>
<Import Project="..\ILLink.Shared\ILLink.Shared.projitems" Label="Shared" />

View File

@ -12,37 +12,38 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
{
internal static class GenericArgumentDataFlow
{
public static void ProcessGenericArgumentDataFlow(Location location, INamedTypeSymbol type, Action<Diagnostic> reportDiagnostic)
public static void ProcessGenericArgumentDataFlow(TypeNameResolver typeNameResolver, Location location, INamedTypeSymbol type, Action<Diagnostic>? reportDiagnostic)
{
while (type is { IsGenericType: true })
{
ProcessGenericArgumentDataFlow(location, type.TypeArguments, type.TypeParameters, reportDiagnostic);
ProcessGenericArgumentDataFlow(typeNameResolver, location, type.TypeArguments, type.TypeParameters, reportDiagnostic);
type = type.ContainingType;
}
}
public static void ProcessGenericArgumentDataFlow(Location location, IMethodSymbol method, Action<Diagnostic> reportDiagnostic)
public static void ProcessGenericArgumentDataFlow(TypeNameResolver typeNameResolver, Location location, IMethodSymbol method, Action<Diagnostic>? 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<Diagnostic> reportDiagnostic)
public static void ProcessGenericArgumentDataFlow(TypeNameResolver typeNameResolver, Location location, IFieldSymbol field, Action<Diagnostic>? reportDiagnostic)
{
ProcessGenericArgumentDataFlow(location, field.ContainingType, reportDiagnostic);
ProcessGenericArgumentDataFlow(typeNameResolver, location, field.ContainingType, reportDiagnostic);
}
public static void ProcessGenericArgumentDataFlow(Location location, IPropertySymbol property, Action<Diagnostic> reportDiagnostic)
public static void ProcessGenericArgumentDataFlow(TypeNameResolver typeNameResolver, Location location, IPropertySymbol property, Action<Diagnostic> reportDiagnostic)
{
ProcessGenericArgumentDataFlow(location, property.ContainingType, reportDiagnostic);
ProcessGenericArgumentDataFlow(typeNameResolver, location, property.ContainingType, reportDiagnostic);
}
private static void ProcessGenericArgumentDataFlow(
TypeNameResolver typeNameResolver,
Location location,
ImmutableArray<ITypeSymbol> typeArguments,
ImmutableArray<ITypeParameterSymbol> typeParameters,
Action<Diagnostic> reportDiagnostic)
Action<Diagnostic>? reportDiagnostic)
{
var diagnosticContext = new DiagnosticContext(location, reportDiagnostic);
for (int i = 0; i < typeArguments.Length; i++)
@ -53,14 +54,14 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
if (genericParameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None)
{
SingleValue genericArgumentValue = SingleValueExtensions.FromTypeSymbol(typeArgument)!;
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer(reportDiagnostic, typeHierarchyType: null);
var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(diagnosticContext, reflectionAccessAnalyzer);
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer(reportDiagnostic, typeNameResolver, typeHierarchyType: null);
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);
}
}

View File

@ -28,6 +28,7 @@ namespace ILLink.Shared.TrimAnalysis
private ValueSetLattice<SingleValue> _multiValueLattice;
public HandleCallAction(
TypeNameResolver typeNameResolver,
Location location,
ISymbol owningSymbol,
IOperation operation,
@ -39,8 +40,8 @@ namespace ILLink.Shared.TrimAnalysis
_isNewObj = operation.Kind == OperationKind.ObjectCreation;
_diagnosticContext = new DiagnosticContext(location, reportDiagnostic);
_annotations = FlowAnnotations.Instance;
_reflectionAccessAnalyzer = new(reportDiagnostic, typeHierarchyType: null);
_requireDynamicallyAccessedMembersAction = new(_diagnosticContext, _reflectionAccessAnalyzer);
_reflectionAccessAnalyzer = new(reportDiagnostic, typeNameResolver, typeHierarchyType: null);
_requireDynamicallyAccessedMembersAction = new(typeNameResolver, location, reportDiagnostic, _reflectionAccessAnalyzer);
_multiValueLattice = multiValueLattice;
}

View File

@ -12,15 +12,22 @@ using Microsoft.CodeAnalysis;
namespace ILLink.RoslynAnalyzer.TrimAnalysis
{
internal readonly struct ReflectionAccessAnalyzer
readonly struct ReflectionAccessAnalyzer
{
private readonly Action<Diagnostic>? _reportDiagnostic;
private readonly INamedTypeSymbol? _typeHierarchyType;
readonly Action<Diagnostic>? _reportDiagnostic;
public ReflectionAccessAnalyzer(Action<Diagnostic>? reportDiagnostic, INamedTypeSymbol? typeHierarchyType)
readonly INamedTypeSymbol? _typeHierarchyType;
readonly TypeNameResolver _typeNameResolver;
public ReflectionAccessAnalyzer(
Action<Diagnostic>? reportDiagnostic,
TypeNameResolver typeNameResolver,
INamedTypeSymbol? typeHierarchyType)
{
_reportDiagnostic = reportDiagnostic;
_typeHierarchyType = typeHierarchyType;
_typeNameResolver = typeNameResolver;
}
#pragma warning disable CA1822 // Mark members as static - the other partial implementations might need to be instance methods
@ -212,5 +219,10 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
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);
}
}
}

View File

@ -1,40 +1,56 @@
// 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
{
private readonly ReflectionAccessAnalyzer _reflectionAccessAnalyzer;
readonly Location _location;
readonly Action<Diagnostic>? _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<Diagnostic>? 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);
}
}

View File

@ -54,7 +54,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
public void ReportDiagnostics(DataFlowAnalyzerContext context, Action<Diagnostic> reportDiagnostic)
{
var diagnosticContext = new DiagnosticContext(Operation.Syntax.GetLocation(), reportDiagnostic);
var location = Operation.Syntax.GetLocation();
if (context.EnableTrimAnalyzer &&
!OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope(out _) &&
!FeatureContext.IsEnabled(RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute))
@ -68,8 +68,9 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
if (targetValue is not ValueWithDynamicallyAccessedMembers targetWithDynamicallyAccessedMembers)
throw new NotImplementedException();
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer(reportDiagnostic, typeHierarchyType: null);
var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(diagnosticContext, reflectionAccessAnalyzer);
var typeNameResolver = new TypeNameResolver(context.Compilation);
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer(reportDiagnostic, typeNameResolver, typeHierarchyType: null);
var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction(typeNameResolver, location, reportDiagnostic, reflectionAccessAnalyzer);
requireDynamicallyAccessedMembersAction.Invoke(sourceValue, targetWithDynamicallyAccessedMembers);
}
}

View File

@ -50,18 +50,19 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
!FeatureContext.IsEnabled(RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute))
{
var location = Operation.Syntax.GetLocation();
var typeNameResolver = new TypeNameResolver(context.Compilation);
switch (GenericInstantiation)
{
case INamedTypeSymbol type:
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(location, type, reportDiagnostic);
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(typeNameResolver, location, type, reportDiagnostic);
break;
case IMethodSymbol method:
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(location, method, reportDiagnostic);
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(typeNameResolver, location, method, reportDiagnostic);
break;
case IFieldSymbol field:
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(location, field, reportDiagnostic);
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow(typeNameResolver, location, field, reportDiagnostic);
break;
}
}

View File

@ -82,7 +82,8 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
!OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope(out _) &&
!FeatureContext.IsEnabled(RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute))
{
TrimAnalysisVisitor.HandleCall(Operation, OwningSymbol, CalledMethod, Instance, Arguments, location, reportDiagnostic, default, out var _);
var typeNameResolver = new TypeNameResolver(context.Compilation);
TrimAnalysisVisitor.HandleCall(typeNameResolver, Operation, OwningSymbol, CalledMethod, Instance, Arguments, location, reportDiagnostic, default, out var _);
}
// For Requires, make the location the reference to the method, not the entire invocation.
// The parameters are not part of the issue, and including them in the location can be misleading.

View File

@ -46,7 +46,8 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
public void ReportDiagnostics(DataFlowAnalyzerContext context, Action<Diagnostic> reportDiagnostic)
{
var location = Operation.Syntax.GetLocation();
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer(reportDiagnostic, typeHierarchyType: null);
var typeNameResolver = new TypeNameResolver(context.Compilation);
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer(reportDiagnostic, typeNameResolver, typeHierarchyType: null);
if (context.EnableTrimAnalyzer &&
!OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope(out _) &&
!FeatureContext.IsEnabled(RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute))

View File

@ -43,6 +43,8 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
private FeatureChecksVisitor _featureChecksVisitor;
readonly TypeNameResolver _typeNameResolver;
public TrimAnalysisVisitor(
Compilation compilation,
LocalStateAndContextLattice<MultiValue, FeatureContext, ValueSetLattice<SingleValue>, FeatureContextLattice> lattice,
@ -57,6 +59,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
_multiValueLattice = lattice.LocalStateLattice.Lattice.ValueLattice;
TrimAnalysisPatterns = trimAnalysisPatterns;
_featureChecksVisitor = new FeatureChecksVisitor(dataFlowAnalyzerContext);
_typeNameResolver = new TypeNameResolver(compilation);
}
public override FeatureChecksValue GetConditionValue(IOperation branchValueOperation, StateValue state)
@ -331,7 +334,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
// 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(
@ -359,6 +362,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
}
internal static void HandleCall(
TypeNameResolver typeNameResolver,
IOperation operation,
ISymbol owningSymbol,
IMethodSymbol calledMethod,
@ -369,7 +373,7 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
ValueSetLattice<SingleValue> 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))

View File

@ -0,0 +1,58 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Metadata;
using System.Text;
namespace System.Reflection.Metadata
{
// Once Roslyn references System.Reflection.Metadata 10.0.0 or later,
// we can replace this with TypeName.Unescape.
internal static class TypeNameHelpers
{
private const char EscapeCharacter = '\\';
/// <summary>
/// Removes escape characters from the string (if there were any found).
/// </summary>
internal static string Unescape(string name)
{
int indexOfEscapeCharacter = name.IndexOf(EscapeCharacter);
if (indexOfEscapeCharacter < 0)
{
return name;
}
return Unescape(name, indexOfEscapeCharacter);
static string Unescape(string name, int indexOfEscapeCharacter)
{
// this code path is executed very rarely (IL Emit or pure IL with chars not allowed in C# or F#)
var sb = new ValueStringBuilder(stackalloc char[64]);
sb.EnsureCapacity(name.Length);
sb.Append(name.AsSpan(0, indexOfEscapeCharacter));
for (int i = indexOfEscapeCharacter; i < name.Length;)
{
char c = name[i++];
if (c != EscapeCharacter)
{
sb.Append(c);
}
else if (i < name.Length && name[i] == EscapeCharacter) // escaped escape character ;)
{
sb.Append(c);
// Consume the escaped escape character, it's important for edge cases
// like escaped escape character followed by another escaped char (example: "\\\\\\+")
i++;
}
}
return sb.ToString();
}
}
}
}

View File

@ -0,0 +1,154 @@
// 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<TypeName> 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;
}
}
}

View File

@ -103,7 +103,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)]
static string M(Type t) {
M2(t);
return "Foo";
return "Foo, test";
}
static void M2([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t) {}
@ -119,7 +119,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
[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) {}
@ -189,7 +189,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
[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) {}
@ -1069,7 +1069,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
}
[Fact]
public async Task CodeFix_IL2075_ReutrnAttributeLeavesOnCodeFix()
public async Task CodeFix_IL2075_ReturnAttributeLeavesOnCodeFix()
{
var test = $$$"""
namespace System
@ -1080,7 +1080,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
public static string Main()
{
GetC().GetMethod("Foo");
return "Foo";
return "Foo, test";
}
private static Type GetC()
@ -1099,7 +1099,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
public static string Main()
{
GetC().GetMethod("Foo");
return "Foo";
return "Foo, test";
}
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
@ -1610,7 +1610,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
private string M1()
{
M2(this);
return "Foo";
return "Foo, test";
}
private static void M2([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t)
@ -1635,7 +1635,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
private string M1()
{
M2(this);
return "Foo";
return "Foo, test";
}
private static void M2([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type t)
@ -1678,7 +1678,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
{
public static void Main()
{
new C().M1("Foo");
new C().M1("Foo, test");
}
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)]
@ -1702,7 +1702,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
{
public static void Main()
{
new C().M1("Foo");
new C().M1("Foo, test");
}
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicMethods)]
@ -1738,7 +1738,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
// /0/Test0.cs(193,4): warning IL2065: Value passed to implicit 'this' parameter of method 'System.C.M1(String)' can not be statically determined
// and may not meet 'DynamicallyAccessedMembersAttribute' requirements.
VerifyCS.Diagnostic(DiagnosticId.ImplicitThisCannotBeStaticallyDetermined)
.WithSpan(193, 13, 193, 30)
.WithSpan(193, 13, 193, 36)
.WithArguments("System.C.M1(String)")
});
}
@ -1860,7 +1860,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
{
public static void Main()
{
new C().M1("Foo");
new C().M1("Foo, test");
}
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
@ -1880,7 +1880,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
{
public static void Main()
{
new C().M1("Foo");
new C().M1("Foo, test");
}
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)]
@ -1909,7 +1909,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true")));
// /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, 13, 193, 30)
.WithSpan(193, 13, 193, 36)
.WithArguments("System.C.M1(String)")
});
}

View File

@ -60,7 +60,7 @@ namespace ILLink.RoslynAnalyzer.Tests
sources.AddRange(commonSourcePaths.Select(p => CSharpSyntaxTree.ParseText(File.ReadAllText(p), path: p)));
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,

View File

@ -58,7 +58,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
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");

View File

@ -25,7 +25,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[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));

View File

@ -40,7 +40,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[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()
{

View File

@ -56,8 +56,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[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()
{
@ -213,8 +212,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
{
[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()
{
@ -226,7 +224,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
// 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;

View File

@ -1412,7 +1412,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
{
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[["
@ -1420,7 +1420,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
+ "]], 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()
{
@ -1432,7 +1432,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[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[["
@ -1450,7 +1450,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
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[["

View File

@ -170,8 +170,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[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();
@ -185,7 +185,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow
[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();

View File

@ -86,7 +86,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
public class Full { }
[Kept]
[ExpectedWarning("IL2026", nameof(Full), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[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";
@ -101,7 +101,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
public class Generic<T> { }
[Kept]
[ExpectedWarning("IL2026", "Generic", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[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";
@ -121,7 +121,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
public class GenericArgument { }
[Kept]
[ExpectedWarning("IL2026", "GenericInstantiation", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[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]]";
@ -141,7 +141,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
public class GenericArgumentFullString { }
[Kept]
[ExpectedWarning("IL2026", "GenericInstantiationFullString", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning("IL2026", "GenericInstantiationFullString")]
public static void TestGenericInstantiationFullString()
{
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+GenericInstantiationFullString`1["
@ -158,7 +158,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
public class GenericInstantiationOverCoreLib<T> { }
[Kept]
[ExpectedWarning("IL2026", "GenericInstantiationOverCoreLib", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[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
@ -175,7 +175,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
public class FullConst { }
[Kept]
[ExpectedWarning("IL2026", nameof(FullConst), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[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";
@ -190,7 +190,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
public class TypeAsmName { }
[Kept]
[ExpectedWarning("IL2026", nameof(TypeAsmName), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning("IL2026", nameof(TypeAsmName))]
public static void TestTypeAsmName()
{
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+TypeAsmName, test";
@ -205,7 +205,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
public class AType { }
[Kept]
[ExpectedWarning("IL2026", nameof(AType), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning("IL2026", nameof(AType))]
public static void TestType()
{
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+AType";
@ -322,7 +322,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
}
[Kept]
[ExpectedWarning("IL2026", "N3", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning("IL2026", "N3")]
static void TestDeeplyNested()
{
var typeKept = Type.GetType("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+Nested1+N2+N3");
@ -353,8 +353,8 @@ namespace Mono.Linker.Tests.Cases.Reflection
class TypeFromBranchB { }
[Kept]
[ExpectedWarning("IL2026", nameof(TypeFromBranchA), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning("IL2026", nameof(TypeFromBranchB), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning("IL2026", nameof(TypeFromBranchA))]
[ExpectedWarning("IL2026", nameof(TypeFromBranchB))]
static void TestTypeFromBranch(int b)
{
string name = null;
@ -424,7 +424,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
public class OverloadWith3Parameters { }
[Kept]
[ExpectedWarning("IL2026", nameof(OverloadWith3Parameters), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning("IL2026", nameof(OverloadWith3Parameters))]
static void TestTypeOverloadWith3Parameters()
{
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+OverloadWith3Parameters";
@ -436,11 +436,11 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept]
[KeptMember(".ctor()")]
[KeptAttributeAttribute(typeof(RequiresUnreferencedCodeAttribute))]
[RequiresUnreferencedCode(nameof(OverloadWith3Parameters))]
[RequiresUnreferencedCode(nameof(OverloadWith4Parameters))]
public class OverloadWith4Parameters { }
[Kept]
[ExpectedWarning("IL2026", nameof(OverloadWith4Parameters), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning("IL2026", nameof(OverloadWith4Parameters))]
static void TestTypeOverloadWith4Parameters()
{
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+OverloadWith4Parameters";
@ -465,11 +465,11 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept]
[KeptMember(".ctor()")]
[KeptAttributeAttribute(typeof(RequiresUnreferencedCodeAttribute))]
[RequiresUnreferencedCode(nameof(OverloadWith3Parameters))]
[RequiresUnreferencedCode(nameof(OverloadWith5ParametersWithIgnoreCase))]
public class OverloadWith5ParametersWithoutIgnoreCase { }
[Kept]
[ExpectedWarning("IL2026", nameof(OverloadWith5ParametersWithoutIgnoreCase), Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning("IL2026", nameof(OverloadWith5ParametersWithIgnoreCase))]
static void TestTypeOverloadWith5ParametersWithoutIgnoreCase()
{
const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+OverloadWith5ParametersWithoutIgnoreCase";
@ -525,7 +525,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept]
[KeptMember(".ctor()")]
[KeptAttributeAttribute(typeof(RequiresUnreferencedCodeAttribute))]
[RequiresUnreferencedCode(nameof(OverloadWith3Parameters))]
[RequiresUnreferencedCode("GenericTypeWithAnnotations_OuterType")]
public class GenericTypeWithAnnotations_OuterType<
[KeptAttributeAttribute(typeof(DynamicallyAccessedMembersAttribute))]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicProperties)] T>
@ -534,7 +534,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept]
[KeptAttributeAttribute(typeof(RequiresUnreferencedCodeAttribute))]
[RequiresUnreferencedCode(nameof(OverloadWith3Parameters))]
[RequiresUnreferencedCode(nameof(GenericTypeWithAnnotations_InnerType))]
public class GenericTypeWithAnnotations_InnerType
{
[Kept]
@ -545,9 +545,9 @@ namespace Mono.Linker.Tests.Cases.Reflection
}
[Kept]
[ExpectedWarning("IL2026", "GenericTypeWithAnnotations_OuterType", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning("IL2026", nameof(GenericTypeWithAnnotations_InnerType), "PrivateProperty.get", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[ExpectedWarning("IL2026", nameof(GenericTypeWithAnnotations_InnerType), "PrivateProperty.set", Tool.Trimmer | Tool.NativeAot, "https://github.com/dotnet/runtime/issues/95118")]
[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["
@ -620,28 +620,28 @@ namespace Mono.Linker.Tests.Cases.Reflection
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["
@ -650,7 +650,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
}
[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["
@ -659,7 +659,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
}
[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["

View File

@ -1148,7 +1148,6 @@ namespace Mono.Linker.Tests.TestCasesRunner
int? unexpectedWarningCodeNumber = unexpectedWarningCode == null ? null : int.Parse(unexpectedWarningCode.Substring(2));
MessageContainer? unexpectedWarningMessage = null;
foreach (var mc in unmatchedMessages)
{
if (mc.Category != MessageCategory.Warning)
@ -1161,13 +1160,7 @@ namespace Mono.Linker.Tests.TestCasesRunner
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}");
}
}