mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 13:41:03 +00:00 
			
		
		
		
	 88e367a406
			
		
	
	
		88e367a406
		
	
	
	
	
		
			
			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.
		
			
				
	
	
		
			135 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
	
		
			4.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using Microsoft.CodeAnalysis;
 | |
| using Microsoft.CodeAnalysis.CSharp;
 | |
| using Microsoft.CodeAnalysis.CSharp.Syntax;
 | |
| 
 | |
| 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);
 | |
| 
 | |
|         public static bool AreGodotSourceGeneratorsDisabled(this GeneratorExecutionContext context)
 | |
|             => context.TryGetGlobalAnalyzerProperty("GodotSourceGenerators", out string? toggle) &&
 | |
|                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)
 | |
|                 return false;
 | |
| 
 | |
|             while (true)
 | |
|             {
 | |
|                 if (symbol.ToString() == baseName)
 | |
|                 {
 | |
|                     return true;
 | |
|                 }
 | |
| 
 | |
|                 if (symbol.BaseType != null)
 | |
|                 {
 | |
|                     symbol = symbol.BaseType;
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         private static bool IsGodotScriptClass(
 | |
|             this ClassDeclarationSyntax cds, Compilation compilation,
 | |
|             out INamedTypeSymbol? symbol
 | |
|         )
 | |
|         {
 | |
|             var sm = compilation.GetSemanticModel(cds.SyntaxTree);
 | |
| 
 | |
|             var classTypeSymbol = sm.GetDeclaredSymbol(cds);
 | |
| 
 | |
|             if (classTypeSymbol?.BaseType == null
 | |
|                 || !classTypeSymbol.BaseType.InheritsFrom(GodotClasses.Object))
 | |
|             {
 | |
|                 symbol = null;
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             symbol = classTypeSymbol;
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         public static IEnumerable<(ClassDeclarationSyntax cds, INamedTypeSymbol symbol)> SelectGodotScriptClasses(
 | |
|             this IEnumerable<ClassDeclarationSyntax> source,
 | |
|             Compilation compilation
 | |
|         )
 | |
|         {
 | |
|             foreach (var cds in source)
 | |
|             {
 | |
|                 if (cds.IsGodotScriptClass(compilation, out var symbol))
 | |
|                     yield return (cds, symbol!);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         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);
 | |
| 
 | |
|         public static string FullQualifiedName(this ITypeSymbol symbol)
 | |
|             => symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal);
 | |
| 
 | |
|         public static string FullQualifiedName(this INamespaceSymbol namespaceSymbol)
 | |
|             => namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
 | |
|     }
 | |
| }
 |