Browse Source

Fix GD0107 not applying to arrays and dictionaries containing nodes

Juan Pablo Arce 1 year ago
parent
commit
8aa444d212

+ 17 - 1
modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ExportDiagnostics_GD0107_OK_ScriptPropertyDefVal.generated.cs

@@ -11,11 +11,27 @@ partial class ExportDiagnostics_GD0107_OK
     [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
     internal new static global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant> GetGodotPropertyDefaultValues()
     {
-        var values = new global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>(2);
+        var values = new global::System.Collections.Generic.Dictionary<global::Godot.StringName, global::Godot.Variant>(10);
         global::Godot.Node __NodeProperty_default_value = default;
         values.Add(PropertyName.@NodeProperty, global::Godot.Variant.From<global::Godot.Node>(__NodeProperty_default_value));
+        global::Godot.Node[] __SystemArrayOfNodesProperty_default_value = default;
+        values.Add(PropertyName.@SystemArrayOfNodesProperty, global::Godot.Variant.CreateFrom(__SystemArrayOfNodesProperty_default_value));
+        global::Godot.Collections.Array<global::Godot.Node> __GodotArrayOfNodesProperty_default_value = default;
+        values.Add(PropertyName.@GodotArrayOfNodesProperty, global::Godot.Variant.CreateFrom(__GodotArrayOfNodesProperty_default_value));
+        global::Godot.Collections.Dictionary<global::Godot.Node, string> __GodotDictionaryWithNodeAsKeyProperty_default_value = default;
+        values.Add(PropertyName.@GodotDictionaryWithNodeAsKeyProperty, global::Godot.Variant.CreateFrom(__GodotDictionaryWithNodeAsKeyProperty_default_value));
+        global::Godot.Collections.Dictionary<string, global::Godot.Node> __GodotDictionaryWithNodeAsValueProperty_default_value = default;
+        values.Add(PropertyName.@GodotDictionaryWithNodeAsValueProperty, global::Godot.Variant.CreateFrom(__GodotDictionaryWithNodeAsValueProperty_default_value));
         global::Godot.Node __NodeField_default_value = default;
         values.Add(PropertyName.@NodeField, global::Godot.Variant.From<global::Godot.Node>(__NodeField_default_value));
+        global::Godot.Node[] __SystemArrayOfNodesField_default_value = default;
+        values.Add(PropertyName.@SystemArrayOfNodesField, global::Godot.Variant.CreateFrom(__SystemArrayOfNodesField_default_value));
+        global::Godot.Collections.Array<global::Godot.Node> __GodotArrayOfNodesField_default_value = default;
+        values.Add(PropertyName.@GodotArrayOfNodesField, global::Godot.Variant.CreateFrom(__GodotArrayOfNodesField_default_value));
+        global::Godot.Collections.Dictionary<global::Godot.Node, string> __GodotDictionaryWithNodeAsKeyField_default_value = default;
+        values.Add(PropertyName.@GodotDictionaryWithNodeAsKeyField, global::Godot.Variant.CreateFrom(__GodotDictionaryWithNodeAsKeyField_default_value));
+        global::Godot.Collections.Dictionary<string, global::Godot.Node> __GodotDictionaryWithNodeAsValueField_default_value = default;
+        values.Add(PropertyName.@GodotDictionaryWithNodeAsValueField, global::Godot.Variant.CreateFrom(__GodotDictionaryWithNodeAsValueField_default_value));
         return values;
     }
 #endif // TOOLS

+ 49 - 0
modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ExportDiagnostics_GD0107.cs

@@ -1,12 +1,37 @@
 using Godot;
+using Godot.Collections;
 
 public partial class ExportDiagnostics_GD0107_OK : Node
 {
     [Export]
     public Node NodeField;
 
+    [Export]
+    public Node[] SystemArrayOfNodesField;
+
+    [Export]
+    public Array<Node> GodotArrayOfNodesField;
+
+    [Export]
+    public Dictionary<Node, string> GodotDictionaryWithNodeAsKeyField;
+
+    [Export]
+    public Dictionary<string, Node> GodotDictionaryWithNodeAsValueField;
+
     [Export]
     public Node NodeProperty { get; set; }
+
+    [Export]
+    public Node[] SystemArrayOfNodesProperty { get; set; }
+
+    [Export]
+    public Array<Node> GodotArrayOfNodesProperty { get; set; }
+
+    [Export]
+    public Dictionary<Node, string> GodotDictionaryWithNodeAsKeyProperty { get; set; }
+
+    [Export]
+    public Dictionary<string, Node> GodotDictionaryWithNodeAsValueProperty { get; set; }
 }
 
 public partial class ExportDiagnostics_GD0107_KO : Resource
@@ -14,6 +39,30 @@ public partial class ExportDiagnostics_GD0107_KO : Resource
     [Export]
     public Node {|GD0107:NodeField|};
 
+    [Export]
+    public Node[] {|GD0107:SystemArrayOfNodesField|};
+
+    [Export]
+    public Array<Node> {|GD0107:GodotArrayOfNodesField|};
+
+    [Export]
+    public Dictionary<Node, string> {|GD0107:GodotDictionaryWithNodeAsKeyField|};
+
+    [Export]
+    public Dictionary<string, Node> {|GD0107:GodotDictionaryWithNodeAsValueField|};
+
     [Export]
     public Node {|GD0107:NodeProperty|} { get; set; }
+
+    [Export]
+    public Node[] {|GD0107:SystemArrayOfNodesProperty|} { get; set; }
+
+    [Export]
+    public Array<Node> {|GD0107:GodotArrayOfNodesProperty|} { get; set; }
+
+    [Export]
+    public Dictionary<Node, string> {|GD0107:GodotDictionaryWithNodeAsKeyProperty|} { get; set; }
+
+    [Export]
+    public Dictionary<string, Node> {|GD0107:GodotDictionaryWithNodeAsValueProperty|} { get; set; }
 }

