Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions Sources/SwiftBasicFormat/BasicFormat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ open class BasicFormat: SyntaxRewriter {
case \EnumCaseParameterClauseSyntax.parameters:
return true
case \FunctionCallExprSyntax.arguments:
if let arguments = Syntax(node).as(LabeledExprListSyntax.self) {
return argumentListIsMultiLine(arguments)
}
return true
case \FunctionTypeSyntax.parameters:
return true
Expand All @@ -219,6 +222,9 @@ open class BasicFormat: SyntaxRewriter {
case \SwitchCaseSyntax.statements:
return true
case \TupleExprSyntax.elements:
if let elements = Syntax(node).as(LabeledExprListSyntax.self) {
return argumentListIsMultiLine(elements)
}
return true
case \TupleTypeSyntax.elements:
return true
Expand Down Expand Up @@ -252,6 +258,25 @@ open class BasicFormat: SyntaxRewriter {
}) != nil
}

/// Returns `true` if the argument list (a `LabeledExprListSyntax` used by
/// `FunctionCallExprSyntax.arguments` or `TupleExprSyntax.elements`) is
/// laid out across multiple lines at the argument level (i.e. at least one
/// argument begins on its own line).
///
/// When this is `false`, the argument list is single-line at the argument
/// level even if individual arguments contain multi-line expressions (such
/// as closures or collection literals). In that case, the argument-list
/// indentation scope shouldn't contribute, because any inner multi-line
/// expression brings its own indentation scope.
private func argumentListIsMultiLine(_ arguments: LabeledExprListSyntax) -> Bool {
for argument in arguments {
if argument.leadingTrivia.contains(where: \.isNewline) {
return true
}
}
return false
}

open func requiresNewline(between first: TokenSyntax?, and second: TokenSyntax?) -> Bool {
// We don't want to add newlines inside string interpolation.
// When first or second ``TokenSyntax`` is a multiline quote we want special handling
Expand Down
30 changes: 30 additions & 0 deletions Tests/SwiftBasicFormatTest/BasicFormatTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,36 @@ final class BasicFormatTest: XCTestCase {
)
}

func testSingleLineCallWithMultiLineClosureArgument() {
assertFormattingRoundTrips(
"""
foo(someClosure: { _ in
return 1
})
"""
)
}

func testSingleLineCallWithUnlabeledMultiLineClosureArgument() {
assertFormattingRoundTrips(
"""
foo({ _ in
return 1
})
"""
)
}

func testSingleLineTupleWithMultiLineClosureElement() {
assertFormattingRoundTrips(
"""
_ = ({ _ in
return 1
})
"""
)
}

