Skip to content

Commit

Permalink
Merge pull request #88495 from paulloz/dotnet/test-and-fix-exports-di…
Browse files Browse the repository at this point in the history
…agnostics

[.NET] Test and fix exports diagnostics
  • Loading branch information
akien-mga authored Feb 21, 2024
2 parents e91438c + 88ad4e6 commit aeaec00
Show file tree
Hide file tree
Showing 19 changed files with 242 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using Xunit;

namespace Godot.SourceGenerators.Tests;

public class ExportDiagnosticsTests
{
[Fact]
public async void StaticMembers()
{
await CSharpSourceGeneratorVerifier<ScriptPropertyDefValGenerator>.Verify(
"ExportDiagnostics_GD0101.cs",
"ExportDiagnostics_GD0101_ScriptPropertyDefVal.generated.cs"
);
}

[Fact]
public async void TypeIsNotSupported()
{
await CSharpSourceGeneratorVerifier<ScriptPropertyDefValGenerator>.Verify(
"ExportDiagnostics_GD0102.cs",
"ExportDiagnostics_GD0102_ScriptPropertyDefVal.generated.cs"
);
}

[Fact]
public async void ReadOnly()
{
await CSharpSourceGeneratorVerifier<ScriptPropertyDefValGenerator>.Verify(
"ExportDiagnostics_GD0103.cs",
"ExportDiagnostics_GD0103_ScriptPropertyDefVal.generated.cs"
);
}

[Fact]
public async void WriteOnly()
{
await CSharpSourceGeneratorVerifier<ScriptPropertyDefValGenerator>.Verify(
"ExportDiagnostics_GD0104.cs",
"ExportDiagnostics_GD0104_ScriptPropertyDefVal.generated.cs"
);
}

[Fact]
public async void Indexer()
{
await CSharpSourceGeneratorVerifier<ScriptPropertyDefValGenerator>.Verify(
"ExportDiagnostics_GD0105.cs",
"ExportDiagnostics_GD0105_ScriptPropertyDefVal.generated.cs"
);
}

[Fact]
public async void ExplicitInterfaceImplementation()
{
await CSharpSourceGeneratorVerifier<ScriptPropertyDefValGenerator>.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<ScriptPropertyDefValGenerator>.Verify(
new string[] { "ExportDiagnostics_GD0107.cs" },
new string[]
{
"ExportDiagnostics_GD0107_OK_ScriptPropertyDefVal.generated.cs",
"ExportDiagnostics_GD0107_KO_ScriptPropertyDefVal.generated.cs",
}
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
partial class ExportDiagnostics_GD0101
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
partial class ExportDiagnostics_GD0102
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
partial class ExportDiagnostics_GD0103
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
partial class ExportDiagnostics_GD0104
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
partial class ExportDiagnostics_GD0105
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
partial class ExportDiagnostics_GD0106_KO
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
partial class ExportDiagnostics_GD0106_OK
{
#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword
#if TOOLS
/// <summary>
/// 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.
/// </summary>
[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>(1);
int __MyProperty_default_value = default;
values.Add(PropertyName.MyProperty, global::Godot.Variant.From<int>(__MyProperty_default_value));
return values;
}
#endif // TOOLS
#pragma warning restore CS0109
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
partial class ExportDiagnostics_GD0107_KO
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
partial class ExportDiagnostics_GD0107_OK
{
#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword
#if TOOLS
/// <summary>
/// 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.
/// </summary>
[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);
global::Godot.Node __NodeProperty_default_value = default;
values.Add(PropertyName.NodeProperty, global::Godot.Variant.From<global::Godot.Node>(__NodeProperty_default_value));
global::Godot.Node __NodeField_default_value = default;
values.Add(PropertyName.NodeField, global::Godot.Variant.From<global::Godot.Node>(__NodeField_default_value));
return values;
}
#endif // TOOLS
#pragma warning restore CS0109
}
Original file line number Diff line number Diff line change
@@ -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; }
}
Original file line number Diff line number Diff line change
@@ -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; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Godot;

public partial class ExportDiagnostics_GD0103 : Node
{
[Export]
public readonly string {|GD0103:ReadOnlyField|};

[Export]
public string {|GD0103:ReadOnlyProperty|} { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Godot;

public partial class ExportDiagnostics_GD0104 : Node
{
[Export]
public string {|GD0104:WriteOnlyProperty|} { set { } }
}
Original file line number Diff line number Diff line change
@@ -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 { }
}
}
Original file line number Diff line number Diff line change
@@ -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; }
}
Original file line number Diff line number Diff line change
@@ -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; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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<IPropertySymbol>()
.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<IFieldSymbol>()
.Where(s => s.GetAttributes()
.Any(a => a.AttributeClass?.IsGodotExportAttribute() ?? false))
Expand Down Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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;
}
}

Expand Down

0 comments on commit aeaec00

Please sign in to comment.