Skip to content

Commit 30f08dc

Browse files
authored
Merge pull request #2592 from ahoppen/ahoppen/no-space-before-attribute-paren
Default to not requiring whitespace before `(`
2 parents 1672a3e + 38bacb3 commit 30f08dc

File tree

4 files changed

+98
-57
lines changed

4 files changed

+98
-57
lines changed

Sources/SwiftBasicFormat/BasicFormat.swift

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -310,27 +310,18 @@ open class BasicFormat: SyntaxRewriter {
310310
(.backtick, _),
311311
(.dollarIdentifier, .period), // a.b
312312
(.endOfFile, _),
313-
(.exclamationMark, .leftParen), // myOptionalClosure!()
314313
(.exclamationMark, .period), // myOptionalBar!.foo()
315-
(.regexPoundDelimiter, .leftParen), // opening extended regex delimiter should never be separate by a space
316314
(.regexPoundDelimiter, .regexSlash), // opening extended regex delimiter should never be separate by a space
317315
(.identifier, .leftAngle), // MyType<Int>
318-
(.identifier, .leftParen), // foo()
319316
(.identifier, .leftSquare), // myArray[1]
320317
(.identifier, .period), // a.b
321318
(.integerLiteral, .period), // macOS 11.2.1
322319
(.keyword(.Any), .period), // Any.Type
323320
(.keyword(.`init`), .leftAngle), // init<T>()
324-
(.keyword(.`init`), .leftParen), // init()
325-
(.keyword(.private), .leftParen), // private(set)
326321
(.keyword(.self), .period), // self.someProperty
327-
(.keyword(.self), .leftParen), // self()
328322
(.keyword(.self), .leftSquare), // self[]
329323
(.keyword(.Self), .period), // Self.someProperty
330-
(.keyword(.Self), .leftParen), // Self()
331324
(.keyword(.Self), .leftSquare), // Self[]
332-
(.keyword(.set), .leftParen), // var mVar: Int { set(value) {} }
333-
(.keyword(.subscript), .leftParen), // subscript(x: Int)
334325
(.keyword(.super), .period), // super.someProperty
335326
(.leftBrace, .rightBrace), // {}
336327
(.leftParen, _),
@@ -339,13 +330,10 @@ open class BasicFormat: SyntaxRewriter {
339330
(.multilineStringQuote, .rawStringPoundDelimiter),
340331
(.period, _),
341332
(.postfixQuestionMark, .leftAngle), // init?<T>()
342-
(.postfixQuestionMark, .leftParen), // init?() or myOptionalClosure?()
343333
(.postfixQuestionMark, .period), // someOptional?.someProperty
344334
(.pound, _),
345-
(.poundUnavailable, .leftParen), // #unavailable(...)
346335
(.prefixAmpersand, _),
347336
(.prefixOperator, _),
348-
(.rawStringPoundDelimiter, .leftParen), // opening raw string delimiter should never be separate by a space
349337
// opening raw string delimiter should never be separate by a space
350338
(.rawStringPoundDelimiter, .multilineStringQuote),
351339
(.rawStringPoundDelimiter, .singleQuote), // opening raw string delimiter should never be separate by a space
@@ -355,10 +343,7 @@ open class BasicFormat: SyntaxRewriter {
355343
(.regexPoundDelimiter, .period), // #/myRegex/#.someMember
356344
(.regexSlash, .regexPoundDelimiter), // closing extended regex delimiter should never be separate by a space
357345
(.regexSlash, .period), // /myRegex/.someMember
358-
(.rightAngle, .leftParen), // func foo<T>(x: T)
359346
(.rightAngle, .period), // Foo<T>.bar
360-
(.rightBrace, .leftParen), // { return 1 }()
361-
(.rightParen, .leftParen), // returnsClosure()()
362347
(.rightParen, .period), // foo().bar
363348
(.rightSquare, .period), // myArray[1].someProperty
364349
(.singleQuote, .rawStringPoundDelimiter), // closing raw string delimiter should never be separate by a space
@@ -378,9 +363,11 @@ open class BasicFormat: SyntaxRewriter {
378363
(nil, _):
379364
return false
380365
case (_, .colon):
381-
if second?.keyPathInParent != \TernaryExprSyntax.colon
382-
&& second?.keyPathInParent != \UnresolvedTernaryExprSyntax.colon
383-
{
366+
switch second?.keyPathInParent {
367+
case \TernaryExprSyntax.colon,
368+
\UnresolvedTernaryExprSyntax.colon:
369+
break
370+
default:
384371
return false
385372
}
386373
case (.leftAngle, _) where second?.tokenKind != .rightAngle:
@@ -389,6 +376,18 @@ open class BasicFormat: SyntaxRewriter {
389376
case (_, .rightAngle) where first?.tokenKind != .leftAngle:
390377
// `<` and `>` need to be separated by a space because otherwise they become an operator
391378
return false
379+
case (_, .leftParen):
380+
switch second?.keyPathInParent {
381+
case \ClosureParameterClauseSyntax.leftParen,
382+
\FunctionTypeSyntax.leftParen,
383+
\TupleExprSyntax.leftParen,
384+
\TuplePatternSyntax.leftParen,
385+
\TupleTypeSyntax.leftParen:
386+
break
387+
default:
388+
return false
389+
}
390+
392391
default:
393392
break
394393
}

Tests/SwiftBasicFormatTest/BasicFormatTests.swift

Lines changed: 77 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ fileprivate func assertFormatted(
4343
)
4444
}
4545

46+
fileprivate func assertFormattingRoundTrips(
47+
_ source: String,
48+
using format: BasicFormat = BasicFormat(indentationWidth: .spaces(4)),
49+
file: StaticString = #filePath,
50+
line: UInt = #line
51+
) {
52+
assertFormatted(source: source, expected: source, using: format, file: file, line: line)
53+
}
54+
4655
final class BasicFormatTest: XCTestCase {
4756
func testNotIndented() {
4857
assertFormatted(
@@ -100,26 +109,26 @@ final class BasicFormatTest: XCTestCase {
100109
}
101110

102111
func testAlreadyIndented() {
103-
let source = """
112+
assertFormattingRoundTrips(
113+
"""
104114
func foo() {
105115
someFunc(a: 1,
106116
b: 1)
107117
}
108118
"""
109-
110-
assertFormatted(source: source, expected: source)
119+
)
111120
}
112121

113122
func testAlreadyIndentedWithComment() {
114-
let source = """
123+
assertFormattingRoundTrips(
124+
"""
115125
func foo() {
116126
// ABC
117127
someFunc(a: 1,
118128
b: 1)
119129
}
120130
"""
121-
122-
assertFormatted(source: source, expected: source)
131+
)
123132
}
124133

125134
func testAlreadyIndentedWithComment2() {
@@ -278,7 +287,8 @@ final class BasicFormatTest: XCTestCase {
278287
}
279288

280289
func testMultilineStringLiteralWithBlankLines() {
281-
let source = #"""
290+
assertFormattingRoundTrips(
291+
#"""
282292
assertionFailure("""
283293
284294
First line
@@ -287,29 +297,30 @@ final class BasicFormatTest: XCTestCase {
287297
288298
""")
289299
"""#
290-
assertFormatted(source: source, expected: source)
300+
)
291301
}
292302

293303
func testMultilineStringLiteralWithFirstLineBlank() {
294-
let source = #"""
304+
assertFormattingRoundTrips(
305+
#"""
295306
assertionFailure("""
296307
297308
""")
298309
"""#
299-
assertFormatted(source: source, expected: source)
310+
)
300311
}
301312

302313
func testNestedMultilineStringLiterals() {
303-
let source = #"""
314+
assertFormattingRoundTrips(
315+
#"""
304316
assertionFailure("""
305317
306318
\("""
307319
First Line
308320
""")
309321
""")
310322
"""#
311-
312-
assertFormatted(source: source, expected: source)
323+
)
313324
}
314325

315326
func testIndentNestedMultilineStringLiterals() throws {
@@ -375,7 +386,8 @@ final class BasicFormatTest: XCTestCase {
375386
}
376387

377388
func testClosureInStringInterpolation() {
378-
let source = #"""
389+
assertFormattingRoundTrips(
390+
#"""
379391
"""
380392
\(gen { (x) in
381393
return """
@@ -384,8 +396,7 @@ final class BasicFormatTest: XCTestCase {
384396
})
385397
"""
386398
"""#
387-
388-
assertFormatted(source: source, expected: source)
399+
)
389400
}
390401

391402
func testNestedUserDefinedIndentation() {
@@ -540,31 +551,27 @@ final class BasicFormatTest: XCTestCase {
540551
}
541552

542553
func testPeriodAfterStringLiteral() {
543-
let source = """
554+
assertFormattingRoundTrips(
555+
"""
544556
"test".lowercased()
545557
"""
546-
assertFormatted(source: source, expected: source)
558+
)
547559
}
548560

549561
func testPeriodAfterRawStringLiteral() {
550-
let source = """
562+
assertFormattingRoundTrips(
563+
"""
551564
#"test"#.lowercased()
552565
"""
553-
assertFormatted(source: source, expected: source)
566+
)
554567
}
555568

556569
func testPeriodAfterRegexLiteral() {
557-
let source = """
558-
/test/.something
559-
"""
560-
assertFormatted(source: source, expected: source)
570+
assertFormattingRoundTrips("/test/.something")
561571
}
562572

563573
func testPeriodAfterRawRegexLiteral() {
564-
let source = """
565-
/test/.something
566-
"""
567-
assertFormatted(source: source, expected: source)
574+
assertFormattingRoundTrips("/test/.something")
568575
}
569576

570577
func testNewlineInTrailingTriviaAtEndOfIndentationScope() throws {
@@ -627,30 +634,65 @@ final class BasicFormatTest: XCTestCase {
627634
}
628635

629636
func testIndentedStandaloneClosureRoundTrips() throws {
630-
let source = """
637+
assertFormattingRoundTrips(
638+
"""
631639
foo {
632640
"abc"
633641
}
634642
"""
635-
assertFormatted(source: source, expected: source)
643+
)
636644
}
637645

638646
func testIndentedStandaloneClosureRoundTrips2() throws {
639-
let source = """
647+
assertFormattingRoundTrips(
648+
"""
640649
foo {
641650
if true {
642651
print("test")
643652
}
644653
}
645654
"""
646-
assertFormatted(source: source, expected: source)
655+
)
647656
}
648657

649658
func testPrivateSetVar() {
650-
let source = """
651-
private(set) var x = 1
659+
assertFormattingRoundTrips("private(set) var x = 1")
660+
661+
assertFormattingRoundTrips("internal(set) var x = 1")
662+
}
663+
664+
func testSpiAttribute() {
665+
assertFormattingRoundTrips(
666+
"""
667+
@_spi(MySPI) struct Foo {
668+
}
652669
"""
670+
)
671+
}
653672

654-
assertFormatted(source: source, expected: source)
673+
func testTypedThrows() {
674+
assertFormattingRoundTrips(
675+
"""
676+
func foo() throws(MyError) {
677+
}
678+
"""
679+
)
680+
}
681+
682+
func testClosureParameterClause() {
683+
assertFormatted(
684+
source: "{(x: Int) in}",
685+
expected: """
686+
{ (x: Int) in
687+
}
688+
"""
689+
)
690+
}
691+
692+
func testFunctionType() {
693+
assertFormatted(
694+
source: "let x:(Int)->Void",
695+
expected: "let x: (Int) -> Void"
696+
)
655697
}
656698
}

Tests/SwiftParserTest/TypeTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,15 +469,15 @@ final class TypeTests: ParserTestCase {
469469
assertParse("func foo() -> dependsOn(scoped x) X", experimentalFeatures: [.nonescapableTypes])
470470

471471
assertParse(
472-
"func foo() -> dependsOn 1️⃣X",
472+
"func foo() -> dependsOn1️⃣ X",
473473
diagnostics: [
474474
DiagnosticSpec(
475475
locationMarker: "1️⃣",
476476
message: "expected '(', parameter reference, and ')' in lifetime specifier",
477477
fixIts: ["insert '(', parameter reference, and ')'"]
478478
)
479479
],
480-
fixedSource: "func foo() -> dependsOn (<#identifier#>) X",
480+
fixedSource: "func foo() -> dependsOn(<#identifier#>) X",
481481
experimentalFeatures: [.nonescapableTypes]
482482
)
483483

Tests/SwiftParserTest/translated/AvailabilityQueryTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ final class AvailabilityQueryTests: ParserTestCase {
124124
func testAvailabilityQuery7() {
125125
assertParse(
126126
"""
127-
if #available 1️⃣{
127+
if #available1️⃣ {
128128
}
129129
""",
130130
diagnostics: [
@@ -135,7 +135,7 @@ final class AvailabilityQueryTests: ParserTestCase {
135135
)
136136
],
137137
fixedSource: """
138-
if #available (<#identifier#>) {
138+
if #available(<#identifier#>) {
139139
}
140140
"""
141141
)

0 commit comments

Comments
 (0)