mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-30 21:21:10 +00:00 
			
		
		
		
	
		
			
	
	
		
			120 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			120 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|   | using System.Collections.Generic; | ||
|  | using System.Linq; | ||
|  | using Microsoft.CodeAnalysis; | ||
|  | using Microsoft.CodeAnalysis.CSharp; | ||
|  | using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
|  | 
 | ||
|  | namespace Godot.SourceGenerators.Internal; | ||
|  | 
 | ||
|  | internal static class ExtensionMethods | ||
|  | { | ||
|  |     public static AttributeData? GetGenerateUnmanagedCallbacksAttribute(this INamedTypeSymbol symbol) | ||
|  |         => symbol.GetAttributes() | ||
|  |             .FirstOrDefault(a => a.AttributeClass?.IsGenerateUnmanagedCallbacksAttribute() ?? false); | ||
|  | 
 | ||
|  |     private static bool HasGenerateUnmanagedCallbacksAttribute( | ||
|  |         this ClassDeclarationSyntax cds, Compilation compilation, | ||
|  |         out INamedTypeSymbol? symbol | ||
|  |     ) | ||
|  |     { | ||
|  |         var sm = compilation.GetSemanticModel(cds.SyntaxTree); | ||
|  | 
 | ||
|  |         var classTypeSymbol = sm.GetDeclaredSymbol(cds); | ||
|  |         if (classTypeSymbol == null) | ||
|  |         { | ||
|  |             symbol = null; | ||
|  |             return false; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (!classTypeSymbol.GetAttributes() | ||
|  |                 .Any(a => a.AttributeClass?.IsGenerateUnmanagedCallbacksAttribute() ?? false)) | ||
|  |         { | ||
|  |             symbol = null; | ||
|  |             return false; | ||
|  |         } | ||
|  | 
 | ||
|  |         symbol = classTypeSymbol; | ||
|  |         return true; | ||
|  |     } | ||
|  | 
 | ||
|  |     private static bool IsGenerateUnmanagedCallbacksAttribute(this INamedTypeSymbol symbol) | ||
|  |         => symbol.ToString() == GeneratorClasses.GenerateUnmanagedCallbacksAttr; | ||
|  | 
 | ||
|  |     public static IEnumerable<(ClassDeclarationSyntax cds, INamedTypeSymbol symbol)> SelectUnmanagedCallbacksClasses( | ||
|  |         this IEnumerable<ClassDeclarationSyntax> 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; | ||
|  | 
 | ||
|  |     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 NameWithTypeParameters(this INamedTypeSymbol symbol) | ||
|  |     { | ||
|  |         return symbol.IsGenericType ? | ||
|  |             string.Concat(symbol.Name, "<", string.Join(", ", symbol.TypeParameters), ">") : | ||
|  |             symbol.Name; | ||
|  |     } | ||
|  | 
 | ||
|  |     public static string FullQualifiedName(this INamespaceSymbol symbol) | ||
|  |         => symbol.ToDisplayString(FullyQualifiedFormatOmitGlobal); | ||
|  | 
 | ||
|  |     public static string SanitizeQualifiedNameForUniqueHint(this string qualifiedName) | ||
|  |         => qualifiedName | ||
|  |             // AddSource() doesn't support angle brackets | ||
|  |             .Replace("<", "(Of ") | ||
|  |             .Replace(">", ")"); | ||
|  | } |