From d94f562e3f8dc43b4d696d361ffaadee68cacb39 Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Thu, 25 Aug 2022 17:20:58 +0200 Subject: [PATCH] Make C# source generators incremental --- .../Godot.SourceGenerators/Common.cs | 23 ++-- .../ExtensionMethods.cs | 43 ++++--- .../Godot.SourceGenerators.csproj | 4 +- .../Godot.SourceGenerators/GodotClassData.cs | 17 +++ .../GodotPluginsInitializerGenerator.cs | 18 ++- .../ScriptMethodsGenerator.cs | 75 ++++++------ .../ScriptPathAttributeGenerator.cs | 112 +++++++++++------- .../ScriptPropertiesGenerator.cs | 77 ++++++------ .../ScriptPropertyDefValGenerator.cs | 85 +++++++------ .../ScriptSerializationGenerator.cs | 75 ++++++------ .../ScriptSignalsGenerator.cs | 71 ++++++----- .../Godot.SourceGenerators.Internal/Common.cs | 7 +- .../ExtensionMethods.cs | 46 +++---- .../Godot.SourceGenerators.Internal.csproj | 2 +- .../UnmanagedCallbacksGenerator.cs | 103 ++++++++-------- 15 files changed, 423 insertions(+), 335 deletions(-) create mode 100644 modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClassData.cs 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 4eed2d7b7b20..4cff5d9d2da2 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs @@ -8,7 +8,7 @@ namespace Godot.SourceGenerators public static class Common { public static void ReportNonPartialGodotScriptClass( - GeneratorExecutionContext context, + SourceProductionContext context, ClassDeclarationSyntax cds, INamedTypeSymbol symbol ) { @@ -32,11 +32,12 @@ public static void ReportNonPartialGodotScriptClass( } public static void ReportNonPartialGodotScriptOuterClass( - GeneratorExecutionContext context, + SourceProductionContext context, + Compilation compilation, TypeDeclarationSyntax outerTypeDeclSyntax ) { - var outerSymbol = context.Compilation + var outerSymbol = compilation .GetSemanticModel(outerTypeDeclSyntax.SyntaxTree) .GetDeclaredSymbol(outerTypeDeclSyntax); @@ -64,7 +65,7 @@ TypeDeclarationSyntax outerTypeDeclSyntax } public static void ReportExportedMemberIsStatic( - GeneratorExecutionContext context, + SourceProductionContext context, ISymbol exportedMemberSymbol ) { @@ -91,7 +92,7 @@ ISymbol exportedMemberSymbol } public static void ReportExportedMemberTypeNotSupported( - GeneratorExecutionContext context, + SourceProductionContext context, ISymbol exportedMemberSymbol ) { @@ -117,7 +118,7 @@ ISymbol exportedMemberSymbol } public static void ReportExportedMemberIsReadOnly( - GeneratorExecutionContext context, + SourceProductionContext context, ISymbol exportedMemberSymbol ) { @@ -145,7 +146,7 @@ ISymbol exportedMemberSymbol } public static void ReportExportedMemberIsWriteOnly( - GeneratorExecutionContext context, + SourceProductionContext context, ISymbol exportedMemberSymbol ) { @@ -169,7 +170,7 @@ ISymbol exportedMemberSymbol } public static void ReportExportedMemberIsIndexer( - GeneratorExecutionContext context, + SourceProductionContext context, ISymbol exportedMemberSymbol ) { @@ -195,7 +196,7 @@ ISymbol exportedMemberSymbol } public static void ReportSignalDelegateMissingSuffix( - GeneratorExecutionContext context, + SourceProductionContext context, INamedTypeSymbol delegateSymbol) { var locations = delegateSymbol.Locations; @@ -220,7 +221,7 @@ public static void ReportSignalDelegateMissingSuffix( } public static void ReportSignalParameterTypeNotSupported( - GeneratorExecutionContext context, + SourceProductionContext context, IParameterSymbol parameterSymbol) { var locations = parameterSymbol.Locations; @@ -244,7 +245,7 @@ public static void ReportSignalParameterTypeNotSupported( } public static void ReportSignalDelegateSignatureMustReturnVoid( - GeneratorExecutionContext context, + SourceProductionContext context, INamedTypeSymbol delegateSymbol) { var locations = delegateSymbol.Locations; 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 8852b7ebad07..6f9fcab84e06 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs @@ -3,25 +3,26 @@ using System.Collections.Immutable; using System.Linq; using System.Text; +using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; namespace Godot.SourceGenerators { static class ExtensionMethods { public static bool TryGetGlobalAnalyzerProperty( - this GeneratorExecutionContext context, string property, out string? value - ) => context.AnalyzerConfigOptions.GlobalOptions - .TryGetValue("build_property." + property, out value); + this AnalyzerConfigOptionsProvider provider, string property, out string? value + ) => provider.GlobalOptions.TryGetValue("build_property." + property, out value); - public static bool AreGodotSourceGeneratorsDisabled(this GeneratorExecutionContext context) + public static bool AreGodotSourceGeneratorsDisabled(this AnalyzerConfigOptionsProvider context) => context.TryGetGlobalAnalyzerProperty("GodotSourceGenerators", out string? toggle) && toggle != null && toggle.Equals("disabled", StringComparison.OrdinalIgnoreCase); - public static bool IsGodotToolsProject(this GeneratorExecutionContext context) + public static bool IsGodotToolsProject(this AnalyzerConfigOptionsProvider context) => context.TryGetGlobalAnalyzerProperty("IsGodotToolsProject", out string? toggle) && toggle != null && toggle.Equals("true", StringComparison.OrdinalIgnoreCase); @@ -69,19 +70,17 @@ public static bool InheritsFrom(this INamedTypeSymbol? symbol, string assemblyNa string? godotClassName = null; - if (godotClassNameAttr is { ConstructorArguments: { Length: > 0 } }) + if (godotClassNameAttr is { ConstructorArguments.Length: > 0 }) godotClassName = godotClassNameAttr.ConstructorArguments[0].Value?.ToString(); return godotClassName ?? nativeType.Name; } - private static bool IsGodotScriptClass( - this ClassDeclarationSyntax cds, Compilation compilation, + public static bool IsGodotScriptClass( + this ClassDeclarationSyntax cds, SemanticModel sm, out INamedTypeSymbol? symbol ) { - var sm = compilation.GetSemanticModel(cds.SyntaxTree); - var classTypeSymbol = sm.GetDeclaredSymbol(cds); if (classTypeSymbol?.BaseType == null @@ -95,16 +94,22 @@ out INamedTypeSymbol? symbol return true; } - public static IEnumerable<(ClassDeclarationSyntax cds, INamedTypeSymbol symbol)> SelectGodotScriptClasses( - this IEnumerable source, - Compilation compilation - ) + public static IncrementalValuesProvider CreateValuesProviderForGodotClasses(this SyntaxValueProvider provider, Func? customPredicate = null, Func? customTransform = null) { - foreach (var cds in source) - { - if (cds.IsGodotScriptClass(compilation, out var symbol)) - yield return (cds, symbol!); - } + return provider.CreateSyntaxProvider( + // By default select class declarations that inherit from something + // since Godot classes must at least inherit from Godot.Object + predicate: customPredicate ?? (static (s, _) => s is ClassDeclarationSyntax { BaseList.Types.Count: > 0 }), + // Filter out non-Godot classes and retrieve the symbol + transform: customTransform ?? (static (ctx, _) => + { + var cds = (ClassDeclarationSyntax)ctx.Node; + if (!cds.IsGodotScriptClass(ctx.SemanticModel, out var symbol)) + return default; + + return new GodotClassData(cds, symbol); + }) + ).Where(static x => x.Symbol is not null); } public static bool IsNested(this TypeDeclarationSyntax cds) 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 f51b5970c36e..d78276a69426 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 @@ -1,7 +1,7 @@ netstandard2.0 - 9.0 + 10.0 enable @@ -20,7 +20,7 @@ false - + diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClassData.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClassData.cs new file mode 100644 index 000000000000..ee4dff424adf --- /dev/null +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClassData.cs @@ -0,0 +1,17 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Godot.SourceGenerators +{ + public readonly struct GodotClassData + { + public GodotClassData(ClassDeclarationSyntax cds, INamedTypeSymbol symbol) + { + DeclarationSyntax = cds; + Symbol = symbol; + } + + public ClassDeclarationSyntax DeclarationSyntax { get; } + public INamedTypeSymbol Symbol { get; } + } +} diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs index 19fdd51dabbf..3d3a7eccbc7e 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs @@ -5,17 +5,23 @@ namespace Godot.SourceGenerators { [Generator] - public class GodotPluginsInitializerGenerator : ISourceGenerator + public class GodotPluginsInitializerGenerator : IIncrementalGenerator { - public void Initialize(GeneratorInitializationContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { + var isGodotToolsProject = context.AnalyzerConfigOptionsProvider.Select((provider, _) => provider.IsGodotToolsProject()); + + context.RegisterSourceOutput(isGodotToolsProject, static (spc, source) => + { + if (source) + return; + + Execute(spc); + }); } - public void Execute(GeneratorExecutionContext context) + private static void Execute(SourceProductionContext context) { - if (context.IsGodotToolsProject()) - return; - string source = @"using System; using System.Runtime.InteropServices; diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs index f79909589ef9..045a2004b0ef 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs @@ -1,55 +1,62 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; namespace Godot.SourceGenerators { [Generator] - public class ScriptMethodsGenerator : ISourceGenerator + public class ScriptMethodsGenerator : IIncrementalGenerator { - public void Initialize(GeneratorInitializationContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { + var areGodotSourceGeneratorsDisabled = context.AnalyzerConfigOptionsProvider.Select(static (provider, _) => provider.AreGodotSourceGeneratorsDisabled()); + + var godotClasses = context.SyntaxProvider.CreateValuesProviderForGodotClasses(); + + var values = areGodotSourceGeneratorsDisabled + .Combine(context.CompilationProvider) + .Combine(godotClasses.Collect()); + + context.RegisterSourceOutput(values, static (spc, source) => + { + (bool areGodotSourceGeneratorsDisabled, Compilation compilation) = source.Left; + var godotClasses = source.Right; + + if (areGodotSourceGeneratorsDisabled) + return; + + Execute(spc, compilation, godotClasses); + }); } - public void Execute(GeneratorExecutionContext context) + private static void Execute(SourceProductionContext context, Compilation compilation, ImmutableArray godotClassDatas) { - if (context.AreGodotSourceGeneratorsDisabled()) - return; - - INamedTypeSymbol[] godotClasses = context - .Compilation.SyntaxTrees - .SelectMany(tree => - tree.GetRoot().DescendantNodes() - .OfType() - .SelectGodotScriptClasses(context.Compilation) - // Report and skip non-partial classes - .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; - }) - .Select(x => x.symbol) - ) + INamedTypeSymbol[] godotClasses = godotClassDatas.Where(x => + { + // Report and skip non-partial classes + if (x.DeclarationSyntax.IsPartial()) + { + if (x.DeclarationSyntax.IsNested() && !x.DeclarationSyntax.AreAllOuterTypesPartial(out var typeMissingPartial)) + { + Common.ReportNonPartialGodotScriptOuterClass(context, compilation, typeMissingPartial); + return false; + } + + return true; + } + + Common.ReportNonPartialGodotScriptClass(context, x.DeclarationSyntax, x.Symbol); + return false; + }).Select(x => x.Symbol) .Distinct(SymbolEqualityComparer.Default) .ToArray(); if (godotClasses.Length > 0) { - var typeCache = new MarshalUtils.TypeCache(context.Compilation); + var typeCache = new MarshalUtils.TypeCache(compilation); foreach (var godotClass in godotClasses) { @@ -73,7 +80,7 @@ public int GetHashCode(GodotMethodData obj) } private static void VisitGodotScriptClass( - GeneratorExecutionContext context, + SourceProductionContext context, MarshalUtils.TypeCache typeCache, INamedTypeSymbol symbol ) 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 eae7e41da805..4566199bc8b4 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.IO; using System.Linq; using System.Text; @@ -10,48 +11,79 @@ namespace Godot.SourceGenerators { [Generator] - public class ScriptPathAttributeGenerator : ISourceGenerator + public class ScriptPathAttributeGenerator : IIncrementalGenerator { - public void Execute(GeneratorExecutionContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { - if (context.AreGodotSourceGeneratorsDisabled()) - return; + var areGodotSourceGeneratorsDisabled = context.AnalyzerConfigOptionsProvider.Select(static (provider, _) => provider.AreGodotSourceGeneratorsDisabled()); - if (context.IsGodotToolsProject()) - return; + var isGodotToolsProject = context.AnalyzerConfigOptionsProvider.Select(static (provider, _) => provider.IsGodotToolsProject()); - // NOTE: NotNullWhen diagnostics don't work on projects targeting .NET Standard 2.0 - // ReSharper disable once ReplaceWithStringIsNullOrEmpty - if (!context.TryGetGlobalAnalyzerProperty("GodotProjectDir", out string? godotProjectDir) - || godotProjectDir!.Length == 0) + var godotProjectDir = context.AnalyzerConfigOptionsProvider.Select(static (provider, _) => { - throw new InvalidOperationException("Property 'GodotProjectDir' is null or empty."); - } + provider.TryGetGlobalAnalyzerProperty("GodotProjectDir", out string? godotProjectDir); + return godotProjectDir; + }); + + var godotClasses = context.SyntaxProvider.CreateValuesProviderForGodotClasses( + // Select class declarations that inherit from something + // since Godot classes must at least inherit from Godot.Object + customPredicate: static (s, _) => s is ClassDeclarationSyntax { BaseList.Types.Count: > 0 } cds && + // Ignore inner classes + !cds.IsNested()); + + var configValues = areGodotSourceGeneratorsDisabled + .Combine(isGodotToolsProject) + .Combine(godotProjectDir); + + var values = configValues.Combine(godotClasses.Collect()); + + context.RegisterSourceOutput(values, static (spc, source) => + { + var configValues = source.Left; + var godotClasses = source.Right; + + ((bool areGodotSourceGeneratorsDisabled, bool isGodotToolsProject), string? godotProjectDir) = configValues; + + if (areGodotSourceGeneratorsDisabled) + return; + + if (isGodotToolsProject) + return; - Dictionary> godotClasses = context - .Compilation.SyntaxTrees - .SelectMany(tree => - tree.GetRoot().DescendantNodes() - .OfType() - // Ignore inner classes - .Where(cds => !cds.IsNested()) - .SelectGodotScriptClasses(context.Compilation) - // Report and skip non-partial classes - .Where(x => - { - if (x.cds.IsPartial()) - return true; - Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol); - return false; - }) - ) - .Where(x => - // Ignore classes whose name is not the same as the file name - Path.GetFileNameWithoutExtension(x.cds.SyntaxTree.FilePath) == x.symbol.Name && - // Ignore generic classes - !x.symbol.IsGenericType) - .GroupBy(x => x.symbol) - .ToDictionary(g => g.Key, g => g.Select(x => x.cds)); + // NOTE: NotNullWhen diagnostics don't work on projects targeting .NET Standard 2.0 + // ReSharper disable once ReplaceWithStringIsNullOrEmpty + if (string.IsNullOrEmpty(godotProjectDir) || godotProjectDir!.Length == 0) + { + throw new InvalidOperationException("Property 'GodotProjectDir' is null or empty."); + } + + Execute(spc, godotClasses, godotProjectDir); + }); + } + + private static void Execute(SourceProductionContext context, ImmutableArray godotClassDatas, string godotProjectDir) + { + Dictionary> godotClasses = godotClassDatas.Where(x => + { + // Report and skip non-partial classes + if (!x.DeclarationSyntax.IsPartial()) + { + Common.ReportNonPartialGodotScriptClass(context, x.DeclarationSyntax, x.Symbol); + return false; + } + + // Ignore classes whose name is not the same as the file name + if (Path.GetFileNameWithoutExtension(x.DeclarationSyntax.SyntaxTree.FilePath) != x.Symbol.Name) + return false; + + // Ignore generic classes + if (x.Symbol.IsGenericType) + return false; + + return true; + }).GroupBy(x => x.Symbol, SymbolEqualityComparer.Default) + .ToDictionary, INamedTypeSymbol, IEnumerable>(g => g.Key, g => g.Select(x => x.DeclarationSyntax), SymbolEqualityComparer.Default); foreach (var godotClass in godotClasses) { @@ -67,7 +99,7 @@ public void Execute(GeneratorExecutionContext context) } private static void VisitGodotScriptClass( - GeneratorExecutionContext context, + SourceProductionContext context, string godotProjectDir, INamedTypeSymbol symbol, IEnumerable classDeclarations @@ -132,7 +164,7 @@ IEnumerable classDeclarations context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8)); } - private static void AddScriptTypesAssemblyAttr(GeneratorExecutionContext context, + private static void AddScriptTypesAssemblyAttr(SourceProductionContext context, Dictionary> godotClasses) { var sourceBuilder = new StringBuilder(); @@ -162,10 +194,6 @@ private static void AddScriptTypesAssemblyAttr(GeneratorExecutionContext context SourceText.From(sourceBuilder.ToString(), Encoding.UTF8)); } - public void Initialize(GeneratorInitializationContext context) - { - } - private static string RelativeToDir(string path, string dir) { // Make sure the directory ends with a path separator diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs index b64b843b7c36..0274017c37c5 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs @@ -1,55 +1,62 @@ +using System.Collections.Immutable; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; namespace Godot.SourceGenerators { [Generator] - public class ScriptPropertiesGenerator : ISourceGenerator + public class ScriptPropertiesGenerator : IIncrementalGenerator { - public void Initialize(GeneratorInitializationContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { + var areGodotSourceGeneratorsDisabled = context.AnalyzerConfigOptionsProvider.Select(static (provider, _) => provider.AreGodotSourceGeneratorsDisabled()); + + var godotClasses = context.SyntaxProvider.CreateValuesProviderForGodotClasses(); + + var values = areGodotSourceGeneratorsDisabled + .Combine(context.CompilationProvider) + .Combine(godotClasses.Collect()); + + context.RegisterSourceOutput(values, static (spc, source) => + { + (bool areGodotSourceGeneratorsDisabled, Compilation compilation) = source.Left; + var godotClasses = source.Right; + + if (areGodotSourceGeneratorsDisabled) + return; + + Execute(spc, compilation, godotClasses); + }); } - public void Execute(GeneratorExecutionContext context) + private static void Execute(SourceProductionContext context, Compilation compilation, ImmutableArray godotClassDatas) { - if (context.AreGodotSourceGeneratorsDisabled()) - return; - - INamedTypeSymbol[] godotClasses = context - .Compilation.SyntaxTrees - .SelectMany(tree => - tree.GetRoot().DescendantNodes() - .OfType() - .SelectGodotScriptClasses(context.Compilation) - // Report and skip non-partial classes - .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; - }) - .Select(x => x.symbol) - ) + INamedTypeSymbol[] godotClasses = godotClassDatas.Where(x => + { + // Report and skip non-partial classes + if (x.DeclarationSyntax.IsPartial()) + { + if (x.DeclarationSyntax.IsNested() && !x.DeclarationSyntax.AreAllOuterTypesPartial(out var typeMissingPartial)) + { + Common.ReportNonPartialGodotScriptOuterClass(context, compilation, typeMissingPartial); + return false; + } + + return true; + } + + Common.ReportNonPartialGodotScriptClass(context, x.DeclarationSyntax, x.Symbol); + return false; + }).Select(x => x.Symbol) .Distinct(SymbolEqualityComparer.Default) .ToArray(); if (godotClasses.Length > 0) { - var typeCache = new MarshalUtils.TypeCache(context.Compilation); + var typeCache = new MarshalUtils.TypeCache(compilation); foreach (var godotClass in godotClasses) { @@ -59,7 +66,7 @@ public void Execute(GeneratorExecutionContext context) } private static void VisitGodotScriptClass( - GeneratorExecutionContext context, + SourceProductionContext context, MarshalUtils.TypeCache typeCache, INamedTypeSymbol symbol ) @@ -386,7 +393,7 @@ private static IEnumerable DetermineGroupingPropertyInfo(ISymbol m } private static PropertyInfo? DeterminePropertyInfo( - GeneratorExecutionContext context, + SourceProductionContext context, MarshalUtils.TypeCache typeCache, ISymbol memberSymbol, MarshalType marshalType diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs index 99a4c95e73b2..3e7b66c5228f 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; @@ -9,58 +10,66 @@ namespace Godot.SourceGenerators { [Generator] - public class ScriptPropertyDefValGenerator : ISourceGenerator + public class ScriptPropertyDefValGenerator : IIncrementalGenerator { - public void Initialize(GeneratorInitializationContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { + var areGodotSourceGeneratorsDisabled = context.AnalyzerConfigOptionsProvider.Select(static (provider, _) => provider.AreGodotSourceGeneratorsDisabled()); + + var godotClasses = context.SyntaxProvider.CreateValuesProviderForGodotClasses(); + + var values = areGodotSourceGeneratorsDisabled + .Combine(context.CompilationProvider) + .Combine(godotClasses.Collect()); + + context.RegisterSourceOutput(values, static (spc, source) => + { + (bool areGodotSourceGeneratorsDisabled, Compilation compilation) = source.Left; + var godotClasses = source.Right; + + if (areGodotSourceGeneratorsDisabled) + return; + + Execute(spc, compilation, godotClasses); + }); } - public void Execute(GeneratorExecutionContext context) + private static void Execute(SourceProductionContext context, Compilation compilation, ImmutableArray godotClassDatas) { - if (context.AreGodotSourceGeneratorsDisabled()) - return; - - INamedTypeSymbol[] godotClasses = context - .Compilation.SyntaxTrees - .SelectMany(tree => - tree.GetRoot().DescendantNodes() - .OfType() - .SelectGodotScriptClasses(context.Compilation) - // Report and skip non-partial classes - .Where(x => - { - if (x.cds.IsPartial()) - { - if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial)) - { - Common.ReportNonPartialGodotScriptOuterClass(context, typeMissingPartial!); - return false; - } + INamedTypeSymbol[] godotClasses = godotClassDatas.Where(x => + { + // Report and skip non-partial classes + if (x.DeclarationSyntax.IsPartial()) + { + if (x.DeclarationSyntax.IsNested() && !x.DeclarationSyntax.AreAllOuterTypesPartial(out var typeMissingPartial)) + { + Common.ReportNonPartialGodotScriptOuterClass(context, compilation, typeMissingPartial); + return false; + } - return true; - } + return true; + } - Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol); - return false; - }) - .Select(x => x.symbol) - ) + Common.ReportNonPartialGodotScriptClass(context, x.DeclarationSyntax, x.Symbol); + return false; + }).Select(x => x.Symbol) .Distinct(SymbolEqualityComparer.Default) .ToArray(); if (godotClasses.Length > 0) { - var typeCache = new MarshalUtils.TypeCache(context.Compilation); + var typeCache = new MarshalUtils.TypeCache(compilation); foreach (var godotClass in godotClasses) { - VisitGodotScriptClass(context, typeCache, godotClass); + VisitGodotScriptClass(context, compilation, typeCache, godotClass); } } } private static void VisitGodotScriptClass( - GeneratorExecutionContext context, + SourceProductionContext context, + Compilation compilation, MarshalUtils.TypeCache typeCache, INamedTypeSymbol symbol ) @@ -169,7 +178,7 @@ INamedTypeSymbol symbol { if (propertyDeclarationSyntax.Initializer != null) { - var sm = context.Compilation.GetSemanticModel(propertyDeclarationSyntax.Initializer.SyntaxTree); + var sm = compilation.GetSemanticModel(propertyDeclarationSyntax.Initializer.SyntaxTree); value = propertyDeclarationSyntax.Initializer.Value.FullQualifiedSyntax(sm); } else @@ -182,7 +191,7 @@ INamedTypeSymbol symbol { if (propertyGet.ExpressionBody.Expression is IdentifierNameSyntax identifierNameSyntax) { - var sm = context.Compilation.GetSemanticModel(identifierNameSyntax.SyntaxTree); + var sm = compilation.GetSemanticModel(identifierNameSyntax.SyntaxTree); var fieldSymbol = sm.GetSymbolInfo(identifierNameSyntax).Symbol as IFieldSymbol; EqualsValueClauseSyntax? initializer = fieldSymbol?.DeclaringSyntaxReferences .Select(r => r.GetSyntax()) @@ -192,7 +201,7 @@ INamedTypeSymbol symbol if (initializer != null) { - sm = context.Compilation.GetSemanticModel(initializer.SyntaxTree); + sm = compilation.GetSemanticModel(initializer.SyntaxTree); value = initializer.Value.FullQualifiedSyntax(sm); } } @@ -206,7 +215,7 @@ INamedTypeSymbol symbol var returnStatementSyntax = returns.Single(); if (returnStatementSyntax.Expression is IdentifierNameSyntax identifierNameSyntax) { - var sm = context.Compilation.GetSemanticModel(identifierNameSyntax.SyntaxTree); + var sm = compilation.GetSemanticModel(identifierNameSyntax.SyntaxTree); var fieldSymbol = sm.GetSymbolInfo(identifierNameSyntax).Symbol as IFieldSymbol; EqualsValueClauseSyntax? initializer = fieldSymbol?.DeclaringSyntaxReferences .Select(r => r.GetSyntax()) @@ -216,7 +225,7 @@ INamedTypeSymbol symbol if (initializer != null) { - sm = context.Compilation.GetSemanticModel(initializer.SyntaxTree); + sm = compilation.GetSemanticModel(initializer.SyntaxTree); value = initializer.Value.FullQualifiedSyntax(sm); } } @@ -265,7 +274,7 @@ INamedTypeSymbol symbol string? value = null; if (initializer != null) { - var sm = context.Compilation.GetSemanticModel(initializer.SyntaxTree); + var sm = compilation.GetSemanticModel(initializer.SyntaxTree); value = initializer.Value.FullQualifiedSyntax(sm); } diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs index 821f3af75f04..8a0348eb63df 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs @@ -1,55 +1,62 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; namespace Godot.SourceGenerators { [Generator] - public class ScriptSerializationGenerator : ISourceGenerator + public class ScriptSerializationGenerator : IIncrementalGenerator { - public void Initialize(GeneratorInitializationContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { + var areGodotSourceGeneratorsDisabled = context.AnalyzerConfigOptionsProvider.Select(static (provider, _) => provider.AreGodotSourceGeneratorsDisabled()); + + var godotClasses = context.SyntaxProvider.CreateValuesProviderForGodotClasses(); + + var values = areGodotSourceGeneratorsDisabled + .Combine(context.CompilationProvider) + .Combine(godotClasses.Collect()); + + context.RegisterSourceOutput(values, static (spc, source) => + { + (bool areGodotSourceGeneratorsDisabled, Compilation compilation) = source.Left; + var godotClasses = source.Right; + + if (areGodotSourceGeneratorsDisabled) + return; + + Execute(spc, compilation, godotClasses); + }); } - public void Execute(GeneratorExecutionContext context) + private static void Execute(SourceProductionContext context, Compilation compilation, ImmutableArray godotClassDatas) { - if (context.AreGodotSourceGeneratorsDisabled()) - return; - - INamedTypeSymbol[] godotClasses = context - .Compilation.SyntaxTrees - .SelectMany(tree => - tree.GetRoot().DescendantNodes() - .OfType() - .SelectGodotScriptClasses(context.Compilation) - // Report and skip non-partial classes - .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; - }) - .Select(x => x.symbol) - ) + INamedTypeSymbol[] godotClasses = godotClassDatas.Where(x => + { + // Report and skip non-partial classes + if (x.DeclarationSyntax.IsPartial()) + { + if (x.DeclarationSyntax.IsNested() && !x.DeclarationSyntax.AreAllOuterTypesPartial(out var typeMissingPartial)) + { + Common.ReportNonPartialGodotScriptOuterClass(context, compilation, typeMissingPartial); + return false; + } + + return true; + } + + Common.ReportNonPartialGodotScriptClass(context, x.DeclarationSyntax, x.Symbol); + return false; + }).Select(x => x.Symbol) .Distinct(SymbolEqualityComparer.Default) .ToArray(); if (godotClasses.Length > 0) { - var typeCache = new MarshalUtils.TypeCache(context.Compilation); + var typeCache = new MarshalUtils.TypeCache(compilation); foreach (var godotClass in godotClasses) { @@ -59,7 +66,7 @@ public void Execute(GeneratorExecutionContext context) } private static void VisitGodotScriptClass( - GeneratorExecutionContext context, + SourceProductionContext context, MarshalUtils.TypeCache typeCache, INamedTypeSymbol symbol ) diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs index ba6c10aa312c..9645325e63cc 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs @@ -1,8 +1,8 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Text; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; // TODO: @@ -15,48 +15,55 @@ namespace Godot.SourceGenerators { [Generator] - public class ScriptSignalsGenerator : ISourceGenerator + public class ScriptSignalsGenerator : IIncrementalGenerator { - public void Initialize(GeneratorInitializationContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { + var areGodotSourceGeneratorsDisabled = context.AnalyzerConfigOptionsProvider.Select(static (provider, _) => provider.AreGodotSourceGeneratorsDisabled()); + + var godotClasses = context.SyntaxProvider.CreateValuesProviderForGodotClasses(); + + var values = areGodotSourceGeneratorsDisabled + .Combine(context.CompilationProvider) + .Combine(godotClasses.Collect()); + + context.RegisterSourceOutput(values, static (spc, source) => + { + (bool areGodotSourceGeneratorsDisabled, Compilation compilation) = source.Left; + var godotClasses = source.Right; + + if (areGodotSourceGeneratorsDisabled) + return; + + Execute(spc, compilation, godotClasses); + }); } - public void Execute(GeneratorExecutionContext context) + private static void Execute(SourceProductionContext context, Compilation compilation, ImmutableArray godotClassDatas) { - if (context.AreGodotSourceGeneratorsDisabled()) - return; - - INamedTypeSymbol[] godotClasses = context - .Compilation.SyntaxTrees - .SelectMany(tree => - tree.GetRoot().DescendantNodes() - .OfType() - .SelectGodotScriptClasses(context.Compilation) - // Report and skip non-partial classes - .Where(x => - { - if (x.cds.IsPartial()) - { - if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial)) - { - Common.ReportNonPartialGodotScriptOuterClass(context, typeMissingPartial!); - return false; - } + INamedTypeSymbol[] godotClasses = godotClassDatas.Where(x => + { + // Report and skip non-partial classes + if (x.DeclarationSyntax.IsPartial()) + { + if (x.DeclarationSyntax.IsNested() && !x.DeclarationSyntax.AreAllOuterTypesPartial(out var typeMissingPartial)) + { + Common.ReportNonPartialGodotScriptOuterClass(context, compilation, typeMissingPartial); + return false; + } - return true; - } + return true; + } - Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol); - return false; - }) - .Select(x => x.symbol) - ) + Common.ReportNonPartialGodotScriptClass(context, x.DeclarationSyntax, x.Symbol); + return false; + }).Select(x => x.Symbol) .Distinct(SymbolEqualityComparer.Default) .ToArray(); if (godotClasses.Length > 0) { - var typeCache = new MarshalUtils.TypeCache(context.Compilation); + var typeCache = new MarshalUtils.TypeCache(compilation); foreach (var godotClass in godotClasses) { @@ -68,7 +75,7 @@ public void Execute(GeneratorExecutionContext context) internal static string SignalDelegateSuffix = "EventHandler"; private static void VisitGodotScriptClass( - GeneratorExecutionContext context, + SourceProductionContext context, MarshalUtils.TypeCache typeCache, INamedTypeSymbol symbol ) diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs index d3726d69f0fe..95aef45d3472 100644 --- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs +++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs @@ -6,7 +6,7 @@ namespace Godot.SourceGenerators.Internal; internal static class Common { public static void ReportNonPartialUnmanagedCallbacksClass( - GeneratorExecutionContext context, + SourceProductionContext context, ClassDeclarationSyntax cds, INamedTypeSymbol symbol ) { @@ -30,11 +30,12 @@ public static void ReportNonPartialUnmanagedCallbacksClass( } public static void ReportNonPartialUnmanagedCallbacksOuterClass( - GeneratorExecutionContext context, + SourceProductionContext context, + Compilation compilation, TypeDeclarationSyntax outerTypeDeclSyntax ) { - var outerSymbol = context.Compilation + var outerSymbol = compilation .GetSemanticModel(outerTypeDeclSyntax.SyntaxTree) .GetDeclaredSymbol(outerTypeDeclSyntax); diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs index 37f7005d0159..bb9b0062f5a8 100644 --- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs +++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs @@ -12,46 +12,34 @@ internal static class ExtensionMethods => symbol.GetAttributes() .FirstOrDefault(a => a.AttributeClass?.IsGenerateUnmanagedCallbacksAttribute() ?? false); - private static bool HasGenerateUnmanagedCallbacksAttribute( - this ClassDeclarationSyntax cds, Compilation compilation, + public static bool HasGenerateUnmanagedCallbacksAttribute( + this ClassDeclarationSyntax cds, SemanticModel sm, out INamedTypeSymbol? symbol ) { - var sm = compilation.GetSemanticModel(cds.SyntaxTree); - - var classTypeSymbol = sm.GetDeclaredSymbol(cds); - if (classTypeSymbol == null) + foreach (var attrListSyntax in cds.AttributeLists) { - symbol = null; - return false; - } + foreach (var attrSyntax in attrListSyntax.Attributes) + { + if (sm.GetSymbolInfo(attrSyntax).Symbol is not IMethodSymbol attrSymbol) + continue; - if (!classTypeSymbol.GetAttributes() - .Any(a => a.AttributeClass?.IsGenerateUnmanagedCallbacksAttribute() ?? false)) - { - symbol = null; - return false; + INamedTypeSymbol attrTypeSymbol = attrSymbol.ContainingType; + if (!attrTypeSymbol.IsGenerateUnmanagedCallbacksAttribute()) + continue; + + symbol = sm.GetDeclaredSymbol(cds); + return symbol != null; + } } - symbol = classTypeSymbol; - return true; + symbol = null; + return false; } - private static bool IsGenerateUnmanagedCallbacksAttribute(this INamedTypeSymbol symbol) + public static bool IsGenerateUnmanagedCallbacksAttribute(this INamedTypeSymbol symbol) => symbol.ToString() == GeneratorClasses.GenerateUnmanagedCallbacksAttr; - public static IEnumerable<(ClassDeclarationSyntax cds, INamedTypeSymbol symbol)> SelectUnmanagedCallbacksClasses( - this IEnumerable source, - Compilation compilation - ) - { - foreach (var cds in source) - { - if (cds.HasGenerateUnmanagedCallbacksAttribute(compilation, out var symbol)) - yield return (cds, symbol!); - } - } - public static bool IsNested(this TypeDeclarationSyntax cds) => cds.Parent is TypeDeclarationSyntax; diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj index 4d1a5bb76c0f..05f34a18fca2 100644 --- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj +++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj @@ -5,7 +5,7 @@ enable - + diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs index 3226ca79e58b..db5db42d9128 100644 --- a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs +++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs @@ -4,64 +4,68 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using System.Collections.Immutable; +using System.Diagnostics; namespace Godot.SourceGenerators.Internal; [Generator] -public class UnmanagedCallbacksGenerator : ISourceGenerator +public class UnmanagedCallbacksGenerator : IIncrementalGenerator { - public void Initialize(GeneratorInitializationContext context) + public void Initialize(IncrementalGeneratorInitializationContext context) { - context.RegisterForPostInitialization(ctx => { GenerateAttribute(ctx); }); + context.RegisterPostInitializationOutput(ctx => GenerateAttribute(ctx)); + + var unmanagedCallbacksClasses = context.SyntaxProvider.CreateSyntaxProvider( + predicate: static (s, _) => s is ClassDeclarationSyntax { AttributeLists.Count: > 0 }, + transform: static (ctx, _) => + { + var cds = (ClassDeclarationSyntax)ctx.Node; + + if (!cds.HasGenerateUnmanagedCallbacksAttribute(ctx.SemanticModel, out var symbol)) + return default; + + return (cds, symbol); + } + ).Where(static x => x.symbol is not null); + + var values = context.CompilationProvider.Combine(unmanagedCallbacksClasses.Collect()); + + context.RegisterSourceOutput(values, (spc, source) => + { + Execute(spc, source.Left, source.Right!); + }); } - public void Execute(GeneratorExecutionContext context) + private static void Execute(SourceProductionContext context, Compilation compilation, ImmutableArray<(ClassDeclarationSyntax cds, INamedTypeSymbol symbol)> classesWithAttribute) { - INamedTypeSymbol[] unmanagedCallbacksClasses = context - .Compilation.SyntaxTrees - .SelectMany(tree => - tree.GetRoot().DescendantNodes() - .OfType() - .SelectUnmanagedCallbacksClasses(context.Compilation) - // Report and skip non-partial classes - .Where(x => - { - if (x.cds.IsPartial()) - { - if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial)) - { - Common.ReportNonPartialUnmanagedCallbacksOuterClass(context, typeMissingPartial!); - return false; - } + INamedTypeSymbol[] unmanagedCallbacksClasses = classesWithAttribute.Where(x => + { + // Report and skip non-partial classes + if (x.cds.IsPartial()) + { + if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial)) + { + Common.ReportNonPartialUnmanagedCallbacksOuterClass(context, compilation, typeMissingPartial!); + return false; + } - return true; - } + return true; + } - Common.ReportNonPartialUnmanagedCallbacksClass(context, x.cds, x.symbol); - return false; - }) - .Select(x => x.symbol) - ) + Common.ReportNonPartialUnmanagedCallbacksClass(context, x.cds, x.symbol); + return false; + }).Select(x => x.symbol) .Distinct(SymbolEqualityComparer.Default) .ToArray(); foreach (var symbol in unmanagedCallbacksClasses) { var attr = symbol.GetGenerateUnmanagedCallbacksAttribute(); - if (attr == null || attr.ConstructorArguments.Length != 1) - { - // TODO: Report error or throw exception, this is an invalid case and should never be reached - System.Diagnostics.Debug.Fail("FAILED!"); - continue; - } + Debug.Assert(attr != null && attr.ConstructorArguments.Length == 1); var funcStructType = (INamedTypeSymbol?)attr.ConstructorArguments[0].Value; - if (funcStructType == null) - { - // TODO: Report error or throw exception, this is an invalid case and should never be reached - System.Diagnostics.Debug.Fail("FAILED!"); - continue; - } + Debug.Assert(funcStructType != null); var data = new CallbacksData(symbol, funcStructType); GenerateInteropMethodImplementations(context, data); @@ -69,28 +73,29 @@ public void Execute(GeneratorExecutionContext context) } } - private void GenerateAttribute(GeneratorPostInitializationContext context) + private static void GenerateAttribute(IncrementalGeneratorPostInitializationContext context) { string source = @"using System; namespace Godot.SourceGenerators.Internal { -internal class GenerateUnmanagedCallbacksAttribute : Attribute -{ - public Type FuncStructType { get; } - - public GenerateUnmanagedCallbacksAttribute(Type funcStructType) + [AttributeUsage(AttributeTargets.Class)] + internal class GenerateUnmanagedCallbacksAttribute : Attribute { - FuncStructType = funcStructType; + public Type FuncStructType { get; } + + public GenerateUnmanagedCallbacksAttribute(Type funcStructType) + { + FuncStructType = funcStructType; + } } -} }"; context.AddSource("GenerateUnmanagedCallbacksAttribute.generated", SourceText.From(source, Encoding.UTF8)); } - private void GenerateInteropMethodImplementations(GeneratorExecutionContext context, CallbacksData data) + private static void GenerateInteropMethodImplementations(SourceProductionContext context, CallbacksData data) { var symbol = data.NativeTypeSymbol; @@ -271,7 +276,7 @@ private void GenerateInteropMethodImplementations(GeneratorExecutionContext cont SourceText.From(source.ToString(), Encoding.UTF8)); } - private void GenerateUnmanagedCallbacksStruct(GeneratorExecutionContext context, CallbacksData data) + private static void GenerateUnmanagedCallbacksStruct(SourceProductionContext context, CallbacksData data) { var symbol = data.FuncStructSymbol;