initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user