Skip to content

Comments

Implement ExpandTernaryExpr mirroring sourcekitd implementation#3247

Open
redne-w wants to merge 1 commit intoswiftlang:mainfrom
redne-w:redne-w-expand-ternary-expr
Open

Implement ExpandTernaryExpr mirroring sourcekitd implementation#3247
redne-w wants to merge 1 commit intoswiftlang:mainfrom
redne-w:redne-w-expand-ternary-expr

Conversation

@redne-w
Copy link

@redne-w redne-w commented Jan 20, 2026

ExpandTernaryExpr

Part of Sourcekit-LSP Issue#2424

Description

Implement ExpandTernaryExpr in Swift-Syntax to be used by lsp in place of current sourcekitd implementation.
Updated sourcekitd implementation to use Swift 5.9+ if-expression syntax.

Support:

  1. Variable assignment
  2. return statements
  3. bare ternary expression

@redne-w redne-w changed the title Implement ExpandTernaryExpr mirroring sourkitd implementation Implement ExpandTernaryExpr mirroring sourcekitd implementation Jan 20, 2026
Copy link
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for implementing this refactoring action @redne-w. 🙏🏽 It looks good overall, I left a few comments inline.

//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2026 Apple Inc. and the Swift project authors

😉

#endif

/// Converts a ternary conditional expression to an if-else expression using
/// Swift 5.9's if-expression syntax.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think it’s worth mentioning the version in which the if-expressions were introduced 5.9 is sufficiently old now.

Suggested change
/// Swift 5.9's if-expression syntax.
/// Swift's if-expression syntax.

Comment on lines +41 to +50
// Extract components with cleaned trivia
let condition = ternary.condition
.with(\.leadingTrivia, [])
.with(\.trailingTrivia, [])
let thenExpr = ternary.thenExpression
.with(\.leadingTrivia, [])
.with(\.trailingTrivia, [])
let elseExpr = ternary.elseExpression
.with(\.leadingTrivia, [])
.with(\.trailingTrivia, [])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will remove any comments around these expressions. Handling comments is always a little tricky but could you try to make sure we do something reasonable for /*a*/ foo /*b*/ ? /*c*/ 1 /*d*/ : /*e*/ 2 /*f*/?

I believe that in most cases we only want to remove surrounding whitespace but not comments.


One other interesting case to handle would be

// test
foo ? 1 : 2

Because // test will be attached to foo. I think you handle this well but it would be good to have a test case for that.

CodeBlockSyntax(
statements: CodeBlockItemListSyntax {
CodeBlockItemSyntax(
leadingTrivia: .newline + indentStep,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also need to add the base indentation of the ternary expression here, eg.

func foo() {
  let x = true ? 1 : 2
}

Comment on lines +21 to +25
let baseline = TernaryExprSyntax(
condition: ExprSyntax("a"),
thenExpression: ExprSyntax("b"),
elseExpression: ExprSyntax("c")
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would read easier if you wrote this as ExprSyntax("a ? b : c").cast(TernaryExprSyntax.self). It would also be closer to what actual users would do based on real source code.

try assertRefactor(baseline, context: (), provider: ExpandTernaryExpr.self, expected: expected)
}

func testTernaryWithStringLiterals() throws {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the following tests are effectively the same as the first one because we just copy the expression verbatim.

Instead, I’d prefer to have some more tests that involve comments because that’s usually the tricky thing to handle.

)

let expected: ExprSyntax = """
if (x > 0 && y < 10) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove the parentheses here? Would also be a good follow-up PR if you don’t want to do it in this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants