summaryrefslogtreecommitdiff
path: root/modules/mono/editor/Godot.NET.Sdk
diff options
context:
space:
mode:
authorIgnacio Roldán Etcheverry <ignalfonsore@gmail.com>2021-12-28 23:25:16 +0100
committerIgnacio Roldán Etcheverry <ignalfonsore@gmail.com>2022-08-22 03:36:51 +0200
commit88e367a4066773a6fbfe2ea25dc2e81d2035d791 (patch)
treea219a4332cb7b4c05daacce718af76347774df77 /modules/mono/editor/Godot.NET.Sdk
parentf88d8902cfc0d6a9441e794eb47611ef4ed0d46c (diff)
C#/netcore: Add base desktop game export implementation
This base implementation is still very barebones but it defines the path for how exporting will work (at least when embedding the .NET runtime). Many manual steps are still needed, which should be automatized in the future. For example, in addition to the API assemblies, now you also need to copy the GodotPlugins assembly to each game project.
Diffstat (limited to 'modules/mono/editor/Godot.NET.Sdk')
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs17
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs32
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs46
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props3
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs58
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptBoilerplateGenerator.cs187
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs5
9 files changed, 308 insertions, 46 deletions
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
index 5a499742e9..9bc134818a 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
@@ -104,11 +104,9 @@
Godot scripting API is continuaslly breaking backwards compatibility even in patch releases.
-->
<Reference Include="GodotSharp">
- <Private>false</Private>
<HintPath>$(GodotProjectDir).godot\mono\assemblies\$(GodotApiConfiguration)\GodotSharp.dll</HintPath>
</Reference>
<Reference Include="GodotSharpEditor" Condition=" '$(Configuration)' == 'Debug' ">
- <Private>false</Private>
<HintPath>$(GodotProjectDir).godot\mono\assemblies\$(GodotApiConfiguration)\GodotSharpEditor.dll</HintPath>
</Reference>
</ItemGroup>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs
index 05723c8940..0c7328284e 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs
@@ -1,6 +1,8 @@
+using System;
+
namespace Godot.SourceGenerators.Sample
{
- public partial class ScriptBoilerplate : Godot.Node
+ public partial class ScriptBoilerplate : Node
{
private NodePath _nodePath;
private int _velocity;
@@ -17,5 +19,18 @@ namespace Godot.SourceGenerators.Sample
_ = name;
return 1;
}
+
+ public void IgnoreThisMethodWithByRefParams(ref int a)
+ {
+ _ = a;
+ }
+ }
+
+ partial struct OuterClass
+ {
+ public partial class NesterClass : RefCounted
+ {
+ public override object _Get(StringName property) => null;
+ }
}
}
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 4dd67252ed..fa41c85322 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
@@ -28,5 +28,37 @@ namespace Godot.SourceGenerators
cds.GetLocation(),
cds.SyntaxTree.FilePath));
}
+
+ public static void ReportNonPartialGodotScriptOuterClass(
+ GeneratorExecutionContext context,
+ TypeDeclarationSyntax outerTypeDeclSyntax
+ )
+ {
+ var outerSymbol = context.Compilation
+ .GetSemanticModel(outerTypeDeclSyntax.SyntaxTree)
+ .GetDeclaredSymbol(outerTypeDeclSyntax);
+
+ string fullQualifiedName = outerSymbol is INamedTypeSymbol namedTypeSymbol ?
+ namedTypeSymbol.FullQualifiedName() :
+ "type not found";
+
+ string message =
+ $"Missing partial modifier on declaration of type '{fullQualifiedName}', " +
+ $"which contains one or more subclasses of '{GodotClasses.Object}'";
+
+ string description = $"{message}. Subclasses of '{GodotClasses.Object}' and their " +
+ "containing types must be declared with the partial modifier.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GODOT-G0002",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ outerTypeDeclSyntax.GetLocation(),
+ outerTypeDeclSyntax.SyntaxTree.FilePath));
+ }
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index f8c50e66c8..9586e71d02 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -19,6 +19,11 @@ namespace Godot.SourceGenerators
toggle != null &&
toggle.Equals("disabled", StringComparison.OrdinalIgnoreCase);
+ public static bool IsGodotToolsProject(this GeneratorExecutionContext context)
+ => context.TryGetGlobalAnalyzerProperty("IsGodotToolsProject", out string? toggle) &&
+ toggle != null &&
+ toggle.Equals("true", StringComparison.OrdinalIgnoreCase);
+
private static bool InheritsFrom(this INamedTypeSymbol? symbol, string baseName)
{
if (symbol == null)
@@ -75,9 +80,48 @@ namespace Godot.SourceGenerators
}
}
- public static bool IsPartial(this ClassDeclarationSyntax cds)
+ public static bool IsNested(this TypeDeclarationSyntax cds)
+ => cds.Parent is TypeDeclarationSyntax;
+
+ public static bool IsPartial(this TypeDeclarationSyntax cds)
=> cds.Modifiers.Any(SyntaxKind.PartialKeyword);
+ public static bool AreAllOuterTypesPartial(
+ this TypeDeclarationSyntax cds,
+ out TypeDeclarationSyntax? typeMissingPartial
+ )
+ {
+ SyntaxNode? outerSyntaxNode = cds.Parent;
+
+ while (outerSyntaxNode is TypeDeclarationSyntax outerTypeDeclSyntax)
+ {
+ if (!outerTypeDeclSyntax.IsPartial())
+ {
+ typeMissingPartial = outerTypeDeclSyntax;
+ return false;
+ }
+
+ outerSyntaxNode = outerSyntaxNode.Parent;
+ }
+
+ typeMissingPartial = null;
+ return true;
+ }
+
+ public static string GetDeclarationKeyword(this INamedTypeSymbol namedTypeSymbol)
+ {
+ string? keyword = namedTypeSymbol.DeclaringSyntaxReferences
+ .OfType<TypeDeclarationSyntax>().FirstOrDefault()?
+ .Keyword.Text;
+
+ return keyword ?? namedTypeSymbol.TypeKind switch
+ {
+ TypeKind.Interface => "interface",
+ TypeKind.Struct => "struct",
+ _ => "class"
+ };
+ }
+
private static SymbolDisplayFormat FullyQualifiedFormatOmitGlobal { get; } =
SymbolDisplayFormat.FullyQualifiedFormat
.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted);
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
index 11d8e0f72b..791ad85572 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
@@ -21,14 +21,14 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" PrivateAssets="all" />
- <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.1" PrivateAssets="all" />
+ <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<!-- Package the generator in the analyzer directory of the nuget package -->
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
<!-- Package the props file -->
- <None Include="Godot.SourceGenerators.props" Pack="true" PackagePath="build" Visible="false" />
+ <None Include="Godot.SourceGenerators.props" Pack="true" PackagePath="build" Visible="true" />
</ItemGroup>
<Target Name="CopyNupkgToSConsOutputDir" AfterTargets="Pack">
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props
index 5025215d34..7881ed0a8c 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props
@@ -2,6 +2,7 @@
<ItemGroup>
<!-- $(GodotProjectDir) is defined by Godot.NET.Sdk -->
<CompilerVisibleProperty Include="GodotProjectDir" />
- <CompilerVisibleProperty Include="EnableGodotGenerators" />
+ <CompilerVisibleProperty Include="GodotSourceGenerators" />
+ <CompilerVisibleProperty Include="IsGodotToolsProject" />
</ItemGroup>
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
new file mode 100644
index 0000000000..497a1b908c
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
@@ -0,0 +1,58 @@
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Godot.SourceGenerators
+{
+ [Generator]
+ public class GodotPluginsInitializerGenerator : ISourceGenerator
+ {
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ }
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ if (context.IsGodotToolsProject())
+ return;
+
+ string source =
+ @"using System;
+using System.Runtime.InteropServices;
+using Godot.Bridge;
+using Godot.NativeInterop;
+
+namespace GodotPlugins.Game
+{
+ internal static partial class Main
+ {
+ [UnmanagedCallersOnly]
+ private static godot_bool InitializeFromGameProject(IntPtr outManagedCallbacks)
+ {
+ try
+ {
+ var coreApiAssembly = typeof(Godot.Object).Assembly;
+
+ NativeLibrary.SetDllImportResolver(coreApiAssembly, GodotDllImportResolver.OnResolveDllImport);
+
+ ManagedCallbacks.Create(outManagedCallbacks);
+
+ ScriptManagerBridge.LookupScriptsInAssembly(typeof(GodotPlugins.Game.Main).Assembly);
+
+ return godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine(e);
+ return false.ToGodotBool();
+ }
+ }
+ }
+}
+";
+
+ context.AddSource("GodotPlugins.Game_Generated",
+ SourceText.From(source, Encoding.UTF8));
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptBoilerplateGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptBoilerplateGenerator.cs
index 5ace809d95..51e9406c15 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptBoilerplateGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptBoilerplateGenerator.cs
@@ -16,8 +16,6 @@ namespace Godot.SourceGenerators
if (context.AreGodotSourceGeneratorsDisabled())
return;
- // False positive for RS1024. We're already using `SymbolEqualityComparer.Default`...
-#pragma warning disable RS1024
INamedTypeSymbol[] godotClasses = context
.Compilation.SyntaxTrees
.SelectMany(tree =>
@@ -28,7 +26,16 @@ namespace Godot.SourceGenerators
.Where(x =>
{
if (x.cds.IsPartial())
+ {
+ if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial))
+ {
+ Common.ReportNonPartialGodotScriptOuterClass(context, typeMissingPartial!);
+ return false;
+ }
+
return true;
+ }
+
Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol);
return false;
})
@@ -36,7 +43,6 @@ namespace Godot.SourceGenerators
)
.Distinct<INamedTypeSymbol>(SymbolEqualityComparer.Default)
.ToArray();
-#pragma warning restore RS1024
if (godotClasses.Length > 0)
{
@@ -63,6 +69,8 @@ namespace Godot.SourceGenerators
string.Empty;
bool hasNamespace = classNs.Length != 0;
+ bool isInnerClass = symbol.ContainingType != null;
+
string uniqueName = hasNamespace ?
classNs + "." + className + "_ScriptBoilerplate_Generated" :
className + "_ScriptBoilerplate_Generated";
@@ -80,6 +88,22 @@ namespace Godot.SourceGenerators
source.Append(" {\n\n");
}
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("partial ");
+ source.Append(containingType.GetDeclarationKeyword());
+ source.Append(" ");
+ source.Append(containingType.Name);
+ source.Append("\n{\n");
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
source.Append("partial class ");
source.Append(className);
source.Append("\n{\n");
@@ -102,15 +126,15 @@ namespace Godot.SourceGenerators
.Cast<IFieldSymbol>()
.Where(p => !p.IsImplicitlyDeclared);
- var methods = WhereHasCompatibleGodotType(methodSymbols, typeCache).ToArray();
- var properties = WhereIsCompatibleGodotType(propertySymbols, typeCache).ToArray();
- var fields = WhereIsCompatibleGodotType(fieldSymbols, typeCache).ToArray();
+ var godotClassMethods = WhereHasCompatibleGodotType(methodSymbols, typeCache).ToArray();
+ var godotClassProperties = WhereIsCompatibleGodotType(propertySymbols, typeCache).ToArray();
+ var godotClassFields = WhereIsCompatibleGodotType(fieldSymbols, typeCache).ToArray();
source.Append(" private class GodotInternal {\n");
// Generate cached StringNames for methods and properties, for fast lookup
- foreach (var method in methods)
+ foreach (var method in godotClassMethods)
{
string methodName = method.Method.Name;
source.Append(" public static readonly StringName MethodName_");
@@ -120,7 +144,7 @@ namespace Godot.SourceGenerators
source.Append("\";\n");
}
- foreach (var property in properties)
+ foreach (var property in godotClassProperties)
{
string propertyName = property.Property.Name;
source.Append(" public static readonly StringName PropName_");
@@ -130,7 +154,7 @@ namespace Godot.SourceGenerators
source.Append("\";\n");
}
- foreach (var field in fields)
+ foreach (var field in godotClassFields)
{
string fieldName = field.Field.Name;
source.Append(" public static readonly StringName PropName_");
@@ -140,14 +164,16 @@ namespace Godot.SourceGenerators
source.Append("\";\n");
}
- source.Append(" }\n");
+ source.Append(" }\n"); // class GodotInternal
+
+ // Generate InvokeGodotClassMethod
- if (methods.Length > 0)
+ if (godotClassMethods.Length > 0)
{
source.Append(" protected override bool InvokeGodotClassMethod(in godot_string_name method, ");
source.Append("NativeVariantPtrArgs args, int argCount, out godot_variant ret)\n {\n");
- foreach (var method in methods)
+ foreach (var method in godotClassMethods)
{
GenerateMethodInvoker(method, source);
}
@@ -157,42 +183,64 @@ namespace Godot.SourceGenerators
source.Append(" }\n");
}
- if (properties.Length > 0 || fields.Length > 0)
+ // Generate Set/GetGodotClassPropertyValue
+
+ if (godotClassProperties.Length > 0 || godotClassFields.Length > 0)
{
+ bool isFirstEntry;
+
// Setters
- source.Append(" protected override bool SetGodotClassPropertyValue(in godot_string_name name, ");
- source.Append("in godot_variant value)\n {\n");
+ bool allPropertiesAreReadOnly = godotClassFields.All(fi => fi.Field.IsReadOnly) &&
+ godotClassProperties.All(pi => pi.Property.IsReadOnly);
- foreach (var property in properties)
+ if (!allPropertiesAreReadOnly)
{
- GeneratePropertySetter(property.Property.Name,
- property.Property.Type.FullQualifiedName(), source);
- }
+ source.Append(" protected override bool SetGodotClassPropertyValue(in godot_string_name name, ");
+ source.Append("in godot_variant value)\n {\n");
- foreach (var field in fields)
- {
- GeneratePropertySetter(field.Field.Name,
- field.Field.Type.FullQualifiedName(), source);
- }
+ isFirstEntry = true;
+ foreach (var property in godotClassProperties)
+ {
+ if (property.Property.IsReadOnly)
+ continue;
- source.Append(" return base.SetGodotClassPropertyValue(name, value);\n");
+ GeneratePropertySetter(property.Property.Name,
+ property.Property.Type.FullQualifiedName(), source, isFirstEntry);
+ isFirstEntry = false;
+ }
- source.Append(" }\n");
+ foreach (var field in godotClassFields)
+ {
+ if (field.Field.IsReadOnly)
+ continue;
+
+ GeneratePropertySetter(field.Field.Name,
+ field.Field.Type.FullQualifiedName(), source, isFirstEntry);
+ isFirstEntry = false;
+ }
+
+ source.Append(" return base.SetGodotClassPropertyValue(name, value);\n");
+
+ source.Append(" }\n");
+ }
// Getters
source.Append(" protected override bool GetGodotClassPropertyValue(in godot_string_name name, ");
source.Append("out godot_variant value)\n {\n");
- foreach (var property in properties)
+ isFirstEntry = true;
+ foreach (var property in godotClassProperties)
{
- GeneratePropertyGetter(property.Property.Name, source);
+ GeneratePropertyGetter(property.Property.Name, source, isFirstEntry);
+ isFirstEntry = false;
}
- foreach (var field in fields)
+ foreach (var field in godotClassFields)
{
- GeneratePropertyGetter(field.Field.Name, source);
+ GeneratePropertyGetter(field.Field.Name, source, isFirstEntry);
+ isFirstEntry = false;
}
source.Append(" return base.GetGodotClassPropertyValue(name, out value);\n");
@@ -200,7 +248,37 @@ namespace Godot.SourceGenerators
source.Append(" }\n");
}
- source.Append("}\n");
+ // Generate HasGodotClassMethod
+
+ if (godotClassMethods.Length > 0)
+ {
+ source.Append(" protected override bool HasGodotClassMethod(in godot_string_name method)\n {\n");
+
+ bool isFirstEntry = true;
+ foreach (var method in godotClassMethods)
+ {
+ GenerateHasMethodEntry(method, source, isFirstEntry);
+ isFirstEntry = false;
+ }
+
+ source.Append(" return base.HasGodotClassMethod(method);\n");
+
+ source.Append(" }\n");
+ }
+
+ source.Append("}\n"); // partial class
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("}\n"); // outer class
+
+ containingType = containingType.ContainingType;
+ }
+ }
if (hasNamespace)
{
@@ -269,10 +347,14 @@ namespace Godot.SourceGenerators
private static void GeneratePropertySetter(
string propertyMemberName,
string propertyTypeQualifiedName,
- StringBuilder source
+ StringBuilder source,
+ bool isFirstEntry
)
{
- source.Append(" if (name == GodotInternal.PropName_");
+ source.Append(" ");
+ if (!isFirstEntry)
+ source.Append("else ");
+ source.Append("if (name == GodotInternal.PropName_");
source.Append(propertyMemberName);
source.Append(") {\n");
@@ -295,10 +377,14 @@ namespace Godot.SourceGenerators
private static void GeneratePropertyGetter(
string propertyMemberName,
- StringBuilder source
+ StringBuilder source,
+ bool isFirstEntry
)
{
- source.Append(" if (name == GodotInternal.PropName_");
+ source.Append(" ");
+ if (!isFirstEntry)
+ source.Append("else ");
+ source.Append("if (name == GodotInternal.PropName_");
source.Append(propertyMemberName);
source.Append(") {\n");
@@ -312,6 +398,22 @@ namespace Godot.SourceGenerators
source.Append(" }\n");
}
+ private static void GenerateHasMethodEntry(
+ GodotMethodInfo method,
+ StringBuilder source,
+ bool isFirstEntry
+ )
+ {
+ string methodName = method.Method.Name;
+
+ source.Append(" ");
+ if (!isFirstEntry)
+ source.Append("else ");
+ source.Append("if (method == GodotInternal.MethodName_");
+ source.Append(methodName);
+ source.Append(") {\n return true;\n }\n");
+ }
+
public void Initialize(GeneratorInitializationContext context)
{
}
@@ -376,12 +478,17 @@ namespace Godot.SourceGenerators
var parameters = method.Parameters;
- var paramTypes = parameters.Select(p =>
- MarshalUtils.ConvertManagedTypeToVariantType(p.Type, typeCache))
+ var paramTypes = parameters
+ // Currently we don't support `ref`, `out`, `in`, `ref readonly` parameters (and we never may)
+ .Where(p => p.RefKind == RefKind.None)
+ // Attempt to determine the variant type
+ .Select(p => MarshalUtils.ConvertManagedTypeToVariantType(p.Type, typeCache))
+ // Discard parameter types that couldn't be determined (null entries)
.Where(t => t != null).Cast<MarshalType>().ToImmutableArray();
+ // If any parameter type was incompatible, it was discarded so the length won't match
if (parameters.Length > paramTypes.Length)
- continue; // Some param types weren't compatible
+ continue; // Ignore incompatible method
yield return new GodotMethodInfo(method, paramTypes, parameters
.Select(p => p.Type).ToImmutableArray(), retType);
@@ -395,6 +502,10 @@ namespace Godot.SourceGenerators
{
foreach (var property in properties)
{
+ // Ignore properties without a getter. Godot properties must be readable.
+ if (property.IsWriteOnly)
+ continue;
+
var marshalType = MarshalUtils.ConvertManagedTypeToVariantType(property.Type, typeCache);
if (marshalType == null)
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 f0b2758342..b625287087 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
@@ -17,6 +17,9 @@ namespace Godot.SourceGenerators
if (context.AreGodotSourceGeneratorsDisabled())
return;
+ if (context.IsGodotToolsProject())
+ return;
+
// NOTE: NotNullWhen diagnostics don't work on projects targeting .NET Standard 2.0
// ReSharper disable once ReplaceWithStringIsNullOrEmpty
if (!context.TryGetGlobalAnalyzerProperty("GodotProjectDir", out string? godotProjectDir)
@@ -31,7 +34,7 @@ namespace Godot.SourceGenerators
tree.GetRoot().DescendantNodes()
.OfType<ClassDeclarationSyntax>()
// Ignore inner classes
- .Where(cds => !(cds.Parent is ClassDeclarationSyntax))
+ .Where(cds => !cds.IsNested())
.SelectGodotScriptClasses(context.Compilation)
// Report and skip non-partial classes
.Where(x =>