private static async Task <Document> InsertCloseParenthesisAsync( Document document, ParenthesizedExpressionSyntax parenthesizedExpression, CancellationToken cancellationToken) { var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); if (parenthesizedExpression.Expression is ConditionalExpressionSyntax conditional && parenthesizedExpression.GetAncestor <InterpolatedStringExpressionSyntax>()?.StringStartToken.Kind() == SyntaxKind.InterpolatedStringStartToken) { // If they have something like: // // var s3 = $""Text1 { true ? ""Text2""[|:|] // NextLineOfCode(); // // We will update this initially to: // // var s3 = $""Text1 { (true ? ""Text2""[|:|] // NextLineOfCode(); // // And we have to decide where the close paren should go. Based on the parse tree, the // 'NextLineOfCode()' expression will be pulled into the WhenFalse portion of the conditional. // So placing the close paren after the conditional woudl result in: 'NextLineOfCode())'. // // However, the user intent is likely that NextLineOfCode is not part of the conditional // So instead find the colon and place the close paren after that, producing: // // var s3 = $""Text1 { (true ? ""Text2"":) // NextLineOfCode(); var endToken = sourceText.AreOnSameLine(conditional.ColonToken, conditional.WhenFalse.GetFirstToken()) ? conditional.WhenFalse.GetLastToken() : conditional.ColonToken; var closeParenPosition = endToken.Span.End; var textWithCloseParenthesis = sourceText.Replace(closeParenPosition, 0, ")"); return(document.WithText(textWithCloseParenthesis)); } var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var newCloseParen = SyntaxFactory.Token(SyntaxKind.CloseParenToken).WithTriviaFrom(parenthesizedExpression.CloseParenToken); var parenthesizedExpressionWithClosingParen = parenthesizedExpression.WithCloseParenToken(newCloseParen); var newRoot = root.ReplaceNode(parenthesizedExpression, parenthesizedExpressionWithClosingParen); return(document.WithSyntaxRoot(newRoot)); }