+ 33 - 18
modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs

@@ -196,16 +196,13 @@ namespace Godot.SourceGenerators
                     continue;
                 }
 
-                if (marshalType == MarshalType.GodotObjectOrDerived)
+                if (!isNode && MemberHasNodeType(propertyType, marshalType.Value))
                 {
-                    if (!isNode && propertyType.InheritsFrom("GodotSharp", GodotClasses.Node))
-                    {
-                        context.ReportDiagnostic(Diagnostic.Create(
-                            Common.OnlyNodesShouldExportNodesRule,
-                            property.Locations.FirstLocationWithSourceTreeOrDefault()
-                        ));
-                        continue;
-                    }
+                    context.ReportDiagnostic(Diagnostic.Create(
+                        Common.OnlyNodesShouldExportNodesRule,
+                        property.Locations.FirstLocationWithSourceTreeOrDefault()
+                    ));
+                    continue;
                 }
 
                 var propertyDeclarationSyntax = property.DeclaringSyntaxReferences
@@ -315,16 +312,13 @@ namespace Godot.SourceGenerators
                     continue;
                 }
 
-                if (marshalType == MarshalType.GodotObjectOrDerived)
+                if (!isNode && MemberHasNodeType(fieldType, marshalType.Value))
                 {
-                    if (!isNode && fieldType.InheritsFrom("GodotSharp", GodotClasses.Node))
-                    {
-                        context.ReportDiagnostic(Diagnostic.Create(
-                            Common.OnlyNodesShouldExportNodesRule,
-                            field.Locations.FirstLocationWithSourceTreeOrDefault()
-                        ));
-                        continue;
-                    }
+                    context.ReportDiagnostic(Diagnostic.Create(
+                        Common.OnlyNodesShouldExportNodesRule,
+                        field.Locations.FirstLocationWithSourceTreeOrDefault()
+                    ));
+                    continue;
                 }
 
                 EqualsValueClauseSyntax? initializer = field.DeclaringSyntaxReferences
@@ -424,6 +418,27 @@ namespace Godot.SourceGenerators
             context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
         }
 
+        private static bool MemberHasNodeType(ITypeSymbol memberType, MarshalType marshalType)
+        {
+            if (marshalType == MarshalType.GodotObjectOrDerived)
+            {
+                return memberType.InheritsFrom("GodotSharp", GodotClasses.Node);
+            }
+            if (marshalType == MarshalType.GodotObjectOrDerivedArray)
+            {
+                var elementType = ((IArrayTypeSymbol)memberType).ElementType;
+                return elementType.InheritsFrom("GodotSharp", GodotClasses.Node);
+            }
+            if (memberType is INamedTypeSymbol { IsGenericType: true } genericType)
+            {
+                return genericType.TypeArguments
+                    .Any(static typeArgument
+                        => typeArgument.InheritsFrom("GodotSharp", GodotClasses.Node));
+            }
+
+            return false;
+        }
+
         private struct ExportedPropertyMetadata
         {
             public ExportedPropertyMetadata(string name, MarshalType type, ITypeSymbol typeSymbol, string? value)