C#: Fix ScriptPathAttribute generator with none or nested namespaces

The following two bugs were fixed:
- For classes without namespace we were still generating `namespace {`
without a namespace identifier, causing a syntax error.
- For classes with nested namespaces we were generating only the innermost
part of the namespace was being generated, e.g.: for `Foo.Bar` we were
generating `namespace Bar {` instead of `namespace Foo.Bar {`.
This wasn't causing any build error, but because of the wrong namespace
Godot wasn't able to find the class associated with the script.
This commit is contained in:
Ignacio Etcheverry 2021-03-13 01:04:55 +01:00
parent bf309b8a13
commit ee8e5146a4
4 changed files with 54 additions and 24 deletions

View file

@ -1,6 +1,6 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<PackageVersion_Godot_NET_Sdk>4.0.0-dev4</PackageVersion_Godot_NET_Sdk> <PackageVersion_Godot_NET_Sdk>4.0.0-dev5</PackageVersion_Godot_NET_Sdk>
<PackageVersion_Godot_SourceGenerators>4.0.0-dev1</PackageVersion_Godot_SourceGenerators> <PackageVersion_Godot_SourceGenerators>4.0.0-dev2</PackageVersion_Godot_SourceGenerators>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View file

@ -23,11 +23,12 @@
<ItemGroup> <ItemGroup>
<!-- Package Sdk\Sdk.props and Sdk\Sdk.targets file --> <!-- Package Sdk\Sdk.props and Sdk\Sdk.targets file -->
<None Include="Sdk\Sdk.props" Pack="true" PackagePath="Sdk" Visible="false" /> <None Include="Sdk\Sdk.props" Pack="true" PackagePath="Sdk" />
<None Include="Sdk\Sdk.targets" Pack="true" PackagePath="Sdk" Visible="false" /> <None Include="Sdk\Sdk.targets" Pack="true" PackagePath="Sdk" />
<!-- SdkPackageVersions.props --> <!-- SdkPackageVersions.props -->
<None Include="..\..\..\SdkPackageVersions.props" Pack="true" PackagePath="Sdk">
<None Include="..\..\..\SdkPackageVersions.props" Pack="true" PackagePath="Sdk" Visible="false" /> <Link>Sdk\SdkPackageVersions.props</Link>
</None>
</ItemGroup> </ItemGroup>
<Target Name="CopyNupkgToSConsOutputDir" AfterTargets="Pack"> <Target Name="CopyNupkgToSConsOutputDir" AfterTargets="Pack">

View file

@ -82,5 +82,8 @@ namespace Godot.SourceGenerators
public static string FullQualifiedName(this INamedTypeSymbol symbol) public static string FullQualifiedName(this INamedTypeSymbol symbol)
=> symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal); => symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal);
public static string FullQualifiedName(this INamespaceSymbol namespaceSymbol)
=> namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
} }
} }

View file

@ -69,7 +69,7 @@ namespace Godot.SourceGenerators
IEnumerable<ClassDeclarationSyntax> classDeclarations IEnumerable<ClassDeclarationSyntax> classDeclarations
) )
{ {
var attributesBuilder = new StringBuilder(); var attributes = new StringBuilder();
// Remember syntax trees for which we already added an attribute, to prevent unnecessary duplicates. // Remember syntax trees for which we already added an attribute, to prevent unnecessary duplicates.
var attributedTrees = new List<SyntaxTree>(); var attributedTrees = new List<SyntaxTree>();
@ -81,28 +81,54 @@ namespace Godot.SourceGenerators
attributedTrees.Add(cds.SyntaxTree); attributedTrees.Add(cds.SyntaxTree);
if (attributesBuilder.Length != 0) if (attributes.Length != 0)
attributesBuilder.Append("\n "); attributes.Append("\n");
attributesBuilder.Append(@"[ScriptPathAttribute(""res://"); attributes.Append(@"[ScriptPathAttribute(""res://");
attributesBuilder.Append(RelativeToDir(cds.SyntaxTree.FilePath, godotProjectDir)); attributes.Append(RelativeToDir(cds.SyntaxTree.FilePath, godotProjectDir));
attributesBuilder.Append(@""")]"); attributes.Append(@""")]");
} }
string classNs = symbol.ContainingNamespace.Name;
string className = symbol.Name; string className = symbol.Name;
var source = $@"using Godot; INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
namespace {classNs} string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
{{ namespaceSymbol.FullQualifiedName() :
{attributesBuilder} string.Empty;
partial class {className} bool hasNamespace = classNs.Length != 0;
{{
}} string uniqueName = hasNamespace ?
}} classNs + "." + className + "_ScriptPath_Generated" :
"; className + "_ScriptPath_Generated";
context.AddSource(classNs + "." + className + "_ScriptPath_Generated",
SourceText.From(source, Encoding.UTF8)); var source = new StringBuilder();
// using Godot;
// namespace {classNs} {
// {attributesBuilder}
// partial class {className} { }
// }
source.Append("using Godot;\n");
if (hasNamespace)
{
source.Append("namespace ");
source.Append(classNs);
source.Append(" {\n\n");
}
source.Append(attributes);
source.Append("\n partial class ");
source.Append(className);
source.Append("\n{\n}\n");
if (hasNamespace)
{
source.Append("\n}\n");
}
context.AddSource(uniqueName, SourceText.From(source.ToString(), Encoding.UTF8));
} }
private static void AddScriptTypesAssemblyAttr(GeneratorExecutionContext context, private static void AddScriptTypesAssemblyAttr(GeneratorExecutionContext context,