using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Speckle.ProxyGenerator.Extensions; internal static class SyntaxNodeExtensions { // https://stackoverflow.com/questions/20458457/getting-class-fullname-including-namespace-from-roslyn-classdeclarationsyntax public static bool TryGetParentSyntax( this SyntaxNode? syntaxNode, [NotNullWhen(true)] out T? result ) where T : SyntaxNode { result = null; if (syntaxNode is null) { return false; } try { syntaxNode = syntaxNode.Parent; if (syntaxNode is null) { return false; } if (syntaxNode.GetType() == typeof(T)) { result = (T)syntaxNode; return true; } return TryGetParentSyntax(syntaxNode, out result); } catch { return false; } } /// /// determine the namespace the class/enum/struct is declared in, if any /// https://andrewlock.net/creating-a-source-generator-part-5-finding-a-type-declarations-namespace-and-type-hierarchy/ /// /// /// NameSpace public static string GetNamespace(this SyntaxNode syntaxNode) { // If we don't have a namespace at all we'll return an empty string // This accounts for the "default namespace" case string nameSpace = string.Empty; // Get the containing syntax node for the type declaration // (could be a nested type, for example) SyntaxNode? potentialNamespaceParent = syntaxNode.Parent; // Keep moving "out" of nested classes etc until we get to a namespace // or until we run out of parents while ( potentialNamespaceParent != null && potentialNamespaceParent is not NamespaceDeclarationSyntax && potentialNamespaceParent is not FileScopedNamespaceDeclarationSyntax ) { potentialNamespaceParent = potentialNamespaceParent.Parent; } // Build up the final namespace by looping until we no longer have a namespace declaration if (potentialNamespaceParent is BaseNamespaceDeclarationSyntax namespaceParent) { // We have a namespace. Use that as the type nameSpace = namespaceParent.Name.ToString(); // Keep moving "out" of the namespace declarations until we // run out of nested namespace declarations while (true) { if (namespaceParent.Parent is not NamespaceDeclarationSyntax parent) { break; } // Add the outer namespace as a prefix to the final namespace nameSpace = $"{namespaceParent.Name}.{nameSpace}"; namespaceParent = parent; } } // return the final namespace return nameSpace; } }