diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ExportDiagnosticsTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ExportDiagnosticsTests.cs new file mode 100644 index 000000000000..6425c723dda8 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ExportDiagnosticsTests.cs @@ -0,0 +1,77 @@ +using Xunit; + +namespace Godot.SourceGenerators.Tests; + +public class ExportDiagnosticsTests +{ + [Fact] + public async void StaticMembers() + { + await CSharpSourceGeneratorVerifier.Verify( + "ExportDiagnostics_GD0101.cs", + "ExportDiagnostics_GD0101_ScriptPropertyDefVal.generated.cs" + ); + } + + [Fact] + public async void TypeIsNotSupported() + { + await CSharpSourceGeneratorVerifier.Verify( + "ExportDiagnostics_GD0102.cs", + "ExportDiagnostics_GD0102_ScriptPropertyDefVal.generated.cs" + ); + } + + [Fact] + public async void ReadOnly() + { + await CSharpSourceGeneratorVerifier.Verify( + "ExportDiagnostics_GD0103.cs", + "ExportDiagnostics_GD0103_ScriptPropertyDefVal.generated.cs" + ); + } + + [Fact] + public async void WriteOnly() + { + await CSharpSourceGeneratorVerifier.Verify( + "ExportDiagnostics_GD0104.cs", + "ExportDiagnostics_GD0104_ScriptPropertyDefVal.generated.cs" + ); + } + + [Fact] + public async void Indexer() + { + await CSharpSourceGeneratorVerifier.Verify( + "ExportDiagnostics_GD0105.cs", + "ExportDiagnostics_GD0105_ScriptPropertyDefVal.generated.cs" + ); + } + + [Fact] + public async void ExplicitInterfaceImplementation() + { + await CSharpSourceGeneratorVerifier.Verify( + new string[] { "ExportDiagnostics_GD0106.cs" }, + new string[] + { + "ExportDiagnostics_GD0106_OK_ScriptPropertyDefVal.generated.cs", + "ExportDiagnostics_GD0106_KO_ScriptPropertyDefVal.generated.cs", + } + ); + } + + [Fact] + public async void NodeExports() + { + await CSharpSourceGeneratorVerifier.Verify( + new string[] { "ExportDiagnostics_GD0107.cs" }, + new string[] + { + "ExportDiagnostics_GD0107_OK_ScriptPropertyDefVal.generated.cs", + "ExportDiagnostics_GD0107_KO_ScriptPropertyDefVal.generated.cs", + } + ); + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0101_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0101_ScriptPropertyDefVal.generated.cs new file mode 100644 index 000000000000..47dba644aefe --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0101_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,3 @@ +partial class ExportDiagnostics_GD0101 +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0102_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0102_ScriptPropertyDefVal.generated.cs new file mode 100644 index 000000000000..636f5174d7b7 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0102_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,3 @@ +partial class ExportDiagnostics_GD0102 +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0103_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0103_ScriptPropertyDefVal.generated.cs new file mode 100644 index 000000000000..ef969235f4f3 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0103_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,3 @@ +partial class ExportDiagnostics_GD0103 +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0104_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0104_ScriptPropertyDefVal.generated.cs new file mode 100644 index 000000000000..8f01aaff6f66 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0104_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,3 @@ +partial class ExportDiagnostics_GD0104 +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0105_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0105_ScriptPropertyDefVal.generated.cs new file mode 100644 index 000000000000..52c4f1f7324c --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0105_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,3 @@ +partial class ExportDiagnostics_GD0105 +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0106_KO_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0106_KO_ScriptPropertyDefVal.generated.cs new file mode 100644 index 000000000000..8f807cef10b8 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0106_KO_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,3 @@ +partial class ExportDiagnostics_GD0106_KO +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0106_OK_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0106_OK_ScriptPropertyDefVal.generated.cs new file mode 100644 index 000000000000..f9dc4003e722 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0106_OK_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,21 @@ +partial class ExportDiagnostics_GD0106_OK +{ +#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword +#if TOOLS + /// + /// Get the default values for all properties declared in this class. + /// This method is used by Godot to determine the value that will be + /// used by the inspector when resetting properties. + /// Do not call this method. + /// + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + internal new static global::System.Collections.Generic.Dictionary GetGodotPropertyDefaultValues() + { + var values = new global::System.Collections.Generic.Dictionary(1); + int __MyProperty_default_value = default; + values.Add(PropertyName.MyProperty, global::Godot.Variant.From(__MyProperty_default_value)); + return values; + } +#endif // TOOLS +#pragma warning restore CS0109 +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0107_KO_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0107_KO_ScriptPropertyDefVal.generated.cs new file mode 100644 index 000000000000..21259107df74 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0107_KO_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,3 @@ +partial class ExportDiagnostics_GD0107_KO +{ +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0107_OK_ScriptPropertyDefVal.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0107_OK_ScriptPropertyDefVal.generated.cs new file mode 100644 index 000000000000..8b823d52c13b --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0107_OK_ScriptPropertyDefVal.generated.cs @@ -0,0 +1,23 @@ +partial class ExportDiagnostics_GD0107_OK +{ +#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword +#if TOOLS + /// + /// Get the default values for all properties declared in this class. + /// This method is used by Godot to determine the value that will be + /// used by the inspector when resetting properties. + /// Do not call this method. + /// + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + internal new static global::System.Collections.Generic.Dictionary GetGodotPropertyDefaultValues() + { + var values = new global::System.Collections.Generic.Dictionary(2); + global::Godot.Node __NodeProperty_default_value = default; + values.Add(PropertyName.NodeProperty, global::Godot.Variant.From(__NodeProperty_default_value)); + global::Godot.Node __NodeField_default_value = default; + values.Add(PropertyName.NodeField, global::Godot.Variant.From(__NodeField_default_value)); + return values; + } +#endif // TOOLS +#pragma warning restore CS0109 +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0101.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0101.cs new file mode 100644 index 000000000000..6a6682f49337 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0101.cs @@ -0,0 +1,10 @@ +using Godot; + +public partial class ExportDiagnostics_GD0101 : Node +{ + [Export] + public static string {|GD0101:StaticField|}; + + [Export] + public static int {|GD0101:StaticProperty|} { get; set; } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0102.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0102.cs new file mode 100644 index 000000000000..c2e4a60811b2 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0102.cs @@ -0,0 +1,12 @@ +using Godot; + +public partial class ExportDiagnostics_GD0102 : Node +{ + public struct MyStruct { } + + [Export] + public MyStruct {|GD0102:StructField|}; + + [Export] + public MyStruct {|GD0102:StructProperty|} { get; set; } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0103.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0103.cs new file mode 100644 index 000000000000..c4b3d3aaacce --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0103.cs @@ -0,0 +1,10 @@ +using Godot; + +public partial class ExportDiagnostics_GD0103 : Node +{ + [Export] + public readonly string {|GD0103:ReadOnlyField|}; + + [Export] + public string {|GD0103:ReadOnlyProperty|} { get; } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0104.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0104.cs new file mode 100644 index 000000000000..d7d80b6a14a3 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0104.cs @@ -0,0 +1,7 @@ +using Godot; + +public partial class ExportDiagnostics_GD0104 : Node +{ + [Export] + public string {|GD0104:WriteOnlyProperty|} { set { } } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0105.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0105.cs new file mode 100644 index 000000000000..f6b13e00fae2 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0105.cs @@ -0,0 +1,12 @@ +using System; +using Godot; + +public partial class ExportDiagnostics_GD0105 : Node +{ + [Export] + public int {|GD0105:this|}[int index] + { + get { return index; } + set { } + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0106.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0106.cs new file mode 100644 index 000000000000..e2e5c68c2133 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0106.cs @@ -0,0 +1,18 @@ +using Godot; + +public interface MyInterface +{ + public int MyProperty { get; set; } +} + +public partial class ExportDiagnostics_GD0106_OK : Node, MyInterface +{ + [Export] + public int MyProperty { get; set; } +} + +public partial class ExportDiagnostics_GD0106_KO : Node, MyInterface +{ + [Export] + int MyInterface.{|GD0106:MyProperty|} { get; set; } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0107.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0107.cs new file mode 100644 index 000000000000..067783ea66d1 --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0107.cs @@ -0,0 +1,19 @@ +using Godot; + +public partial class ExportDiagnostics_GD0107_OK : Node +{ + [Export] + public Node NodeField; + + [Export] + public Node NodeProperty { get; set; } +} + +public partial class ExportDiagnostics_GD0107_KO : Resource +{ + [Export] + public Node {|GD0107:NodeField|}; + + [Export] + public Node {|GD0107:NodeProperty|} { get; set; } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs index e80837dbe064..af39a54b0b0d 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs @@ -3,6 +3,7 @@ namespace Godot.SourceGenerators public static class GodotClasses { public const string GodotObject = "Godot.GodotObject"; + public const string Node = "Godot.Node"; public const string AssemblyHasScriptsAttr = "Godot.AssemblyHasScriptsAttribute"; public const string ExportAttr = "Godot.ExportAttribute"; public const string ExportCategoryAttr = "Godot.ExportCategoryAttribute"; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs index 27e7632ff7b0..d12a0e8d147d 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs @@ -66,11 +66,13 @@ INamedTypeSymbol symbol ) { INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace; - string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ? - namespaceSymbol.FullQualifiedNameOmitGlobal() : - string.Empty; + string classNs = namespaceSymbol is { IsGlobalNamespace: false } + ? namespaceSymbol.FullQualifiedNameOmitGlobal() + : string.Empty; bool hasNamespace = classNs.Length != 0; + bool isNode = symbol.InheritsFrom("GodotSharp", GodotClasses.Node); + bool isInnerClass = symbol.ContainingType != null; string uniqueHint = symbol.FullQualifiedNameOmitGlobal().SanitizeQualifiedNameForUniqueHint() @@ -114,14 +116,14 @@ void AppendPartialContainingTypeDeclarations(INamedTypeSymbol? containingType) var members = symbol.GetMembers(); var exportedProperties = members - .Where(s => !s.IsStatic && s.Kind == SymbolKind.Property) + .Where(s => s.Kind == SymbolKind.Property) .Cast() .Where(s => s.GetAttributes() .Any(a => a.AttributeClass?.IsGodotExportAttribute() ?? false)) .ToArray(); var exportedFields = members - .Where(s => !s.IsStatic && s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared) + .Where(s => s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared) .Cast() .Where(s => s.GetAttributes() .Any(a => a.AttributeClass?.IsGodotExportAttribute() ?? false)) @@ -198,13 +200,13 @@ void AppendPartialContainingTypeDeclarations(INamedTypeSymbol? containingType) if (marshalType == MarshalType.GodotObjectOrDerived) { - if (!symbol.InheritsFrom("GodotSharp", "Godot.Node") && - propertyType.InheritsFrom("GodotSharp", "Godot.Node")) + if (!isNode && propertyType.InheritsFrom("GodotSharp", GodotClasses.Node)) { context.ReportDiagnostic(Diagnostic.Create( Common.OnlyNodesShouldExportNodesRule, property.Locations.FirstLocationWithSourceTreeOrDefault() )); + continue; } } @@ -317,13 +319,13 @@ void AppendPartialContainingTypeDeclarations(INamedTypeSymbol? containingType) if (marshalType == MarshalType.GodotObjectOrDerived) { - if (!symbol.InheritsFrom("GodotSharp", "Godot.Node") && - fieldType.InheritsFrom("GodotSharp", "Godot.Node")) + if (!isNode && fieldType.InheritsFrom("GodotSharp", GodotClasses.Node)) { context.ReportDiagnostic(Diagnostic.Create( Common.OnlyNodesShouldExportNodesRule, field.Locations.FirstLocationWithSourceTreeOrDefault() )); + continue; } }