Skip to content

Instantly share code, notes, and snippets.

@tiesmaster
Created November 13, 2016 21:06
Show Gist options
  • Save tiesmaster/4a2a81b83c45dcd336fb5757b1eaab56 to your computer and use it in GitHub Desktop.
Save tiesmaster/4a2a81b83c45dcd336fb5757b1eaab56 to your computer and use it in GitHub Desktop.
so-40578806 "what-is-the-canonical-way-to-convert-a-methoddeclarationsyntax-to-a-constructord" support
<Query Kind="Program">
<NuGetReference>Microsoft.CodeAnalysis</NuGetReference>
<NuGetReference>Microsoft.CodeAnalysis.CSharp</NuGetReference>
<Namespace>Microsoft.CodeAnalysis</Namespace>
<Namespace>Microsoft.CodeAnalysis.CSharp.Syntax</Namespace>
<Namespace>Microsoft.CodeAnalysis.MSBuild</Namespace>
<Namespace>Microsoft.CodeAnalysis.CSharp</Namespace>
<Namespace>Microsoft.CodeAnalysis.Formatting</Namespace>
<Namespace>Microsoft.CodeAnalysis.Text</Namespace>
</Query>
void Main()
{
var tree = CSharpSyntaxTree.ParseText(
@"public class Thing
{
protected override void Configure() => CreateMap<InvoiceDto, Invoice>().ConstructUsing(MapInvoice);
public void Hoi()
{
// Hoi
}
}");
var root = tree.GetRootAsync().Result;
root.ToFullString().Dump("old root");
var methodNode = root.DescendantNodes().OfType<MethodDeclarationSyntax>().First();
var convertedNode = ConvertProtectedOverrideToConstructor(methodNode);
var newRoot = root.ReplaceNode(methodNode, convertedNode);
newRoot.ToFullString().Dump("new root");
}
SyntaxNode ConvertProtectedOverrideToConstructor(MethodDeclarationSyntax oldMethodNode)
{
var classIdentifier = oldMethodNode.Ancestors().OfType<ClassDeclarationSyntax>().Single().Identifier;
var constructorIdentifier = classIdentifier.NormalizeWhitespace();
var newBody = oldMethodNode.Body;
var newParameterList = oldMethodNode.ParameterList;
var expressionBody = oldMethodNode.ExpressionBody;
if (newBody == null)
{
var oldMethodTrailingTrivia = oldMethodNode.GetTrailingTrivia();
newParameterList = newParameterList.WithTrailingTrivia(oldMethodTrailingTrivia);
var expressionBodyAsStatement = SyntaxFactory.ExpressionStatement(expressionBody.Expression);
newBody = SyntaxFactory.Block(expressionBodyAsStatement).NormalizeWhitespace();
var baseIndentationForMethod = oldMethodNode.GetLeadingTrivia().Last();
newBody = (BlockSyntax)newBody.AddIndentationFromTrivia(baseIndentationForMethod);
}
return SyntaxFactory
.ConstructorDeclaration(constructorIdentifier)
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)))
.NormalizeWhitespace()
.WithAttributeLists(oldMethodNode.AttributeLists)
.WithParameterList(newParameterList)
.WithBody(newBody)
.WithTriviaFrom(oldMethodNode);
}
public static class SyntaxNodeManipulationExtensions
{
public static SyntaxNode AddIndentationFromTrivia(this SyntaxNode oldNode, SyntaxTrivia indentation)
{
var baseIndentation = indentation.ToString();
var tokensToLineStartPositionsDictionary = oldNode.GetNonEmptyLinePositions()
.GroupBy(lineStart => oldNode.FindTriviaIncludingZeroLength(lineStart).Token)
.ToDictionary(group => group.Key, group => group.ToList());
return oldNode.ReplaceTokens(tokensToLineStartPositionsDictionary.Keys, (originalToken, rewrittenToken) =>
{
var triviasToReplace = tokensToLineStartPositionsDictionary[originalToken].Select(lineStart => originalToken.Parent.FindTriviaIncludingZeroLength(lineStart));
return originalToken.ReplaceTrivia(triviasToReplace, (originalTrivia, rewrittenTrivia)
=> SyntaxFactory.Whitespace(baseIndentation + originalTrivia));
});
}
}
public static class SyntaxNodeExtensions
{
public static SyntaxTrivia FindTriviaIncludingZeroLength(this SyntaxNode node, int position)
=> node.DescendantTrivia().Single(trivia => trivia.SpanStart == position);
public static IEnumerable<int> GetNonEmptyLinePositions(this SyntaxNode node)
{
return
from line in node.GetText().Lines
where !line.IsEmpty()
let offset = node.FullSpan.Start
select offset + line.Start;
}
}
public static class TextLineExtensions
{
public static bool IsEmpty(this TextLine line)
=> line.Start == line.End;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment