123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- using System.Collections.Immutable;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- using Microsoft.CodeAnalysis;
- using Microsoft.CodeAnalysis.CodeActions;
- using Microsoft.CodeAnalysis.CodeFixes;
- using Microsoft.CodeAnalysis.CSharp;
- using Microsoft.CodeAnalysis.CSharp.Syntax;
- using Microsoft.CodeAnalysis.Diagnostics;
- namespace Godot.SourceGenerators
- {
- [DiagnosticAnalyzer(LanguageNames.CSharp)]
- public sealed class ClassPartialModifierAnalyzer : DiagnosticAnalyzer
- {
- public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
- ImmutableArray.Create(Common.ClassPartialModifierRule, Common.OuterClassPartialModifierRule);
- public override void Initialize(AnalysisContext context)
- {
- context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
- context.EnableConcurrentExecution();
- context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
- }
- private void AnalyzeNode(SyntaxNodeAnalysisContext context)
- {
- if (context.Node is not ClassDeclarationSyntax classDeclaration)
- return;
- if (context.ContainingSymbol is not INamedTypeSymbol typeSymbol)
- return;
- if (!typeSymbol.InheritsFrom("GodotSharp", GodotClasses.GodotObject))
- return;
- if (!classDeclaration.IsPartial())
- context.ReportDiagnostic(Diagnostic.Create(
- Common.ClassPartialModifierRule,
- classDeclaration.Identifier.GetLocation(),
- typeSymbol.ToDisplayString()));
- var outerClassDeclaration = context.Node.Parent as ClassDeclarationSyntax;
- while (outerClassDeclaration is not null)
- {
- var outerClassTypeSymbol = context.SemanticModel.GetDeclaredSymbol(outerClassDeclaration);
- if (outerClassTypeSymbol == null)
- return;
- if (!outerClassDeclaration.IsPartial())
- context.ReportDiagnostic(Diagnostic.Create(
- Common.OuterClassPartialModifierRule,
- outerClassDeclaration.Identifier.GetLocation(),
- outerClassTypeSymbol.ToDisplayString()));
- outerClassDeclaration = outerClassDeclaration.Parent as ClassDeclarationSyntax;
- }
- }
- }
- [ExportCodeFixProvider(LanguageNames.CSharp)]
- public sealed class ClassPartialModifierCodeFixProvider : CodeFixProvider
- {
- public override ImmutableArray<string> FixableDiagnosticIds =>
- ImmutableArray.Create(Common.ClassPartialModifierRule.Id);
- public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
- public override async Task RegisterCodeFixesAsync(CodeFixContext context)
- {
- // Get the syntax root of the document.
- var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
- // Get the diagnostic to fix.
- var diagnostic = context.Diagnostics.First();
- // Get the location of code issue.
- var diagnosticSpan = diagnostic.Location.SourceSpan;
- // Use that location to find the containing class declaration.
- var classDeclaration = root?.FindToken(diagnosticSpan.Start)
- .Parent?
- .AncestorsAndSelf()
- .OfType<ClassDeclarationSyntax>()
- .First();
- if (classDeclaration == null)
- return;
- context.RegisterCodeFix(
- CodeAction.Create(
- "Add partial modifier",
- cancellationToken => AddPartialModifierAsync(context.Document, classDeclaration, cancellationToken),
- classDeclaration.ToFullString()),
- context.Diagnostics);
- }
- private static async Task<Document> AddPartialModifierAsync(Document document,
- ClassDeclarationSyntax classDeclaration, CancellationToken cancellationToken)
- {
- // Create a new partial modifier.
- var partialModifier = SyntaxFactory.Token(SyntaxKind.PartialKeyword);
- var modifiedClassDeclaration = classDeclaration.AddModifiers(partialModifier);
- var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
- // Replace the old class declaration with the modified one in the syntax root.
- var newRoot = root!.ReplaceNode(classDeclaration, modifiedClassDeclaration);
- var newDocument = document.WithSyntaxRoot(newRoot);
- return newDocument;
- }
- }
- }
|