summaryrefslogtreecommitdiffstats
path: root/modules/mono/editor
diff options
context:
space:
mode:
authorRaul Santos <raulsntos@gmail.com>2024-02-15 18:18:33 +0100
committerRaul Santos <raulsntos@gmail.com>2024-02-19 06:33:13 +0100
commitfe280ef9ae65d38cbccbdc5fe197cf029a0ca397 (patch)
treeabafda3dfdfece36a2ed60c4602cb53dca8ff5ed /modules/mono/editor
parentae51db75e7a4b4d111cf5dcbf596bc2c8c8a3222 (diff)
downloadredot-engine-fe280ef9ae65d38cbccbdc5fe197cf029a0ca397.tar.gz
C#: Various fixes to generic scripts
- Report a diagnostic when there are multiple classes that match the script file name in the same script since that will result in a duplicate path key in the bimap and it's not allowed. - Fix InspectorPlugin to handle empty paths in case the project was built with a previous version of Godot that used empty paths for generic scripts. - Add tests for the new diagnostic GD0003.
Diffstat (limited to 'modules/mono/editor')
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs11
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic1T.cs9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic2T.cs10
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPathAttributeGeneratorTests.cs29
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Generic(Of T)_ScriptPath.generated.cs (renamed from modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Generic_ScriptPath.generated.cs)2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/NamespaceA.SameName_ScriptPath.generated.cs9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.GD0003.cs18
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs12
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/SameName.GD0003.cs18
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs10
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs17
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorPlugin.cs9
12 files changed, 126 insertions, 28 deletions
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs
index 2cd1a08c0e..457d8daa8e 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs
@@ -2,17 +2,6 @@
namespace Godot.SourceGenerators.Sample
{
- partial class Generic<T> : GodotObject
- {
- private int _field;
- }
-
- // Generic again but different generic parameters
- partial class Generic<T, R> : GodotObject
- {
- private int _field;
- }
-
// Generic again but without generic parameters
partial class Generic : GodotObject
{
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic1T.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic1T.cs
new file mode 100644
index 0000000000..9c4f8ee1e1
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic1T.cs
@@ -0,0 +1,9 @@
+#pragma warning disable CS0169
+
+namespace Godot.SourceGenerators.Sample
+{
+ partial class Generic1T<T> : GodotObject
+ {
+ private int _field;
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic2T.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic2T.cs
new file mode 100644
index 0000000000..80551a0b42
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic2T.cs
@@ -0,0 +1,10 @@
+#pragma warning disable CS0169
+
+namespace Godot.SourceGenerators.Sample
+{
+ // Generic again but different generic parameters
+ partial class Generic2T<T, R> : GodotObject
+ {
+ private int _field;
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPathAttributeGeneratorTests.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPathAttributeGeneratorTests.cs
index b7ad4217aa..4f6b50cf02 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPathAttributeGeneratorTests.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/ScriptPathAttributeGeneratorTests.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -47,9 +48,33 @@ public class ScriptPathAttributeGeneratorTests
{
var verifier = CSharpSourceGeneratorVerifier<ScriptPathAttributeGenerator>.MakeVerifier(
new string[] { "Generic.cs" },
- new string[] { "Generic_ScriptPath.generated.cs" }
+ new string[] { "Generic(Of T)_ScriptPath.generated.cs" }
);
- verifier.TestState.GeneratedSources.Add(MakeAssemblyScriptTypesGeneratedSource(new string[] { "global::Generic" }));
+ verifier.TestState.GeneratedSources.Add(MakeAssemblyScriptTypesGeneratedSource(new string[] { "global::Generic<>" }));
+ await verifier.RunAsync();
+ }
+
+ [Fact]
+ public async void GenericMultipleClassesSameName()
+ {
+ var verifier = CSharpSourceGeneratorVerifier<ScriptPathAttributeGenerator>.MakeVerifier(
+ Array.Empty<string>(),
+ new string[] { "Generic(Of T)_ScriptPath.generated.cs" }
+ );
+ verifier.TestState.Sources.Add(("Generic.cs", File.ReadAllText(Path.Combine(Constants.SourceFolderPath, "Generic.GD0003.cs"))));
+ verifier.TestState.GeneratedSources.Add(MakeAssemblyScriptTypesGeneratedSource(new string[] { "global::Generic<>", "global::Generic<,>", "global::Generic" }));
+ await verifier.RunAsync();
+ }
+
+ [Fact]
+ public async void NamespaceMultipleClassesSameName()
+ {
+ var verifier = CSharpSourceGeneratorVerifier<ScriptPathAttributeGenerator>.MakeVerifier(
+ Array.Empty<string>(),
+ new string[] { "NamespaceA.SameName_ScriptPath.generated.cs" }
+ );
+ verifier.TestState.Sources.Add(("SameName.cs", File.ReadAllText(Path.Combine(Constants.SourceFolderPath, "SameName.GD0003.cs"))));
+ verifier.TestState.GeneratedSources.Add(MakeAssemblyScriptTypesGeneratedSource(new string[] { "global::NamespaceA.SameName", "global::NamespaceB.SameName" }));
await verifier.RunAsync();
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Generic_ScriptPath.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Generic(Of T)_ScriptPath.generated.cs
index 72c48595a2..355b01f753 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Generic_ScriptPath.generated.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/Generic(Of T)_ScriptPath.generated.cs
@@ -1,5 +1,5 @@
using Godot;
[ScriptPathAttribute("res://Generic.cs")]
-partial class Generic
+partial class Generic<T>
{
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/NamespaceA.SameName_ScriptPath.generated.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/NamespaceA.SameName_ScriptPath.generated.cs
new file mode 100644
index 0000000000..cad9f2a46b
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/NamespaceA.SameName_ScriptPath.generated.cs
@@ -0,0 +1,9 @@
+using Godot;
+namespace NamespaceA {
+
+[ScriptPathAttribute("res://SameName.cs")]
+partial class SameName
+{
+}
+
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.GD0003.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.GD0003.cs
new file mode 100644
index 0000000000..15c1e03801
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.GD0003.cs
@@ -0,0 +1,18 @@
+using Godot;
+
+partial class Generic<T> : GodotObject
+{
+ private int _field;
+}
+
+// Generic again but different generic parameters
+partial class {|GD0003:Generic|}<T, R> : GodotObject
+{
+ private int _field;
+}
+
+// Generic again but without generic parameters
+partial class {|GD0003:Generic|} : GodotObject
+{
+ private int _field;
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs
index 84d1ede065..5a83e21e96 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/Generic.cs
@@ -4,15 +4,3 @@ partial class Generic<T> : GodotObject
{
private int _field;
}
-
-// Generic again but different generic parameters
-partial class Generic<T, R> : GodotObject
-{
- private int _field;
-}
-
-// Generic again but without generic parameters
-partial class Generic : GodotObject
-{
- private int _field;
-}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/SameName.GD0003.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/SameName.GD0003.cs
new file mode 100644
index 0000000000..3f4f79fc49
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/SameName.GD0003.cs
@@ -0,0 +1,18 @@
+using Godot;
+
+namespace NamespaceA
+{
+ partial class SameName : GodotObject
+ {
+ private int _field;
+ }
+}
+
+// SameName again but different namespace
+namespace NamespaceB
+{
+ partial class {|GD0003:SameName|} : GodotObject
+ {
+ private int _field;
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
index a47e2e170f..6cd5ddb42f 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
@@ -65,6 +65,16 @@ namespace Godot.SourceGenerators
outerTypeDeclSyntax.SyntaxTree.FilePath));
}
+ public static readonly DiagnosticDescriptor MultipleClassesInGodotScriptRule =
+ new DiagnosticDescriptor(id: "GD0003",
+ title: "Found multiple classes with the same name in the same script file",
+ messageFormat: "Found multiple classes with the name '{0}' in the same script file",
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ "Found multiple classes with the same name in the same script file. A script file must only contain one class with a name that matches the file name.",
+ helpLinkUri: string.Format(_helpLinkFormat, "GD0003"));
+
public static readonly DiagnosticDescriptor ExportedMemberIsStaticRule =
new DiagnosticDescriptor(id: "GD0101",
title: "The exported member is static",
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
index 625a6f9921..6dc541cc59 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
@@ -58,9 +58,10 @@ namespace Godot.SourceGenerators
.GroupBy<(ClassDeclarationSyntax cds, INamedTypeSymbol symbol), INamedTypeSymbol>(x => x.symbol, SymbolEqualityComparer.Default)
.ToDictionary<IGrouping<INamedTypeSymbol, (ClassDeclarationSyntax cds, INamedTypeSymbol symbol)>, INamedTypeSymbol, IEnumerable<ClassDeclarationSyntax>>(g => g.Key, g => g.Select(x => x.cds), SymbolEqualityComparer.Default);
+ var usedPaths = new HashSet<string>();
foreach (var godotClass in godotClasses)
{
- VisitGodotScriptClass(context, godotProjectDir,
+ VisitGodotScriptClass(context, godotProjectDir, usedPaths,
symbol: godotClass.Key,
classDeclarations: godotClass.Value);
}
@@ -74,6 +75,7 @@ namespace Godot.SourceGenerators
private static void VisitGodotScriptClass(
GeneratorExecutionContext context,
string godotProjectDir,
+ HashSet<string> usedPaths,
INamedTypeSymbol symbol,
IEnumerable<ClassDeclarationSyntax> classDeclarations
)
@@ -93,8 +95,19 @@ namespace Godot.SourceGenerators
if (attributes.Length != 0)
attributes.Append("\n");
+ string scriptPath = RelativeToDir(cds.SyntaxTree.FilePath, godotProjectDir);
+ if (!usedPaths.Add(scriptPath))
+ {
+ context.ReportDiagnostic(Diagnostic.Create(
+ Common.MultipleClassesInGodotScriptRule,
+ cds.Identifier.GetLocation(),
+ symbol.Name
+ ));
+ return;
+ }
+
attributes.Append(@"[ScriptPathAttribute(""res://");
- attributes.Append(RelativeToDir(cds.SyntaxTree.FilePath, godotProjectDir));
+ attributes.Append(scriptPath);
attributes.Append(@""")]");
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorPlugin.cs
index b86a2b8b24..8aeb19e08b 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Inspector/InspectorPlugin.cs
@@ -28,6 +28,15 @@ namespace GodotTools.Inspector
continue;
string scriptPath = script.ResourcePath;
+
+ if (string.IsNullOrEmpty(scriptPath))
+ {
+ // Generic types used empty paths in older versions of Godot
+ // so we assume your project is out of sync.
+ AddCustomControl(new InspectorOutOfSyncWarning());
+ break;
+ }
+
if (scriptPath.StartsWith("csharp://"))
{
// This is a virtual path used by generic types, extract the real path.