Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[.NET] Test and fix exports diagnostics #88495

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading