| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  | using System; | 
					
						
							| 
									
										
										
										
											2021-03-06 00:12:42 +01:00
										 |  |  | 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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |         public static bool AreGodotSourceGeneratorsDisabled(this GeneratorExecutionContext context) | 
					
						
							|  |  |  |             => context.TryGetGlobalAnalyzerProperty("GodotSourceGenerators", out string? toggle) && | 
					
						
							|  |  |  |                toggle != null && | 
					
						
							|  |  |  |                toggle.Equals("disabled", StringComparison.OrdinalIgnoreCase); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |         public static bool IsGodotToolsProject(this GeneratorExecutionContext context) | 
					
						
							|  |  |  |             => context.TryGetGlobalAnalyzerProperty("IsGodotToolsProject", out string? toggle) && | 
					
						
							|  |  |  |                toggle != null && | 
					
						
							|  |  |  |                toggle.Equals("true", StringComparison.OrdinalIgnoreCase); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-06 00:12:42 +01:00
										 |  |  |         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!); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |         public static bool IsNested(this TypeDeclarationSyntax cds) | 
					
						
							|  |  |  |             => cds.Parent is TypeDeclarationSyntax; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         public static bool IsPartial(this TypeDeclarationSyntax cds) | 
					
						
							| 
									
										
										
										
											2021-03-06 00:12:42 +01:00
										 |  |  |             => cds.Modifiers.Any(SyntaxKind.PartialKeyword); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |         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" | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-06 00:12:42 +01:00
										 |  |  |         private static SymbolDisplayFormat FullyQualifiedFormatOmitGlobal { get; } = | 
					
						
							|  |  |  |             SymbolDisplayFormat.FullyQualifiedFormat | 
					
						
							|  |  |  |                 .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 23:25:16 +01:00
										 |  |  |         public static string FullQualifiedName(this ITypeSymbol symbol) | 
					
						
							| 
									
										
										
										
											2021-03-06 00:12:42 +01:00
										 |  |  |             => symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal); | 
					
						
							| 
									
										
										
										
											2021-03-13 01:04:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         public static string FullQualifiedName(this INamespaceSymbol namespaceSymbol) | 
					
						
							|  |  |  |             => namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal); | 
					
						
							| 
									
										
										
										
											2021-03-06 00:12:42 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } |