mirror of
https://github.com/godotengine/godot.git
synced 2024-11-25 21:52:51 +00:00
Merge pull request #79007 from 398utubzyt/dotnet/globalclass-analyzer
C#: Add a Roslyn analyzer for global classes
This commit is contained in:
commit
bb6879e7cc
@ -384,5 +384,65 @@ namespace Godot.SourceGenerators
|
||||
typeArgumentSyntax.GetLocation(),
|
||||
typeArgumentSyntax.SyntaxTree.FilePath));
|
||||
}
|
||||
|
||||
public static readonly DiagnosticDescriptor GlobalClassMustDeriveFromGodotObjectRule =
|
||||
new DiagnosticDescriptor(id: "GD0401",
|
||||
title: "The class must derive from GodotObject or a derived class",
|
||||
messageFormat: "The class '{0}' must derive from GodotObject or a derived class.",
|
||||
category: "Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true,
|
||||
"The class must derive from GodotObject or a derived class. Change the base class or remove the '[GlobalClass]' attribute.");
|
||||
|
||||
public static void ReportGlobalClassMustDeriveFromGodotObject(
|
||||
SyntaxNodeAnalysisContext context,
|
||||
SyntaxNode classSyntax,
|
||||
ISymbol typeSymbol)
|
||||
{
|
||||
string message = $"The class '{typeSymbol.ToDisplayString()}' must derive from GodotObject or a derived class";
|
||||
|
||||
string description = $"{message}. Change the base class or remove the '[GlobalClass]' attribute.";
|
||||
|
||||
context.ReportDiagnostic(Diagnostic.Create(
|
||||
new DiagnosticDescriptor(id: "GD0401",
|
||||
title: message,
|
||||
messageFormat: message,
|
||||
category: "Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true,
|
||||
description),
|
||||
classSyntax.GetLocation(),
|
||||
classSyntax.SyntaxTree.FilePath));
|
||||
}
|
||||
|
||||
public static readonly DiagnosticDescriptor GlobalClassMustNotBeGenericRule =
|
||||
new DiagnosticDescriptor(id: "GD0402",
|
||||
title: "The class must not contain generic arguments",
|
||||
messageFormat: "The class '{0}' must not contain generic arguments",
|
||||
category: "Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true,
|
||||
"The class must be a non-generic type. Remove the generic arguments or the '[GlobalClass]' attribute.");
|
||||
|
||||
public static void ReportGlobalClassMustNotBeGeneric(
|
||||
SyntaxNodeAnalysisContext context,
|
||||
SyntaxNode classSyntax,
|
||||
ISymbol typeSymbol)
|
||||
{
|
||||
string message = $"The class '{typeSymbol.ToDisplayString()}' must not contain generic arguments";
|
||||
|
||||
string description = $"{message}. Remove the generic arguments or the '[GlobalClass]' attribute.";
|
||||
|
||||
context.ReportDiagnostic(Diagnostic.Create(
|
||||
new DiagnosticDescriptor(id: "GD0402",
|
||||
title: message,
|
||||
messageFormat: message,
|
||||
category: "Usage",
|
||||
DiagnosticSeverity.Error,
|
||||
isEnabledByDefault: true,
|
||||
description),
|
||||
classSyntax.GetLocation(),
|
||||
classSyntax.SyntaxTree.FilePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ namespace Godot.SourceGenerators
|
||||
return godotClassName ?? nativeType.Name;
|
||||
}
|
||||
|
||||
private static bool IsGodotScriptClass(
|
||||
private static bool TryGetGodotScriptClass(
|
||||
this ClassDeclarationSyntax cds, Compilation compilation,
|
||||
out INamedTypeSymbol? symbol
|
||||
)
|
||||
@ -108,7 +108,7 @@ namespace Godot.SourceGenerators
|
||||
{
|
||||
foreach (var cds in source)
|
||||
{
|
||||
if (cds.IsGodotScriptClass(compilation, out var symbol))
|
||||
if (cds.TryGetGodotScriptClass(compilation, out var symbol))
|
||||
yield return (cds, symbol!);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace Godot.SourceGenerators
|
||||
{
|
||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
public class GlobalClassAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
|
||||
=> ImmutableArray.Create(
|
||||
Common.GlobalClassMustDeriveFromGodotObjectRule,
|
||||
Common.GlobalClassMustNotBeGenericRule);
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
||||
context.EnableConcurrentExecution();
|
||||
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
|
||||
}
|
||||
|
||||
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
var typeClassDecl = (ClassDeclarationSyntax)context.Node;
|
||||
|
||||
// Return if not a type symbol or the type is not a global class.
|
||||
if (context.ContainingSymbol is not INamedTypeSymbol typeSymbol ||
|
||||
!typeSymbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotGlobalClassAttribute() ?? false))
|
||||
return;
|
||||
|
||||
if (typeSymbol.IsGenericType)
|
||||
Common.ReportGlobalClassMustNotBeGeneric(context, typeClassDecl, typeSymbol);
|
||||
|
||||
if (!typeSymbol.InheritsFrom("GodotSharp", GodotClasses.GodotObject))
|
||||
Common.ReportGlobalClassMustDeriveFromGodotObject(context, typeClassDecl, typeSymbol);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user