Skip to content

Revert "Implement type name resolution for ILLink analyzer" #106343

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ public static ImmutableArray<DiagnosticDescriptor> GetSupportedDiagnostics ()
diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.UnrecognizedTypeNameInTypeGetType));
diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.UnrecognizedParameterInMethodCreateInstance));
diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.ParametersOfAssemblyCreateInstanceCannotBeAnalyzed));
diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.TypeNameIsNotAssemblyQualified));
diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.ReturnValueDoesNotMatchFeatureGuards));
diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.InvalidFeatureGuard));

Expand Down Expand Up @@ -118,12 +117,11 @@ public override void Initialize (AnalysisContext context)

var location = GetPrimaryLocation (type.Locations);

var typeNameResolver = new TypeNameResolver (context.Compilation);
if (type.BaseType is INamedTypeSymbol baseType)
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (typeNameResolver, location, baseType, context.ReportDiagnostic);
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, baseType, context.ReportDiagnostic);

foreach (var interfaceType in type.Interfaces)
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (typeNameResolver, location, interfaceType, context.ReportDiagnostic);
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, interfaceType, context.ReportDiagnostic);
}, SymbolKind.NamedType);
context.RegisterSymbolAction (context => {
VerifyMemberOnlyApplyToTypesOrStrings (context, context.Symbol);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,10 @@
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\Reflection\Metadata\TypeNameHelpers.cs" />
<Compile Include="$(LibrariesProjectRoot)\Common\src\System\Text\ValueStringBuilder.cs" />
</ItemGroup>

<ItemGroup>
Expand All @@ -31,7 +28,6 @@
<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" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,28 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
{
internal static class GenericArgumentDataFlow
{
public static void ProcessGenericArgumentDataFlow (TypeNameResolver typeNameResolver, Location location, INamedTypeSymbol type, Action<Diagnostic>? reportDiagnostic)
public static void ProcessGenericArgumentDataFlow (Location location, INamedTypeSymbol type, Action<Diagnostic> reportDiagnostic)
{
ProcessGenericArgumentDataFlow (typeNameResolver, location, type.TypeArguments, type.TypeParameters, reportDiagnostic);
ProcessGenericArgumentDataFlow (location, type.TypeArguments, type.TypeParameters, reportDiagnostic);
}

public static void ProcessGenericArgumentDataFlow (TypeNameResolver typeNameResolver, Location location, IMethodSymbol method, Action<Diagnostic>? reportDiagnostic)
public static void ProcessGenericArgumentDataFlow (Location location, IMethodSymbol method, Action<Diagnostic> reportDiagnostic)
{
ProcessGenericArgumentDataFlow (typeNameResolver, location, method.TypeArguments, method.TypeParameters, reportDiagnostic);
ProcessGenericArgumentDataFlow (location, method.TypeArguments, method.TypeParameters, reportDiagnostic);

ProcessGenericArgumentDataFlow (typeNameResolver, location, method.ContainingType, reportDiagnostic);
ProcessGenericArgumentDataFlow (location, method.ContainingType, reportDiagnostic);
}

public static void ProcessGenericArgumentDataFlow (TypeNameResolver typeNameResolver, Location location, IFieldSymbol field, Action<Diagnostic>? reportDiagnostic)
public static void ProcessGenericArgumentDataFlow (Location location, IFieldSymbol field, Action<Diagnostic> reportDiagnostic)
{
ProcessGenericArgumentDataFlow (typeNameResolver, location, field.ContainingType, reportDiagnostic);
ProcessGenericArgumentDataFlow (location, field.ContainingType, reportDiagnostic);
}

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++) {
Expand All @@ -43,14 +42,14 @@ static void ProcessGenericArgumentDataFlow (
var genericParameterValue = new GenericParameterValue (typeParameters[i]);
if (genericParameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) {
SingleValue genericArgumentValue = SingleValueExtensions.FromTypeSymbol (typeArgument)!;
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic, typeNameResolver);
var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (typeNameResolver, location, reportDiagnostic, reflectionAccessAnalyzer);
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic);
var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (diagnosticContext, 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 (typeNameResolver, location, namedTypeArgument, reportDiagnostic);
ProcessGenericArgumentDataFlow (location, namedTypeArgument, reportDiagnostic);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ internal partial struct HandleCallAction
ValueSetLattice<SingleValue> _multiValueLattice;

public HandleCallAction (
TypeNameResolver typeNameResolver,
Location location,
ISymbol owningSymbol,
IOperation operation,
Expand All @@ -40,8 +39,8 @@ public HandleCallAction (
_isNewObj = operation.Kind == OperationKind.ObjectCreation;
_diagnosticContext = new DiagnosticContext (location, reportDiagnostic);
_annotations = FlowAnnotations.Instance;
_reflectionAccessAnalyzer = new (reportDiagnostic, typeNameResolver);
_requireDynamicallyAccessedMembersAction = new (typeNameResolver, location, reportDiagnostic, _reflectionAccessAnalyzer);
_reflectionAccessAnalyzer = new (reportDiagnostic);
_requireDynamicallyAccessedMembersAction = new (_diagnosticContext, _reflectionAccessAnalyzer);
_multiValueLattice = multiValueLattice;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,8 @@ namespace ILLink.RoslynAnalyzer.TrimAnalysis
readonly struct ReflectionAccessAnalyzer
{
readonly Action<Diagnostic>? _reportDiagnostic;
readonly TypeNameResolver _typeNameResolver;

public ReflectionAccessAnalyzer (
Action<Diagnostic>? reportDiagnostic,
TypeNameResolver typeNameResolver)
{
_reportDiagnostic = reportDiagnostic;
_typeNameResolver = typeNameResolver;
}
public ReflectionAccessAnalyzer (Action<Diagnostic>? reportDiagnostic) => _reportDiagnostic = reportDiagnostic;

#pragma warning disable CA1822 // Mark members as static - the other partial implementations might need to be instance methods
internal void GetReflectionAccessDiagnostics (Location location, ITypeSymbol typeSymbol, DynamicallyAccessedMemberTypes requiredMemberTypes, bool declaredOnly = false)
Expand Down Expand Up @@ -145,10 +138,5 @@ void GetDiagnosticsForField (Location location, IFieldSymbol fieldSymbol)
diagnosticContext.AddDiagnostic (DiagnosticId.DynamicallyAccessedMembersFieldAccessedViaReflection, fieldSymbol.GetDisplayName ());
}
}

internal bool TryResolveTypeNameAndMark (string typeName, in DiagnosticContext diagnosticContext, bool needsAssemblyName, [NotNullWhen (true)] out ITypeSymbol? type)
{
return _typeNameResolver.TryResolveTypeName (typeName, diagnosticContext, out type, needsAssemblyName);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,55 +1,40 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection.Metadata;
using Microsoft.CodeAnalysis;
using ILLink.RoslynAnalyzer.TrimAnalysis;
using ILLink.Shared.TypeSystemProxy;
using System.Collections.Immutable;

namespace ILLink.Shared.TrimAnalysis
{
internal partial struct RequireDynamicallyAccessedMembersAction
{
readonly Location _location;
readonly Action<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 (
TypeNameResolver typeNameResolver,
Location location,
Action<Diagnostic>? reportDiagnostic,
DiagnosticContext diagnosticContext,
ReflectionAccessAnalyzer reflectionAccessAnalyzer)
{
_typeNameResolver = typeNameResolver;
_location = location;
_reportDiagnostic = reportDiagnostic;
_diagnosticContext = diagnosticContext;
_reflectionAccessAnalyzer = reflectionAccessAnalyzer;
_diagnosticContext = new (location, reportDiagnostic);
}

public partial bool TryResolveTypeNameAndMark (string typeName, bool needsAssemblyName, out TypeProxy type)
{
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);
// TODO: Implement type name resolution to type symbol
// https://github.com/dotnet/runtime/issues/95118

type = new TypeProxy (foundType);
return true;
}
// 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 = default;
return false;
}

private partial void MarkTypeForDynamicallyAccessedMembers (in TypeProxy type, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes) =>
_reflectionAccessAnalyzer.GetReflectionAccessDiagnostics (_location, type.Type, dynamicallyAccessedMemberTypes);
_reflectionAccessAnalyzer.GetReflectionAccessDiagnostics (_diagnosticContext.Location, type.Type, dynamicallyAccessedMemberTypes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public TrimAnalysisAssignmentPattern Merge (

public void ReportDiagnostics (DataFlowAnalyzerContext context, Action<Diagnostic> reportDiagnostic)
{
var location = Operation.Syntax.GetLocation ();
var diagnosticContext = new DiagnosticContext (Operation.Syntax.GetLocation (), reportDiagnostic);
if (context.EnableTrimAnalyzer &&
!OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) &&
!FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) {
Expand All @@ -66,9 +66,8 @@ public void ReportDiagnostics (DataFlowAnalyzerContext context, Action<Diagnosti
if (targetValue is not ValueWithDynamicallyAccessedMembers targetWithDynamicallyAccessedMembers)
throw new NotImplementedException ();

var typeNameResolver = new TypeNameResolver (context.Compilation);
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic, typeNameResolver);
var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (typeNameResolver, location, reportDiagnostic, reflectionAccessAnalyzer);
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic);
var requireDynamicallyAccessedMembersAction = new RequireDynamicallyAccessedMembersAction (diagnosticContext, reflectionAccessAnalyzer);
requireDynamicallyAccessedMembersAction.Invoke (sourceValue, targetWithDynamicallyAccessedMembers);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,17 @@ public void ReportDiagnostics (DataFlowAnalyzerContext context, Action<Diagnosti
!OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) &&
!FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) {
var location = Operation.Syntax.GetLocation ();
var typeNameResolver = new TypeNameResolver (context.Compilation);
switch (GenericInstantiation) {
case INamedTypeSymbol type:
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (typeNameResolver, location, type, reportDiagnostic);
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, type, reportDiagnostic);
break;

case IMethodSymbol method:
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (typeNameResolver, location, method, reportDiagnostic);
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, method, reportDiagnostic);
break;

case IFieldSymbol field:
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (typeNameResolver, location, field, reportDiagnostic);
GenericArgumentDataFlow.ProcessGenericArgumentDataFlow (location, field, reportDiagnostic);
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,10 @@ public void ReportDiagnostics (DataFlowAnalyzerContext context, Action<Diagnosti
{
var location = Operation.Syntax.GetLocation ();
if (context.EnableTrimAnalyzer &&
!OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) &&
!OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope(out _) &&
!FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute))
{
var typeNameResolver = new TypeNameResolver (context.Compilation);
TrimAnalysisVisitor.HandleCall (typeNameResolver, Operation, OwningSymbol, CalledMethod, Instance, Arguments, location, reportDiagnostic, default, out var _);
TrimAnalysisVisitor.HandleCall(Operation, OwningSymbol, CalledMethod, Instance, Arguments, location, reportDiagnostic, default, out var _);
}

var diagnosticContext = new DiagnosticContext (location, reportDiagnostic);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ public TrimAnalysisReflectionAccessPattern Merge (
public void ReportDiagnostics (DataFlowAnalyzerContext context, Action<Diagnostic> reportDiagnostic)
{
var location = Operation.Syntax.GetLocation ();
var typeNameResolver = new TypeNameResolver (context.Compilation);
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic, typeNameResolver);
var reflectionAccessAnalyzer = new ReflectionAccessAnalyzer (reportDiagnostic);
if (context.EnableTrimAnalyzer &&
!OwningSymbol.IsInRequiresUnreferencedCodeAttributeScope (out _) &&
!FeatureContext.IsEnabled (RequiresUnreferencedCodeAnalyzer.FullyQualifiedRequiresUnreferencedCodeAttribute)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ internal sealed class TrimAnalysisVisitor : LocalDataFlowVisitor<

FeatureChecksVisitor _featureChecksVisitor;

readonly TypeNameResolver _typeNameResolver;

public TrimAnalysisVisitor (
Compilation compilation,
LocalStateAndContextLattice<MultiValue, FeatureContext, ValueSetLattice<SingleValue>, FeatureContextLattice> lattice,
Expand All @@ -59,7 +57,6 @@ public TrimAnalysisVisitor (
_multiValueLattice = lattice.LocalStateLattice.Lattice.ValueLattice;
TrimAnalysisPatterns = trimAnalysisPatterns;
_featureChecksVisitor = new FeatureChecksVisitor (dataFlowAnalyzerContext);
_typeNameResolver = new TypeNameResolver (compilation);
}

public override FeatureChecksValue GetConditionValue (IOperation branchValueOperation, StateValue state)
Expand Down Expand Up @@ -294,7 +291,7 @@ public override MultiValue HandleMethodCall (
// Especially with DAM on type, this can lead to incorrectly analyzed code (as in unknown type which leads
// to noise). ILLink has the same problem currently: https://github.com/dotnet/linker/issues/1952

HandleCall (_typeNameResolver, operation, OwningSymbol, calledMethod, instance, arguments, Location.None, null, _multiValueLattice, out MultiValue methodReturnValue);
HandleCall (operation, OwningSymbol, calledMethod, instance, arguments, Location.None, null, _multiValueLattice, out MultiValue methodReturnValue);

// This will copy the values if necessary
TrimAnalysisPatterns.Add (new TrimAnalysisMethodCallPattern (
Expand All @@ -318,7 +315,6 @@ public override MultiValue HandleMethodCall (
}

internal static void HandleCall(
TypeNameResolver typeNameResolver,
IOperation operation,
ISymbol owningSymbol,
IMethodSymbol calledMethod,
Expand All @@ -329,7 +325,7 @@ internal static void HandleCall(
ValueSetLattice<SingleValue> multiValueLattice,
out MultiValue methodReturnValue)
{
var handleCallAction = new HandleCallAction (typeNameResolver, location, owningSymbol, operation, multiValueLattice, reportDiagnostic);
var handleCallAction = new HandleCallAction (location, owningSymbol, operation, multiValueLattice, reportDiagnostic);
MethodProxy method = new (calledMethod);
var intrinsicId = Intrinsics.GetIntrinsicIdForMethod (method);
if (!handleCallAction.Invoke (method, instance, arguments, intrinsicId, out methodReturnValue))
Expand Down
Loading