Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/ILLink.CodeFix/DAMCodeFixProvider.cs')
-rw-r--r--src/ILLink.CodeFix/DAMCodeFixProvider.cs134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/ILLink.CodeFix/DAMCodeFixProvider.cs b/src/ILLink.CodeFix/DAMCodeFixProvider.cs
new file mode 100644
index 000000000..60de66cea
--- /dev/null
+++ b/src/ILLink.CodeFix/DAMCodeFixProvider.cs
@@ -0,0 +1,134 @@
+// 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.Collections.Immutable;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using ILLink.CodeFixProvider;
+using ILLink.RoslynAnalyzer;
+using ILLink.Shared;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Simplification;
+
+namespace ILLink.CodeFix
+{
+ public class DAMCodeFixProvider : Microsoft.CodeAnalysis.CodeFixes.CodeFixProvider
+ {
+ public static ImmutableArray<DiagnosticDescriptor> GetSupportedDiagnostics ()
+ {
+ var diagDescriptorsArrayBuilder = ImmutableArray.CreateBuilder<DiagnosticDescriptor> ();
+ diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter));
+ diagDescriptorsArrayBuilder.Add (DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter));
+ return diagDescriptorsArrayBuilder.ToImmutable ();
+ }
+
+ public static ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => GetSupportedDiagnostics ();
+
+ public sealed override ImmutableArray<string> FixableDiagnosticIds => SupportedDiagnostics.Select (dd => dd.Id).ToImmutableArray ();
+
+ private protected static LocalizableString CodeFixTitle => new LocalizableResourceString (nameof (Resources.DynamicallyAccessedMembersCodeFixTitle), Resources.ResourceManager, typeof (Resources));
+
+ private protected static string FullyQualifiedAttributeName => DynamicallyAccessedMembersAnalyzer.FullyQualifiedDynamicallyAccessedMembersAttribute;
+
+ protected static SyntaxNode[] GetAttributeArguments (ISymbol targetSymbol, SyntaxGenerator syntaxGenerator, Diagnostic diagnostic)
+ {
+ object id = Enum.Parse (typeof (DiagnosticId), diagnostic.Id.Substring (2));
+ switch (id) {
+ case DiagnosticId.DynamicallyAccessedMembersMismatchParameterTargetsThisParameter:
+ return new[] { syntaxGenerator.AttributeArgument (syntaxGenerator.TypedConstantExpression (targetSymbol.GetAttributes ().First (attr => attr.AttributeClass?.ToDisplayString () == DynamicallyAccessedMembersAnalyzer.FullyQualifiedDynamicallyAccessedMembersAttribute).ConstructorArguments[0])) };
+ case DiagnosticId.DynamicallyAccessedMembersMismatchFieldTargetsThisParameter:
+ return new[] { syntaxGenerator.AttributeArgument (syntaxGenerator.TypedConstantExpression (targetSymbol.GetAttributes ().First (attr => attr.AttributeClass?.ToDisplayString () == DynamicallyAccessedMembersAnalyzer.FullyQualifiedDynamicallyAccessedMembersAttribute).ConstructorArguments[0])) };
+ default:
+ return Array.Empty<SyntaxNode> ();
+ }
+ }
+
+ public sealed override FixAllProvider GetFixAllProvider ()
+ {
+ // See https://github.com/dotnet/roslyn/blob/master/docs/analyzers/FixAllProvider.md for more information on Fix All Providers
+ return WellKnownFixAllProviders.BatchFixer;
+ }
+
+ public override async Task RegisterCodeFixesAsync (CodeFixContext context)
+ {
+ var document = context.Document;
+ if (await document.GetSyntaxRootAsync (context.CancellationToken).ConfigureAwait (false) is not { } root)
+ return;
+ var diagnostic = context.Diagnostics.First ();
+ SyntaxNode diagnosticNode = root.FindNode (diagnostic.Location.SourceSpan, getInnermostNodeForTie: true);
+ if (await document.GetSemanticModelAsync (context.CancellationToken).ConfigureAwait (false) is not { } model)
+ return;
+ // Note: We get the target symbol from the diagnostic location.
+ // This works when the diagnostic location is a method call, because the target symbol will be the called method with annotations, but won't work in general for other kinds of diagnostics.
+ if (model.GetSymbolInfo (diagnosticNode).Symbol is not { } targetSymbol)
+ return;
+ if (model.Compilation.GetTypeByMetadataName (FullyQualifiedAttributeName) is not { } attributeSymbol)
+ return;
+
+ if (diagnosticNode is not InvocationExpressionSyntax invocationExpression)
+ return;
+
+ var arguments = invocationExpression.ArgumentList.Arguments;
+
+ if (arguments.Count > 1)
+ return;
+
+ if (arguments.Count == 1) {
+ if (arguments[0].Expression is not LiteralExpressionSyntax literalSyntax
+ || literalSyntax.Kind () is not SyntaxKind.StringLiteralExpression) {
+ return;
+ }
+ }
+
+ // N.B. May be null for FieldDeclaration, since field declarations can declare multiple variables
+ var attributableSymbol = (invocationExpression.Expression is MemberAccessExpressionSyntax simpleMember
+ && simpleMember.Expression is IdentifierNameSyntax name) ? model.GetSymbolInfo (name).Symbol : null;
+
+
+ if (attributableSymbol is null)
+ return;
+
+ var attributableNodeList = attributableSymbol.DeclaringSyntaxReferences;
+
+ if (attributableNodeList.Length != 1)
+ return;
+
+ var attributableNode = attributableNodeList[0].GetSyntax ();
+
+ if (attributableNode is null) return;
+
+ var attributeArguments = GetAttributeArguments (targetSymbol, SyntaxGenerator.GetGenerator (document), diagnostic);
+ var codeFixTitle = CodeFixTitle.ToString ();
+
+ context.RegisterCodeFix (CodeAction.Create (
+ title: codeFixTitle,
+ createChangedDocument: ct => AddAttributeAsync (
+ document, attributableNode, attributeArguments, attributeSymbol, ct),
+ equivalenceKey: codeFixTitle), diagnostic);
+ }
+
+ private static async Task<Document> AddAttributeAsync (
+ Document document,
+ SyntaxNode targetNode,
+ SyntaxNode[] attributeArguments,
+ ITypeSymbol attributeSymbol,
+ CancellationToken cancellationToken)
+ {
+ var editor = await DocumentEditor.CreateAsync (document, cancellationToken).ConfigureAwait (false);
+ var generator = editor.Generator;
+ var attribute = generator.Attribute (
+ generator.TypeExpression (attributeSymbol), attributeArguments)
+ .WithAdditionalAnnotations (Simplifier.Annotation, Simplifier.AddImportsAnnotation);
+
+ editor.AddAttribute (targetNode, attribute);
+ return editor.GetChangedDocument ();
+ }
+ }
+}