Innovenergy_trunk/csharp/Lib/SrcGen/SyntaxUtils.cs

182 lines
6.5 KiB
C#

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<GenericNameSyntax>()
.Any(n => n.Identifier.ValueText == "Extends");
}
public static T GetAncestor<T>(this SyntaxNode sn) where T: SyntaxNode
{
return sn
.Ancestors()
.OfType<T>()
.First();
}
public static IEnumerable<AttributeSyntax> GetGenerateAttributes(this SyntaxNode sn)
{
return sn
.DescendantNodes()
.Where(n => n is AttributeSyntax { Name : GenericNameSyntax { Identifier.ValueText: "Generate" } })
.OfType<AttributeSyntax>();
}
public static IEnumerable<AttributeSyntax> GetNestPropertiesAttributes(this SyntaxNode sn)
{
return sn
.DescendantNodes()
.Where(n => n is AttributeSyntax { Name : IdentifierNameSyntax { Identifier.ValueText: "NestProperties" } })
.OfType<AttributeSyntax>();
}
public static IEnumerable<AttributeSyntax> GetAttributes(this MemberDeclarationSyntax member)
{
return member
.AttributeLists
.SelectMany(al => al.Attributes);
}
// public static T Debug<T>(this T t, String? title = null)
// {
// var prefix = title is null ? "" : title + ": ";
// var contents = t is null ? "<null>" : t.ToString();
//
// File.AppendAllText(DebugFile, prefix + contents + '\n');
// return t;
// }
public static IEnumerable<AttributeSyntax> 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<AttributeSyntax>();
}
public static IEnumerable<T> ChildNodes<T>(this SyntaxNode node) where T : SyntaxNode
{
return node.ChildNodes().OfType<T>();
}
public static IEnumerable<T> DescendantNodes<T>(this SyntaxNode node) where T : SyntaxNode
{
return node.DescendantNodes().OfType<T>();
}
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
public static T ReplaceIdentifiers<T>(this T root, String idToReplace, String replacementId) where T: SyntaxNode
{
var newIdentifier = SyntaxFactory.Identifier(replacementId);
return root
.EditNodes()
.OfType<IdentifierNameSyntax>()
.Where(n => n.Identifier.ValueText == idToReplace)
.Replace(n => n.WithIdentifier(newIdentifier).WithTriviaFrom(n))
.EditNodes()
.OfType<ConstructorDeclarationSyntax>()
.Where(n => n.Identifier.ValueText == idToReplace)
.Replace(n => n.WithIdentifier(newIdentifier).WithTriviaFrom(n))
.EditNodes()
.OfType<TypeDeclarationSyntax>()
.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<StructDeclarationSyntax>()
.Where(s => !s.Modifiers.Contains(PartialKeyword))
.Replace(s => s.AddModifiers(PartialKeyword));
}
public static T GetDefinition<T>(this Compilation compilation, TypeSyntax baseTypeDeclaration) where T : SyntaxNode
{
return compilation
.GetDefinitions(baseTypeDeclaration)
.OfType<T>()
.Single();
}
public static IEnumerable<T> GetDefinitions<T>(this Compilation compilation, TypeSyntax baseTypeDeclaration) where T : SyntaxNode
{
return compilation
.GetDefinitions(baseTypeDeclaration)
.OfType<T>();
}
public static IEnumerable<SyntaxNode> GetDefinitions(this Compilation compilation, TypeSyntax baseTypeDeclaration)
{
return compilation
.GetSemanticModel(baseTypeDeclaration.SyntaxTree)
.GetTypeInfo(baseTypeDeclaration)
.Type?
.DeclaringSyntaxReferences
.Select(r => r.GetSyntax())
?? Enumerable.Empty<SyntaxNode>();
}
public static IEnumerable<TypeSyntax> GetGenericArguments(this AttributeSyntax attribute) => attribute.Name switch
{
GenericNameSyntax gns => gns.TypeArgumentList.Arguments,
_ => Enumerable.Empty<TypeSyntax>()
};
public static TypeSyntax GetGenericArgument(this AttributeSyntax attribute) => attribute.GetGenericArguments().Single();
public static CompilationUnitSyntax RemoveNotImplemented(this CompilationUnitSyntax baseFile)
{
return baseFile
.EditNodes()
.OfType<IdentifierNameSyntax>()
.Where(i => i.Identifier.ValueText == nameof(NotImplementedException))
.HasAncestor<ThrowExpressionSyntax>()
.GetAncestor<MemberDeclarationSyntax>()
.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}";
}
}