1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-11 13:10:58 +00:00

Implement [ExportToolButton]

This commit is contained in:
Paul Joannon
2024-10-06 18:24:46 +02:00
parent db66bd35af
commit 4f52c2bb1f
18 changed files with 406 additions and 3 deletions

View File

@@ -3,3 +3,6 @@
Rule ID | Category | Severity | Notes
--------|----------|----------|--------------------
GD0003 | Usage | Error | ScriptPathAttributeGenerator, [Documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/diagnostics/GD0003.html)
GD0108 | Usage | Error | ScriptPropertiesGenerator, [Documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/diagnostics/GD0108.html)
GD0109 | Usage | Error | ScriptPropertiesGenerator, [Documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/diagnostics/GD0109.html)
GD0110 | Usage | Error | ScriptPropertiesGenerator, [Documentation](https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/diagnostics/GD0110.html)

View File

@@ -107,6 +107,36 @@ namespace Godot.SourceGenerators
"Types not derived from Node should not export Node members. Node export is only supported in Node-derived classes.",
helpLinkUri: string.Format(_helpLinkFormat, "GD0107"));
public static readonly DiagnosticDescriptor OnlyToolClassesShouldUseExportToolButtonRule =
new DiagnosticDescriptor(id: "GD0108",
title: "The exported tool button is not in a tool class",
messageFormat: "The exported tool button '{0}' is not in a tool class",
category: "Usage",
DiagnosticSeverity.Error,
isEnabledByDefault: true,
"The exported tool button is not in a tool class. Annotate the class with the '[Tool]' attribute, or remove the '[ExportToolButton]' attribute.",
helpLinkUri: string.Format(_helpLinkFormat, "GD0108"));
public static readonly DiagnosticDescriptor ExportToolButtonShouldNotBeUsedWithExportRule =
new DiagnosticDescriptor(id: "GD0109",
title: "The '[ExportToolButton]' attribute cannot be used with another '[Export]' attribute",
messageFormat: "The '[ExportToolButton]' attribute cannot be used with another '[Export]' attribute on '{0}'",
category: "Usage",
DiagnosticSeverity.Error,
isEnabledByDefault: true,
"The '[ExportToolButton]' attribute cannot be used with the '[Export]' attribute. Remove one of the attributes.",
helpLinkUri: string.Format(_helpLinkFormat, "GD0109"));
public static readonly DiagnosticDescriptor ExportToolButtonIsNotCallableRule =
new DiagnosticDescriptor(id: "GD0110",
title: "The exported tool button is not a Callable",
messageFormat: "The exported tool button '{0}' is not a Callable",
category: "Usage",
DiagnosticSeverity.Error,
isEnabledByDefault: true,
"The exported tool button is not a Callable. The '[ExportToolButton]' attribute is only supported on members of type Callable.",
helpLinkUri: string.Format(_helpLinkFormat, "GD0110"));
public static readonly DiagnosticDescriptor SignalDelegateMissingSuffixRule =
new DiagnosticDescriptor(id: "GD0201",
title: "The name of the delegate must end with 'EventHandler'",

View File

@@ -287,6 +287,12 @@ namespace Godot.SourceGenerators
public static bool IsGodotGlobalClassAttribute(this INamedTypeSymbol symbol)
=> symbol.FullQualifiedNameOmitGlobal() == GodotClasses.GlobalClassAttr;
public static bool IsGodotExportToolButtonAttribute(this INamedTypeSymbol symbol)
=> symbol.FullQualifiedNameOmitGlobal() == GodotClasses.ExportToolButtonAttr;
public static bool IsGodotToolAttribute(this INamedTypeSymbol symbol)
=> symbol.FullQualifiedNameOmitGlobal() == GodotClasses.ToolAttr;
public static bool IsSystemFlagsAttribute(this INamedTypeSymbol symbol)
=> symbol.FullQualifiedNameOmitGlobal() == GodotClasses.SystemFlagsAttr;

View File

@@ -9,10 +9,12 @@ namespace Godot.SourceGenerators
public const string ExportCategoryAttr = "Godot.ExportCategoryAttribute";
public const string ExportGroupAttr = "Godot.ExportGroupAttribute";
public const string ExportSubgroupAttr = "Godot.ExportSubgroupAttribute";
public const string ExportToolButtonAttr = "Godot.ExportToolButtonAttribute";
public const string SignalAttr = "Godot.SignalAttribute";
public const string MustBeVariantAttr = "Godot.MustBeVariantAttribute";
public const string GodotClassNameAttr = "Godot.GodotClassNameAttribute";
public const string GlobalClassAttr = "Godot.GlobalClassAttribute";
public const string ToolAttr = "Godot.ToolAttribute";
public const string SystemFlagsAttr = "System.FlagsAttribute";
}
}