func testLineWrappingInsideIndentedBlock() {
assertFormatted(
source: """
Expand Down
9 changes: 3 additions & 6 deletions Tests/SwiftRefactorTest/CallToTrailingClosureTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,10 @@ final class CallToTrailingClosuresTest: XCTestCase {
})
"""

// TODO: The ident here is not great.
// https://github.com/swiftlang/swift-syntax/issues/1473
let expected: ExprSyntax = """
foo({ label in
return 1
}, 1) { label2 in
}, 1) { label2 in
return 2
} _: { label3 in
return 3
Expand All @@ -109,13 +107,12 @@ final class CallToTrailingClosuresTest: XCTestCase {
})
"""

// TODO: BasicFormat is pretty messed up here
let expected: ExprSyntax = """
foo({ label in
return 1
}, 1, { label2 in
}, 1, { label2 in
return 2
}) { label3 in
}) { label3 in
return 3
} named: { label4 in
return 4
Expand Down
8 changes: 4 additions & 4 deletions Tests/SwiftSyntaxBuilderTest/VariableTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ final class VariableTests: XCTestCase {
"""
var bar: [String] {
bar.map({
$0.description
})
$0.description
})
}
"""
),
Expand All @@ -148,8 +148,8 @@ final class VariableTests: XCTestCase {
"""
inout bar: [String] {
bar.map({
$0.description
})
$0.description
})
}
"""
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ final class ExpressionMacroTests: XCTestCase {
_ = ({ () -> Bool in
print("hello")
return true
}, #"{ () -> Bool in\\#n print("hello")\\#n return true\\#n}"#)
}, #"{ () -> Bool in\\#n print("hello")\\#n return true\\#n}"#)
""",
macros: ["stringify": StringifyMacro.self],
indentationWidth: indentationWidth
Expand Down
68 changes: 34 additions & 34 deletions Tests/SwiftSyntaxTest/DebugDescriptionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -181,47 +181,47 @@ class DebugDescriptionTests: XCTestCase {
sourceFile.debugInitCall(includeTrivia: true).trimmingTrailingWhitespace(),
"""
SourceFileSyntax(
statements: CodeBlockItemListSyntax([
CodeBlockItemSyntax(item: CodeBlockItemSyntax.Item(FunctionCallExprSyntax(
calledExpression: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("test"))),
leftParen: .leftParenToken(),
arguments: LabeledExprListSyntax([
LabeledExprSyntax(
expression: ExprSyntax(IntegerLiteralExprSyntax(literal: .integerLiteral("1"))),
trailingComma: .commaToken(trailingTrivia: .space)
),
LabeledExprSyntax(expression: ExprSyntax(IntegerLiteralExprSyntax(literal: .integerLiteral("2"))))
]),
rightParen: .rightParenToken(),
additionalTrailingClosures: MultipleTrailingClosureElementListSyntax([])
)))
]),
endOfFileToken: .endOfFileToken()
)
statements: CodeBlockItemListSyntax([
CodeBlockItemSyntax(item: CodeBlockItemSyntax.Item(FunctionCallExprSyntax(
calledExpression: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("test"))),
leftParen: .leftParenToken(),
arguments: LabeledExprListSyntax([
LabeledExprSyntax(
expression: ExprSyntax(IntegerLiteralExprSyntax(literal: .integerLiteral("1"))),
trailingComma: .commaToken(trailingTrivia: .space)
),
LabeledExprSyntax(expression: ExprSyntax(IntegerLiteralExprSyntax(literal: .integerLiteral("2"))))
]),
rightParen: .rightParenToken(),
additionalTrailingClosures: MultipleTrailingClosureElementListSyntax([])
)))
]),
endOfFileToken: .endOfFileToken()
)
"""
)

assertStringsEqualWithDiff(
sourceFile.debugInitCall(includeTrivia: false).trimmingTrailingWhitespace(),
"""
SourceFileSyntax(
statements: CodeBlockItemListSyntax([
CodeBlockItemSyntax(item: CodeBlockItemSyntax.Item(FunctionCallExprSyntax(
calledExpression: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("test"))),
leftParen: .leftParenToken(),
arguments: LabeledExprListSyntax([
LabeledExprSyntax(
expression: ExprSyntax(IntegerLiteralExprSyntax(literal: .integerLiteral("1"))),
trailingComma: .commaToken()
),
LabeledExprSyntax(expression: ExprSyntax(IntegerLiteralExprSyntax(literal: .integerLiteral("2"))))
]),
rightParen: .rightParenToken(),
additionalTrailingClosures: MultipleTrailingClosureElementListSyntax([])
)))
]),
endOfFileToken: .endOfFileToken()
)
statements: CodeBlockItemListSyntax([
CodeBlockItemSyntax(item: CodeBlockItemSyntax.Item(FunctionCallExprSyntax(
calledExpression: ExprSyntax(DeclReferenceExprSyntax(baseName: .identifier("test"))),
leftParen: .leftParenToken(),
arguments: LabeledExprListSyntax([
LabeledExprSyntax(
expression: ExprSyntax(IntegerLiteralExprSyntax(literal: .integerLiteral("1"))),
trailingComma: .commaToken()
),
LabeledExprSyntax(expression: ExprSyntax(IntegerLiteralExprSyntax(literal: .integerLiteral("2"))))
]),
rightParen: .rightParenToken(),
additionalTrailingClosures: MultipleTrailingClosureElementListSyntax([])
)))
]),
endOfFileToken: .endOfFileToken()
)
"""
)
}
Expand Down