C
C#3mo ago
leviathan

Adding a CommaToken in a code fix

I'm trying to write a code fix that just adds a comma to the end of an InitializerExpressionSyntax (which was previously flagged by an analyzer). I've followed this guide and tried adapting it to my use case, but for some reason it's not working. This is my first time working with Roslyn, and I don't know what I could be doing wrong. Here's the relevant method:
private async Task<Document> AddTrailingCommaAsync(
Document document,
InitializerExpressionSyntax initializerExpression,
CancellationToken cancellationToken
)
{
// Get the last expression
var lastExpression = initializerExpression.Expressions.Last();
// Get the last token
var lastToken = lastExpression.GetLastToken();
// Get any trailing trivia from that token
var trailingTrivia = lastToken.TrailingTrivia;
// Remove the trivia from the expression
var trimmedInitializerExpression = initializerExpression.ReplaceToken(
lastToken,
lastToken.WithTrailingTrivia(SyntaxTriviaList.Empty)
);
// Create the comma token
var commaToken = SyntaxFactory.Token(
SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker),
SyntaxKind.CommaToken,
trailingTrivia
);
// Insert the new token
var newInitializerExpression = trimmedInitializerExpression.InsertTokensAfter(
lastToken,
SyntaxFactory.TokenList(commaToken)
);
// Add a Formatter annotation
var formattedInitializerExpression = newInitializerExpression.WithAdditionalAnnotations(
Formatter.Annotation
);

var oldRoot = await document.GetSyntaxRootAsync(cancellationToken);
var newRoot = oldRoot.ReplaceNode(
initializerExpression,
formattedInitializerExpression
);

return document.WithSyntaxRoot(newRoot);
}
private async Task<Document> AddTrailingCommaAsync(
Document document,
InitializerExpressionSyntax initializerExpression,
CancellationToken cancellationToken
)
{
// Get the last expression
var lastExpression = initializerExpression.Expressions.Last();
// Get the last token
var lastToken = lastExpression.GetLastToken();
// Get any trailing trivia from that token
var trailingTrivia = lastToken.TrailingTrivia;
// Remove the trivia from the expression
var trimmedInitializerExpression = initializerExpression.ReplaceToken(
lastToken,
lastToken.WithTrailingTrivia(SyntaxTriviaList.Empty)
);
// Create the comma token
var commaToken = SyntaxFactory.Token(
SyntaxFactory.TriviaList(SyntaxFactory.ElasticMarker),
SyntaxKind.CommaToken,
trailingTrivia
);
// Insert the new token
var newInitializerExpression = trimmedInitializerExpression.InsertTokensAfter(
lastToken,
SyntaxFactory.TokenList(commaToken)
);
// Add a Formatter annotation
var formattedInitializerExpression = newInitializerExpression.WithAdditionalAnnotations(
Formatter.Annotation
);

var oldRoot = await document.GetSyntaxRootAsync(cancellationToken);
var newRoot = oldRoot.ReplaceNode(
initializerExpression,
formattedInitializerExpression
);

return document.WithSyntaxRoot(newRoot);
}
And I've also attached the whole file in case it's helpful.
2 Replies
leviathan
leviathan3mo ago
I've found two problems with my own code, the first of which I could easily solve - lastToken referred to the original syntax tree. so it wasn't found and nothing was being inserted. Adding the following line before the call to InsertTokensAfter sleved it:
lastToken = trimmedInitializerExpression.Expressions.Last().GetLastToken();
lastToken = trimmedInitializerExpression.Expressions.Last().GetLastToken();
The second problem is related to a (poorly documented) restriction of Insert** methods: the first argument must be in a syntax list - which isn't the case with lastToken, so I can't use those methods (nor Replace* methods). I don't think I can replace the lastExpression with a new one (which would be valid 'cause it is in a list), since the CommaTokens are children of the ObjectInitializerExpression itself (at least, that's what I understand from looking at the syntax visualiser, see attached image). It also doesn't seem like I can't create a new initializer expression, since the SyntaxFactory method doesn't take any argument that'd somehow allow me to specify child tokens. So I really don't see how I can just add a token into the syntax tree, even though it's something that looks like it should be quite easy. Does anyone know how to achieve this?
No description
lycian
lycian3mo ago
It's likely you'll get more traction in #roslyn since it's a fairly niche topic SyntaxGenerator will help keep track of the tree as you make changes and avoid using wrong nodes
Want results from more Discord servers?
Add your server