View File

@@ -89,7 +89,8 @@ namespace Godot.SourceGenerators
Password = 36,
LayersAvoidance = 37,
DictionaryType = 38,
Max = 39
ToolButton = 39,
Max = 40
}
[Flags]

View File

@@ -69,6 +69,7 @@ namespace Godot.SourceGenerators
bool hasNamespace = classNs.Length != 0;
bool isInnerClass = symbol.ContainingType != null;
bool isToolClass = symbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotToolAttribute() ?? false);
string uniqueHint = symbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint()
+ "_ScriptProperties.generated";
@@ -277,6 +278,16 @@ namespace Godot.SourceGenerators
if (propertyInfo == null)
continue;
if (propertyInfo.Value.Hint == PropertyHint.ToolButton && !isToolClass)
{
context.ReportDiagnostic(Diagnostic.Create(
Common.OnlyToolClassesShouldUseExportToolButtonRule,
member.Symbol.Locations.FirstLocationWithSourceTreeOrDefault(),
member.Symbol.ToDisplayString()
));
continue;
}
AppendPropertyInfo(source, propertyInfo.Value);
}
@@ -418,6 +429,19 @@ namespace Godot.SourceGenerators
var exportAttr = memberSymbol.GetAttributes()
.FirstOrDefault(a => a.AttributeClass?.IsGodotExportAttribute() ?? false);
var exportToolButtonAttr = memberSymbol.GetAttributes()
.FirstOrDefault(a => a.AttributeClass?.IsGodotExportToolButtonAttribute() ?? false);
if (exportAttr != null && exportToolButtonAttr != null)
{
context.ReportDiagnostic(Diagnostic.Create(
Common.ExportToolButtonShouldNotBeUsedWithExportRule,
memberSymbol.Locations.FirstLocationWithSourceTreeOrDefault(),
memberSymbol.ToDisplayString()
));
return null;
}
var propertySymbol = memberSymbol as IPropertySymbol;
var fieldSymbol = memberSymbol as IFieldSymbol;
@@ -446,19 +470,56 @@ namespace Godot.SourceGenerators
}
}
if (exportToolButtonAttr != null && propertySymbol != null && propertySymbol.GetMethod == null)
{
context.ReportDiagnostic(Diagnostic.Create(
Common.ExportedPropertyIsWriteOnlyRule,
propertySymbol.Locations.FirstLocationWithSourceTreeOrDefault(),
propertySymbol.ToDisplayString()
));
return null;
}
var memberType = propertySymbol?.Type ?? fieldSymbol!.Type;
var memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType)!.Value;
string memberName = memberSymbol.Name;
string? hintString = null;
if (exportToolButtonAttr != null)
{
if (memberVariantType != VariantType.Callable)
{
context.ReportDiagnostic(Diagnostic.Create(
Common.ExportToolButtonIsNotCallableRule,
memberSymbol.Locations.FirstLocationWithSourceTreeOrDefault(),
memberSymbol.ToDisplayString()
));
return null;
}
hintString = exportToolButtonAttr.ConstructorArguments[0].Value?.ToString() ?? "";
foreach (var namedArgument in exportToolButtonAttr.NamedArguments)
{
if (namedArgument is { Key: "Icon", Value.Value: string { Length: > 0 } })
{
hintString += $",{namedArgument.Value.Value}";
}
}
return new PropertyInfo(memberVariantType, memberName, PropertyHint.ToolButton,
hintString: hintString, PropertyUsageFlags.Editor, exported: true);
}
if (exportAttr == null)
{
return new PropertyInfo(memberVariantType, memberName, PropertyHint.None,
hintString: null, PropertyUsageFlags.ScriptVariable, exported: false);
hintString: hintString, PropertyUsageFlags.ScriptVariable, exported: false);
}
if (!TryGetMemberExportHint(typeCache, memberType, exportAttr, memberVariantType,
isTypeArgument: false, out var hint, out var hintString))
isTypeArgument: false, out var hint, out hintString))
{
var constructorArguments = exportAttr.ConstructorArguments;