mirror of https://github.com/dotnet/runtime
Merge 00e5fccdc0
into 02596ba8d9
This commit is contained in:
commit
b19f61f17a
|
@ -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 =>
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)")
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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[["
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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["
|
||||
|
|
|
@ -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}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue