[Refactoring] ConvertConcatenationToInterpolatedString: Support inlineing of other interpolated strings#49229
Conversation
Co-authored-by: CyrusNajmabadi <cyrus.najmabadi@gmail.com>
|
@CyrusNajmabadi Thanks for the review. In my previous PR I added support for the removal of superfluous parentheses in private static async Task<Document> UpdateDocumentAsync(Document document, BinaryExpressionSyntax binaryExpression, ImmutableArray<ExpressionSyntax> concatParts, CancellationToken cancellationToken)
{
var interpolatedStringContent = ConvertConcatPartsToInterpolatedStringContent(concatParts);
var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var editor = new SyntaxEditor(root, CSharpSyntaxGenerator.Instance);
var interpolated = InterpolatedStringExpression(
Token(SyntaxKind.InterpolatedStringStartToken),
List(interpolatedStringContent));
// expressions may have superfluous parenthesis after the conversion to an interpolated string:
// "a" + (1 + 1) -> $"a{(1 + 1)}"
// if there is any (InterpolationSyntax.Expression is ParenthesizedExpressionSyntax) we need to
// recompile and check via parenthesized.CanRemoveParentheses(semanticModel) if it can be removed.
var anyPotentiallyRemovableParenthesis = interpolated.Contents.Any(IsParenthesizedInterpolation);
var annotation = new SyntaxAnnotation("InterpolatedStringExpressionWithPotentiallyRemovableParanthesisKind");
if (anyPotentiallyRemovableParenthesis)
{
// annotate "interpolated" because we need to find it after the changes are applied
interpolated = interpolated.WithAdditionalAnnotations(annotation);
}
editor.ReplaceNode(binaryExpression, interpolated);
if (anyPotentiallyRemovableParenthesis)
{
// Take the changed document and go through interpolatedNode.Contents to check if any parenthesis can be removed.
var newDocument = document.WithSyntaxRoot(editor.GetChangedRoot());
var newRoot = await newDocument.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var interpolatedNode = (InterpolatedStringExpressionSyntax)newRoot.GetAnnotatedNodes(annotation).Single();
var semanticModel = await newDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
editor = new SyntaxEditor(newRoot, CSharpSyntaxGenerator.Instance);
foreach (var content in interpolatedNode.Contents.Where(IsParenthesizedInterpolation).Cast<InterpolationSyntax>())
{
var parenthesized = (ParenthesizedExpressionSyntax)content.Expression;
if (parenthesized.CanRemoveParentheses(semanticModel))
{
editor.ReplaceNode(parenthesized, parenthesized.Expression);
}
}
}
return document.WithSyntaxRoot(editor.GetChangedRoot());
}Do we want to reuse that approach here or not? |
…InterpolatedStringInConcatinationRefactoring
…tConvertConcatenationToInterpolatedStringRefactoringProvider.cs Co-authored-by: CyrusNajmabadi <cyrus.najmabadi@gmail.com>
|
@CyrusNajmabadi Sorry, but I haven't seen your LGTM before I pushed more commits. The commits are only minor clean-ups. I have one more question though: Should I add some logic to remove superfluous parenthesis? There are some approaches to do that. I implemented one with tests as described here: #49229 (comment). I could do this as part of this PR or a new one. |
In general, an easy way to do that is to just add the SimplifierAnnotation to the topmost node you're creating. We should then go through and clean up those parens. See if that works for you. Otherwise, i wouldn't bother doing more here (unless it was super easy). |
that's fine. i still review the later commits :) |
The Simplifier worked like a charm, but I needed to place it on each |
|
@CyrusNajmabadi Tests are green now. I added the simplifier annotation to the expressions that gets capsulated in an Interpolation, but only if the expression is a ParenthesisExpression. |
|
I am sorry I am new to this process, where does this go? How does this get mainlined? |
|
Thanks! |

Fixes #48900
Supersedes #49207