using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; namespace InnovEnergy.Lib.SrcGen; public static class SyntaxUtils { // const String DebugFile = "/home/eef/sync/work/Code/innovenergy/git/csharp/Lib/SrcGen/Debug.txt"; // // static SyntaxUtils() => File.WriteAllText(DebugFile, ""); public static Boolean HasExtendsAttribute(this TypeDeclarationSyntax td) { return td .GetAttributes() .Select(a => a.Name) .OfType() .Any(n => n.Identifier.ValueText == "Extends"); } public static T GetAncestor(this SyntaxNode sn) where T: SyntaxNode { return sn .Ancestors() .OfType() .First(); } public static IEnumerable GetGenerateAttributes(this SyntaxNode sn) { return sn .DescendantNodes() .Where(n => n is AttributeSyntax { Name : GenericNameSyntax { Identifier.ValueText: "Generate" } }) .OfType(); } public static IEnumerable GetNestPropertiesAttributes(this SyntaxNode sn) { return sn .DescendantNodes() .Where(n => n is AttributeSyntax { Name : IdentifierNameSyntax { Identifier.ValueText: "NestProperties" } }) .OfType(); } public static IEnumerable GetAttributes(this MemberDeclarationSyntax member) { return member .AttributeLists .SelectMany(al => al.Attributes); } // public static T Debug(this T t, String? title = null) // { // var prefix = title is null ? "" : title + ": "; // var contents = t is null ? "" : t.ToString(); // // File.AppendAllText(DebugFile, prefix + contents + '\n'); // return t; // } public static IEnumerable GetAttributes(this SyntaxNode node, String attributeName) { return node .DescendantTokens() .Where(st => st.ValueText == attributeName) .Where(st => st.IsKind(SyntaxKind.IdentifierToken)) .Select(st => st.Parent?.Parent) .OfType(); } public static IEnumerable ChildNodes(this SyntaxNode node) where T : SyntaxNode { return node.ChildNodes().OfType(); } public static IEnumerable DescendantNodes(this SyntaxNode node) where T : SyntaxNode { return node.DescendantNodes().OfType(); } [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] public static T ReplaceIdentifiers(this T root, String idToReplace, String replacementId) where T: SyntaxNode { var newIdentifier = SyntaxFactory.Identifier(replacementId); return root .EditNodes() .OfType() .Where(n => n.Identifier.ValueText == idToReplace) .Replace(n => n.WithIdentifier(newIdentifier).WithTriviaFrom(n)) .EditNodes() .OfType() .Where(n => n.Identifier.ValueText == idToReplace) .Replace(n => n.WithIdentifier(newIdentifier).WithTriviaFrom(n)) .EditNodes() .OfType() .Where(n => n.Identifier.ValueText == idToReplace) .Replace(n => n.WithIdentifier(newIdentifier.WithTrailingTrivia(NewLine))); } private static readonly SyntaxTrivia NewLine = SyntaxFactory.SyntaxTrivia(SyntaxKind.EndOfLineTrivia, "\n"); private static readonly SyntaxTrivia WhiteSpace = SyntaxFactory.SyntaxTrivia(SyntaxKind.WhitespaceTrivia, " "); private static readonly SyntaxToken PartialKeyword = SyntaxFactory .Token(SyntaxKind.PartialKeyword) .WithTrailingTrivia(WhiteSpace); public static CompilationUnitSyntax AddPartialModifier(this CompilationUnitSyntax baseFile) { return baseFile .EditNodes() .OfType() .Where(s => !s.Modifiers.Contains(PartialKeyword)) .Replace(s => s.AddModifiers(PartialKeyword)); } public static T GetDefinition(this Compilation compilation, TypeSyntax baseTypeDeclaration) where T : SyntaxNode { return compilation .GetDefinitions(baseTypeDeclaration) .OfType() .Single(); } public static IEnumerable GetDefinitions(this Compilation compilation, TypeSyntax baseTypeDeclaration) where T : SyntaxNode { return compilation .GetDefinitions(baseTypeDeclaration) .OfType(); } public static IEnumerable GetDefinitions(this Compilation compilation, TypeSyntax baseTypeDeclaration) { return compilation .GetSemanticModel(baseTypeDeclaration.SyntaxTree) .GetTypeInfo(baseTypeDeclaration) .Type? .DeclaringSyntaxReferences .Select(r => r.GetSyntax()) ?? Enumerable.Empty(); } public static IEnumerable GetGenericArguments(this AttributeSyntax attribute) => attribute.Name switch { GenericNameSyntax gns => gns.TypeArgumentList.Arguments, _ => Enumerable.Empty() }; public static TypeSyntax GetGenericArgument(this AttributeSyntax attribute) => attribute.GetGenericArguments().Single(); public static CompilationUnitSyntax RemoveNotImplemented(this CompilationUnitSyntax baseFile) { return baseFile .EditNodes() .OfType() .Where(i => i.Identifier.ValueText == nameof(NotImplementedException)) .HasAncestor() .GetAncestor() .Remove(); } public static String GetGeneratedPath(this String path, String postfix = "generated") { var ext = Path.GetExtension(path); var name = Path.GetFileNameWithoutExtension(path); var dir = Path.GetDirectoryName(path); return $"{dir}/{name}.{postfix}{ext}"; } }