diff --git a/Tests/SwiftParserTest/Assertions.swift b/Tests/SwiftParserTest/Assertions.swift index 4a55a4a6697..b58979a5440 100644 --- a/Tests/SwiftParserTest/Assertions.swift +++ b/Tests/SwiftParserTest/Assertions.swift @@ -604,7 +604,9 @@ func assertParse( } // Applying Fix-Its - if let expectedFixedSource = expectedFixedSource { + if expectedDiagnostics.contains(where: { !$0.fixIts.isEmpty }) && expectedFixedSource == nil { + XCTFail("Expected a fixed source if the test case produces diagnostics with Fix-Its", file: file, line: line) + } else if let expectedFixedSource = expectedFixedSource { let fixedTree = FixItApplier.applyFixes(in: diags, withMessages: applyFixIts, to: tree) var fixedTreeDescription = fixedTree.description if options.contains(.normalizeNewlinesInFixedSource) { @@ -621,6 +623,10 @@ func assertParse( ) } + if expectedDiagnostics.allSatisfy({ $0.fixIts.isEmpty }) && expectedFixedSource != nil { + XCTFail("A fixed source was provided but the test case produces no diagnostics with Fix-Its", file: file, line: line) + } + if expectedDiagnostics.isEmpty { assertBasicFormat(source: source, parse: parse, file: file, line: line) } diff --git a/Tests/SwiftParserTest/AttributeTests.swift b/Tests/SwiftParserTest/AttributeTests.swift index 632b7a1b28a..7abfd8235c0 100644 --- a/Tests/SwiftParserTest/AttributeTests.swift +++ b/Tests/SwiftParserTest/AttributeTests.swift @@ -63,7 +63,10 @@ final class AttributeTests: XCTestCase { DiagnosticSpec(message: "expected ':' in attribute argument", fixIts: ["insert ':'"]), DiagnosticSpec(message: "expected ')' to end attribute", fixIts: ["insert ')'"]), DiagnosticSpec(message: "expected declaration after attribute", fixIts: ["insert declaration"]), - ] + ], + fixedSource: """ + @_specialize(e:) <#declaration#> + """ ) } @@ -76,7 +79,10 @@ final class AttributeTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected ':' in attribute argument", fixIts: ["insert ':'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected ': false' in attribute argument", fixIts: ["insert ': false'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected declaration after attribute", fixIts: ["insert declaration"]), - ] + ], + fixedSource: """ + @_specialize(e:, exported: false) <#declaration#> + """ ) } @@ -502,7 +508,11 @@ final class AttributeTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected ':' and string literal in @_unavailableFromAsync argument", fixIts: ["insert ':' and string literal"]), DiagnosticSpec(message: #"unexpected code '= "abc"' in attribute"#), - ] + ], + fixedSource: """ + @_unavailableFromAsync(message: ""= "abc") + func foo() {} + """ ) assertParse( diff --git a/Tests/SwiftParserTest/AvailabilityTests.swift b/Tests/SwiftParserTest/AvailabilityTests.swift index 13cb6eb65ae..de866041b6e 100644 --- a/Tests/SwiftParserTest/AvailabilityTests.swift +++ b/Tests/SwiftParserTest/AvailabilityTests.swift @@ -151,7 +151,11 @@ final class AvailabilityTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected version tuple in version restriction", fixIts: ["insert version tuple"]), DiagnosticSpec(message: "unexpected code '10e10' in attribute"), - ] + ], + fixedSource: """ + @available(OSX <#integer literal#>10e10) + func test() {} + """ ) assertParse( @@ -162,7 +166,11 @@ final class AvailabilityTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected integer literal in version tuple", fixIts: ["insert integer literal"]), DiagnosticSpec(message: "unexpected code '0e10' in attribute"), - ] + ], + fixedSource: """ + @available(OSX 10.<#integer literal#>0e10) + func test() {} + """ ) assertParse( @@ -173,7 +181,11 @@ final class AvailabilityTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected version tuple in version restriction", fixIts: ["insert version tuple"]), DiagnosticSpec(message: "unexpected code '0xff' in attribute"), - ] + ], + fixedSource: """ + @available(OSX <#integer literal#>0xff) + func test() {} + """ ) assertParse( @@ -184,8 +196,11 @@ final class AvailabilityTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected integer literal in version tuple", fixIts: ["insert integer literal"]), DiagnosticSpec(message: "unexpected code '0xff' in attribute"), - ] + ], + fixedSource: """ + @available(OSX 1.0.<#integer literal#>0xff) + func test() {} + """ ) - } } diff --git a/Tests/SwiftParserTest/DeclarationTests.swift b/Tests/SwiftParserTest/DeclarationTests.swift index b3148cbe3f5..ff80025b001 100644 --- a/Tests/SwiftParserTest/DeclarationTests.swift +++ b/Tests/SwiftParserTest/DeclarationTests.swift @@ -125,7 +125,11 @@ final class DeclarationTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected ':' or '==' to indicate a conformance or same-type requirement"), DiagnosticSpec(message: "expected member block in class", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + class T where t{ + } + """ ) assertParse( "class B' to end generic parameter clause", fixIts: ["insert '>'"]), DiagnosticSpec(message: "expected member block in class", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + class B { + } + """ ) } @@ -190,7 +198,11 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code '{}' before enum case"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in enum case", fixIts: ["insert identifier"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end protocol", fixIts: ["insert '}'"]), - ] + ], + fixedSource: """ + protocol P{{}case <#identifier#> + } + """ ) } @@ -221,7 +233,10 @@ final class DeclarationTests: XCTestCase { "_ = foo/* */?.description1️⃣", diagnostics: [ DiagnosticSpec(message: "expected ':' and expression after '? ...' in ternary expression", fixIts: ["insert ':' and expression"]) - ] + ], + fixedSource: """ + _ = foo/* */?.description: <#expression#> + """ ) assertParse("var a = Array?(from: decoder)") @@ -290,7 +305,16 @@ final class DeclarationTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), - ] + ], + fixedSource: """ + open; open(set); var openProp = 0 + public public(set) var publicProp = 0 + package package(set) var packageProp = 0 + internal internal(set) var internalProp = 0 + fileprivate fileprivate(set) var fileprivateProp = 0 + private private(set) var privateProp = 0 + internal(set) var defaultProp = 0 + """ ) assertParse( @@ -300,7 +324,10 @@ final class DeclarationTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected 'set' in modifier", fixIts: ["insert 'set'"]), DiagnosticSpec(message: "unexpected code 'get' in modifier"), - ] + ], + fixedSource: """ + private(setget) var a = 0 + """ ) assertParse( @@ -313,7 +340,12 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(message: "expected 'set)' to end modifier", fixIts: ["insert 'set)'"]), // FIXME: It should print `+` as detail of text. DiagnosticSpec(message: "unexpected code in variable"), - ] + ], + fixedSource: """ + private(set) + + set + ) var a = 0 + """ ) assertParse( @@ -349,7 +381,10 @@ final class DeclarationTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected 'set)' to end modifier", fixIts: ["insert 'set)'"]) - ] + ], + fixedSource: """ + private(set) var a = 0 + """ ) assertParse( @@ -369,7 +404,10 @@ final class DeclarationTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected 'set)' to end modifier", fixIts: ["insert 'set)'"]), DiagnosticSpec(message: "unexpected code 'get, didSet' in variable"), - ] + ], + fixedSource: """ + private(set) get, didSet var a = 0 + """ ) } @@ -602,7 +640,12 @@ final class DeclarationTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected declaration after 'public' modifier", fixIts: ["insert declaration"]) - ] + ], + fixedSource: """ + struct a { + public <#declaration#> + } + """ ) } @@ -611,7 +654,10 @@ final class DeclarationTests: XCTestCase { "func test(first second 1️⃣Int)", diagnostics: [ DiagnosticSpec(message: "expected ':' in parameter", fixIts: ["insert ':'"]) - ] + ], + fixedSource: """ + func test(first second: Int) + """ ) } @@ -629,7 +675,10 @@ final class DeclarationTests: XCTestCase { "func test(first second: Int1️⃣", diagnostics: [ DiagnosticSpec(message: "expected ')' to end parameter clause", fixIts: ["insert ')'"]) - ] + ], + fixedSource: """ + func test(first second: Int) + """ ) } @@ -638,7 +687,10 @@ final class DeclarationTests: XCTestCase { "func test 1️⃣first second: Int)", diagnostics: [ DiagnosticSpec(message: "expected '(' to start parameter clause", fixIts: ["insert '('"]) - ] + ], + fixedSource: """ + func test(first second: Int) + """ ) } @@ -666,7 +718,14 @@ final class DeclarationTests: XCTestCase { ), diagnostics: [ DiagnosticSpec(message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]) - ] + ], + fixedSource: """ + class MyClass { + func withoutParameters() + + func withParameters() {} + } + """ ) } @@ -703,7 +762,12 @@ final class DeclarationTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '->' and return type in subscript", fixIts: ["insert '->' and return type"]) - ] + ], + fixedSource: """ + struct Foo { + subscript(x: String) -> <#type#> {} + } + """ ) } @@ -738,7 +802,12 @@ final class DeclarationTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected async specifier; did you mean 'async'?", fixIts: ["replace 'reasync' with 'async'"]) - ] + ], + fixedSource: """ + var bad2 : Int { + get async { 0 } + } + """ ) } @@ -754,7 +823,13 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "bare slash regex literal may not start with space"), DiagnosticSpec(locationMarker: "3️⃣", message: "expected '/' to end regex literal", fixIts: ["insert '/\'"]), DiagnosticSpec(locationMarker: "4️⃣", message: "extraneous brace at top level"), - ] + ], + fixedSource: """ + struct S { + } + / ###line 25 "line-directive.swift"/ + } + """ ) } @@ -795,7 +870,10 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(locationMarker: "3️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "4️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "5️⃣", message: "extraneous code ', consectetur adipiscing elit' at top level"), - ] + ], + fixedSource: """ + Lorem; ipsum; dolor; sit; amet, consectetur adipiscing elit + """ ) } @@ -851,7 +929,10 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "expected ')' to end parameter clause", fixIts: ["insert ')'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected identifier in struct", fixIts: ["insert identifier"]), DiagnosticSpec(locationMarker: "4️⃣", message: "unexpected code ')' in struct"), - ] + ], + fixedSource: """ + func foo(first second: third)struct <#identifier#>: Int) {} + """ ) } @@ -897,7 +978,10 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected ':' in parameter", fixIts: ["insert ':'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected ']' to end array type", fixIts: ["insert ']'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code 'fourth: Int' in parameter clause"), - ] + ], + fixedSource: """ + func foo(first second: [third]fourth: Int) {} + """ ) } @@ -919,7 +1003,11 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected ':' in parameter", fixIts: ["insert ':'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected ')' to end parameter clause", fixIts: ["insert ')'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "extraneous code ': Int) {}' at top level"), - ] + ], + fixedSource: """ + func foo(first second: third) + : Int) {} + """ ) } @@ -937,7 +1025,14 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(locationMarker: "3️⃣", message: "expected declaration after attribute", fixIts: ["insert declaration"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected '#endif' in conditional compilation block", fixIts: ["insert '#endif'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected '}' to end struct", fixIts: ["insert '}'"]), - ] + ], + fixedSource: """ + struct n { + #if <#expression#> + @<#type#> <#declaration#> + #endif + } + """ ) } @@ -1014,42 +1109,64 @@ final class DeclarationTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected brace before enum"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected member block in enum", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + }enum C { + } + """ ) assertParse( "1️⃣}protocol C2️⃣", diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected brace before protocol"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected member block in protocol", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + }protocol C { + } + """ ) assertParse( "1️⃣}actor C2️⃣", diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected brace before actor"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected member block in actor", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + }actor C { + } + """ ) assertParse( "1️⃣}struct C2️⃣", diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected brace before struct"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected member block in struct", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + }struct C { + } + """ ) assertParse( "1️⃣}func C2️⃣", diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected brace before function"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]), - ] + ], + fixedSource: """ + }func C() + """ ) assertParse( "1️⃣}init2️⃣", diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected brace before initializer"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]), - ] + ], + fixedSource: """ + }init() + """ ) assertParse( "1️⃣}subscript2️⃣", @@ -1057,7 +1174,10 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected brace before subscript"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected parameter clause in subscript", fixIts: ["insert parameter clause"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '->' and return type in subscript", fixIts: ["insert '->' and return type"]), - ] + ], + fixedSource: """ + }subscript() -> <#type#> + """ ) } @@ -1148,7 +1268,11 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(message: "expected name in generic parameter", fixIts: ["insert name"]), DiagnosticSpec(message: "expected '>' to end generic parameter clause", fixIts: ["insert '>'"]), DiagnosticSpec(message: "expected member block in struct", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + struct U<@<#type#> <#identifier#>> { + } + """ ) } @@ -1161,7 +1285,13 @@ final class DeclarationTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected member block in struct", fixIts: ["insert member block"]) - ] + ], + fixedSource: """ + struct Foo { + struct Bar { + } + } + """ ) } @@ -1170,7 +1300,10 @@ final class DeclarationTests: XCTestCase { "func 1️⃣{}", diagnostics: [ DiagnosticSpec(message: "expected identifier and function signature in function", fixIts: ["insert identifier and function signature"]) - ] + ], + fixedSource: """ + func <#identifier#>() {} + """ ) } @@ -1212,7 +1345,19 @@ final class DeclarationTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '{' in variable", fixIts: ["insert '{'"]) - ] + ], + fixedSource: """ + struct Foo { + var x: Int { + get { + 4 + } + set { + x = newValue + } + } + } + """ ) } @@ -1232,7 +1377,19 @@ final class DeclarationTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '{' in variable", fixIts: ["insert '{'"]) - ] + ], + fixedSource: """ + struct Foo { + var x: Int { + set { + x = newValue + } + get { + 4 + } + } + } + """ ) } @@ -1252,25 +1409,37 @@ final class DeclarationTests: XCTestCase { "protocol 1️⃣{}", diagnostics: [ DiagnosticSpec(message: "expected identifier in protocol", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + protocol <#identifier#> {} + """ ) assertParse( "class 1️⃣{}", diagnostics: [ DiagnosticSpec(message: "expected identifier in class", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + class <#identifier#> {} + """ ) assertParse( "struct 1️⃣{}", diagnostics: [ DiagnosticSpec(message: "expected identifier in struct", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + struct <#identifier#> {} + """ ) assertParse( "enum 1️⃣{}", diagnostics: [ DiagnosticSpec(message: "expected identifier in enum", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + enum <#identifier#> {} + """ ) // `actor` cannot recover from a missing identifier since it's contextual // based on the presence of the identifier. @@ -1336,7 +1505,14 @@ final class DeclarationTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected 'func' in function", fixIts: ["insert 'func'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]), - ] + ], + fixedSource: """ + class A { + func ^ () + } + class B { + } + """ ) } @@ -1367,7 +1543,14 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code ': Int = A.M1' before macro"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]), DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code ': T = A.M4 where T.Assoc: P' before macro"), - ] + ], + fixedSource: """ + macro m1(): Int = A.M1 + macro m2(_: Int) = A.M2 + macro m3(a b: Int) -> Int = A.M3 + macro m4(): T = A.M4 where T.Assoc: P + macro m5(_: T) + """ ) assertParse( @@ -1376,7 +1559,10 @@ final class DeclarationTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]) - ] + ], + fixedSource: """ + macro m1() = A + """ ) } @@ -1388,7 +1574,11 @@ final class DeclarationTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "expected name and '>' to end primary associated type clause", fixIts: ["insert name and '>'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected type in inherited type", fixIts: ["insert type"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected member block in protocol", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + protocol <#identifier#><<#identifier#>>: <#type#> { + } + """ ) } diff --git a/Tests/SwiftParserTest/DirectiveTests.swift b/Tests/SwiftParserTest/DirectiveTests.swift index 95feff6e685..0953305254b 100644 --- a/Tests/SwiftParserTest/DirectiveTests.swift +++ b/Tests/SwiftParserTest/DirectiveTests.swift @@ -118,7 +118,11 @@ final class DirectiveTests: XCTestCase { "#if test1️⃣", diagnostics: [ DiagnosticSpec(message: "expected '#endif' in conditional compilation block", fixIts: ["insert '#endif'"]) - ] + ], + fixedSource: """ + #if test + #endif + """ ) } diff --git a/Tests/SwiftParserTest/ExpressionTests.swift b/Tests/SwiftParserTest/ExpressionTests.swift index 007bcc55f8a..5c025a1c635 100644 --- a/Tests/SwiftParserTest/ExpressionTests.swift +++ b/Tests/SwiftParserTest/ExpressionTests.swift @@ -20,7 +20,10 @@ final class ExpressionTests: XCTestCase { "let a =1️⃣", diagnostics: [ DiagnosticSpec(message: "expected expression in variable", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + let a = <#expression#> + """ ) assertParse("a ? b : c ? d : e") @@ -28,7 +31,10 @@ final class ExpressionTests: XCTestCase { "a ? b :1️⃣", diagnostics: [ DiagnosticSpec(message: "expected expression after ternary operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + a ? b : <#expression#> + """ ) } @@ -151,7 +157,11 @@ final class ExpressionTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected value and ']' to end subscript", fixIts: ["insert value and ']'"]) - ] + ], + fixedSource: #""" + \a + c[<#expression#>] + """# ) assertParse( @@ -334,7 +344,11 @@ final class ExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected value in array element", fixIts: ["insert value"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected ']' to end array", fixIts: ["insert ']'"]), - ] + ], + fixedSource: """ + [<#expression#> + ,] + """ ) assertParse( @@ -344,7 +358,10 @@ final class ExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected value in dictionary element", fixIts: ["insert value"]), DiagnosticSpec(message: "expected ']' to end dictionary", fixIts: ["insert ']'"]), - ] + ], + fixedSource: """ + ([1: <#expression#>]) + """ ) assertParse( @@ -422,7 +439,10 @@ final class ExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected ')' in string literal", fixIts: ["insert ')'"]), DiagnosticSpec(message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + "\(())" + """# ) } @@ -479,7 +499,10 @@ final class ExpressionTests: XCTestCase { ], fixIts: [#"insert '"'"#] ) - ] + ], + fixedSource: #""" + "\"," + """# ) assertParse( @@ -552,7 +575,10 @@ final class ExpressionTests: XCTestCase { ], fixIts: [#"insert '"""'"#] ) - ] + ], + fixedSource: ##""" + """"""" + """## ) assertParse( @@ -561,7 +587,10 @@ final class ExpressionTests: XCTestCase { """##, diagnostics: [ DiagnosticSpec(message: #"expected '"""' to end string literal"#, fixIts: [#"insert '"""'"#]) - ] + ], + fixedSource: ##""" + """""""" + """## ) assertParse( @@ -583,7 +612,10 @@ final class ExpressionTests: XCTestCase { """##, diagnostics: [ DiagnosticSpec(message: ##"expected '"#' to end string literal"##, fixIts: [##"insert '"#'"##]) - ] + ], + fixedSource: ##""" + #""# + """## ) assertParse( @@ -592,7 +624,10 @@ final class ExpressionTests: XCTestCase { """##, diagnostics: [ DiagnosticSpec(message: ##"expected '"""#' to end string literal"##, fixIts: [##"insert '"""#'"##]) - ] + ], + fixedSource: ##""" + #""""""# + """## ) assertParse( @@ -601,7 +636,10 @@ final class ExpressionTests: XCTestCase { """##, diagnostics: [ DiagnosticSpec(message: ##"expected '"""#' to end string literal"##, fixIts: [##"insert '"""#'"##]) - ] + ], + fixedSource: ##""" + #"""a"""# + """## ) assertParse( @@ -609,7 +647,10 @@ final class ExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "invalid escape sequence in literal"), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: ###""" + "\" + """### ) assertParse( @@ -670,7 +711,10 @@ final class ExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected root in key path", fixIts: ["insert root"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected ')' to end tuple type", fixIts: ["insert ')'"]), - ] + ], + fixedSource: ##""" + \<#type#>\() + """## ) assertParse( @@ -685,7 +729,10 @@ final class ExpressionTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]) - ] + ], + fixedSource: #""" + "" + """# ) assertParse( @@ -694,7 +741,10 @@ final class ExpressionTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]) - ] + ], + fixedSource: #""" + "'" + """# ) } @@ -729,7 +779,10 @@ final class ExpressionTests: XCTestCase { "foo ? 11️⃣", diagnostics: [ DiagnosticSpec(message: "expected ':' and expression after '? ...' in ternary expression", fixIts: ["insert ':' and expression"]) - ] + ], + fixedSource: """ + foo ? 1: <#expression#> + """ ) } @@ -747,7 +800,16 @@ final class ExpressionTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end 'if' statement", fixIts: ["insert '}'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end function", fixIts: ["insert '}'"]), - ] + ], + fixedSource: #""" + func nestThoseIfs() { + \n + if false != true { + \n + print; "\(i)\"\n" + } + } + """# ) assertParse( @@ -755,7 +817,10 @@ final class ExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected value in tuple", fixIts: ["insert value"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected ')' to end macro expansion", fixIts: ["insert ')'"]), - ] + ], + fixedSource: """ + #keyPath((b: <#expression#>)) + """ ) } @@ -780,7 +845,10 @@ final class ExpressionTests: XCTestCase { "let _ = [Int throws 1️⃣Int]()", diagnostics: [ DiagnosticSpec(message: "expected '->' in array element", fixIts: ["insert '->'"]) - ] + ], + fixedSource: """ + let _ = [Int throws -> Int]() + """ ) } @@ -794,7 +862,13 @@ final class ExpressionTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after ternary operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + do { + true ? () : <#expression#>throw opaque_error() + } catch _ { + } + """ ) } @@ -808,7 +882,10 @@ final class ExpressionTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "expected type in function type", fixIts: ["insert type"]), DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '..' in function type"), DiagnosticSpec(locationMarker: "3️⃣", message: "expected return type in function type", fixIts: ["insert return type"]), - ] + ], + fixedSource: """ + let <#pattern#>:(<#type#>..)-> <#type#> + """ ) } @@ -820,7 +897,10 @@ final class ExpressionTests: XCTestCase { substructureAfterMarker: "1️⃣", diagnostics: [ DiagnosticSpec(locationMarker: "2️⃣", message: "expected expression", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + Foo async -> <#expression#> + """ ) } @@ -948,7 +1028,11 @@ final class ExpressionTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected ')' in string literal", fixIts: ["insert ')'"]), DiagnosticSpec(locationMarker: "1️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(locationMarker: "2️⃣", message: #"extraneous code ')"' at top level"#), - ] + ], + fixedSource: #""" + "test \(label: <#expression#>)" + foo)" + """# ) } @@ -969,7 +1053,11 @@ final class ExpressionTests: XCTestCase { ), diagnostics: [ DiagnosticSpec(message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]) - ] + ], + fixedSource: """ + "This is unterminated" + x + """ ) } @@ -1039,6 +1127,12 @@ final class ExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "escaped newline at the last line of a multi-line string literal is not allowed", fixIts: ["remove ''"]) ], + fixedSource: #""" + """ + line 1 + line 2 + """ + """#, options: [.substructureCheckTrivia] ) } @@ -1682,7 +1776,12 @@ final class StatementExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "multi-line string literal content must begin on a new line", fixIts: ["insert newline"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected value and ')' to end tuple", fixIts: ["insert value and ')'"]), - ] + ], + fixedSource: #""" + """ + \({(<#expression#>)}) + """ + """# ) } @@ -1695,7 +1794,11 @@ final class StatementExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + "abc" + "" + """# ) } @@ -1708,7 +1811,11 @@ final class StatementExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + "" + "" + """# ) } @@ -1722,7 +1829,11 @@ final class StatementExpressionTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "3️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + "abc" + \(def); "" + """# ) } @@ -1736,7 +1847,11 @@ final class StatementExpressionTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected ')' in string literal", fixIts: ["insert ')'"]), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(locationMarker: "3️⃣", message: #"extraneous code ')"' at top level"#), - ] + ], + fixedSource: #""" + "abc\(def)" + )" + """# ) } @@ -1750,7 +1865,11 @@ final class StatementExpressionTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected value and ')' in string literal", fixIts: ["insert value and ')'"]), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(locationMarker: "3️⃣", message: #"extraneous code ')"' at top level"#), - ] + ], + fixedSource: #""" + "abc\(<#expression#>)" + def)" + """# ) } @@ -1765,7 +1884,11 @@ final class StatementExpressionTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(locationMarker: "3️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "4️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + "abc\" + (def); "" + """# ) } @@ -1779,7 +1902,11 @@ final class StatementExpressionTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]), - ] + ], + fixedSource: #""" + #<#identifier#> + "abc"; #<#identifier#> + """# ) } @@ -1793,7 +1920,11 @@ final class StatementExpressionTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: ##"expected '"#' to end string literal"##, fixIts: [##"insert '"#'"##]), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "3️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + #""# + abc; "#" + """# ) } @@ -1806,7 +1937,11 @@ final class StatementExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: ##"expected '"#' to end string literal"##, fixIts: [##"insert '"#'"##]), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + #"abc"# + "#" + """# ) } @@ -1819,7 +1954,11 @@ final class StatementExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: ##"expected '"#' to end string literal"##, fixIts: [##"insert '"#'"##]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]), - ] + ], + fixedSource: #""" + #"abc""# + #<#identifier#> + """# ) } @@ -1837,7 +1976,10 @@ final class StatementExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), - ] + ], + fixedSource: """ + {a; b; c} + """ ) } @@ -1847,7 +1989,10 @@ final class StatementExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), - ] + ], + fixedSource: """ + switch x {case y: a; b; c} + """ ) } @@ -1859,7 +2004,10 @@ final class StatementExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), - ] + ], + fixedSource: """ + var i: Int { a; b; c } + """ ) } @@ -1871,7 +2019,10 @@ final class StatementExpressionTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), - ] + ], + fixedSource: """ + var i: Int { get {a; b} set {c; d} } + """ ) } @@ -1919,7 +2070,10 @@ final class StatementExpressionTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]) - ] + ], + fixedSource: #""" + \String.?; "" + """# ) } diff --git a/Tests/SwiftParserTest/Parser+EntryTests.swift b/Tests/SwiftParserTest/Parser+EntryTests.swift index 054d38784bd..f58f16b8e63 100644 --- a/Tests/SwiftParserTest/Parser+EntryTests.swift +++ b/Tests/SwiftParserTest/Parser+EntryTests.swift @@ -64,7 +64,10 @@ public class EntryTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "'test' is considered an identifier and must not appear within an operator name"), DiagnosticSpec(locationMarker: "2️⃣", message: "operator should not be declared with body", fixIts: ["remove operator body"]), - ] + ], + fixedSource: """ + operator test + """ ) } } diff --git a/Tests/SwiftParserTest/RegexLiteralTests.swift b/Tests/SwiftParserTest/RegexLiteralTests.swift index 9762af1a15d..794b74b1546 100644 --- a/Tests/SwiftParserTest/RegexLiteralTests.swift +++ b/Tests/SwiftParserTest/RegexLiteralTests.swift @@ -41,7 +41,7 @@ final class RegexLiteralTests: XCTestCase { #//#1️⃣# """#, diagnostics: [ - DiagnosticSpec(locationMarker: "1️⃣", message: "too many '#' characters in closing delimiter", fixIts: ["remove extraneous delimiters"]) + DiagnosticSpec(message: "too many '#' characters in closing delimiter", fixIts: ["remove extraneous delimiters"]) ], fixedSource: "#//#" ) @@ -52,7 +52,7 @@ final class RegexLiteralTests: XCTestCase { #/abc/#1️⃣# """, diagnostics: [ - DiagnosticSpec(locationMarker: "1️⃣", message: "too many '#' characters in closing delimiter", fixIts: ["remove extraneous delimiters"]) + DiagnosticSpec(message: "too many '#' characters in closing delimiter", fixIts: ["remove extraneous delimiters"]) ], fixedSource: "#/abc/#" ) @@ -65,7 +65,10 @@ final class RegexLiteralTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected identifier in macro expansion", fixIts: ["insert identifier"]) - ] + ], + fixedSource: #""" + #<#identifier#> + """# ) } @@ -76,7 +79,10 @@ final class RegexLiteralTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected '/' to end regex literal", fixIts: ["insert '/'"]) - ] + ], + fixedSource: #""" + // + """# ) } @@ -87,7 +93,10 @@ final class RegexLiteralTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected identifier in macro expansion", fixIts: ["insert identifier"]) - ] + ], + fixedSource: #""" + /#<#identifier#> + """# ) } @@ -98,7 +107,10 @@ final class RegexLiteralTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected '/#' to end regex literal", fixIts: ["insert '/#'"]) - ] + ], + fixedSource: #""" + #//# + """# ) } @@ -109,7 +121,10 @@ final class RegexLiteralTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected '#' to end regex literal", fixIts: ["insert '#'"]) - ] + ], + fixedSource: #""" + #//# + """# ) } @@ -120,7 +135,10 @@ final class RegexLiteralTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected '#' to end regex literal", fixIts: ["insert '#'"]) - ] + ], + fixedSource: #""" + #///# + """# ) } @@ -131,7 +149,10 @@ final class RegexLiteralTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected '/#' to end regex literal", fixIts: ["insert '/#'"]) - ] + ], + fixedSource: #""" + #/#/# + """# ) } @@ -142,7 +163,10 @@ final class RegexLiteralTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected '/#' to end regex literal", fixIts: ["insert '/#'"]) - ] + ], + fixedSource: #""" + #/##/# + """# ) } @@ -153,7 +177,10 @@ final class RegexLiteralTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected '#' to end regex literal", fixIts: ["insert '#'"]) - ] + ], + fixedSource: #""" + #/##/# + """# ) } @@ -316,7 +343,11 @@ final class RegexLiteralTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '/#' to end regex literal", fixIts: ["insert '/#'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]), - ] + ], + fixedSource: """ + #/abc/# + /#<#identifier#> + """ ) } @@ -329,7 +360,11 @@ final class RegexLiteralTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '/#' to end regex literal", fixIts: ["insert '/#'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]), - ] + ], + fixedSource: """ + #/abc/# + \t \t /#<#identifier#> + """ ) } @@ -392,7 +427,10 @@ final class RegexLiteralTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + /a / <#expression#> + """ ) } @@ -403,7 +441,10 @@ final class RegexLiteralTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + let x = /a / <#expression#> + """ ) } @@ -686,7 +727,10 @@ final class RegexLiteralTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected name in member access", fixIts: ["insert name"]) - ] + ], + fixedSource: """ + x.<#identifier#> /^ x/ + """ ) } @@ -698,7 +742,10 @@ final class RegexLiteralTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected identifier in macro expansion", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + #<#identifier#> /^ x/ + """ ) } @@ -718,7 +765,10 @@ final class RegexLiteralTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected root in key path", fixIts: ["insert root"]) - ] + ], + fixedSource: #""" + \<#type#> /^ x/ + """# ) } @@ -826,7 +876,10 @@ final class RegexLiteralTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression in 'await' expression", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + await <#expression#> /^ x/ + """ ) } @@ -1133,7 +1186,10 @@ final class RegexLiteralTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'=' must have consistent whitespace on both sides", fixIts: ["insert whitespace"]) - ] + ], + fixedSource: """ + let x = /abc/ + """ ) } @@ -1145,7 +1201,10 @@ final class RegexLiteralTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected name in member access", fixIts: ["insert name"]), - ] + ], + fixedSource: """ + let x; .<#identifier#>/abc/ + """ ) } diff --git a/Tests/SwiftParserTest/StatementTests.swift b/Tests/SwiftParserTest/StatementTests.swift index 0ea575be207..4b503ce689d 100644 --- a/Tests/SwiftParserTest/StatementTests.swift +++ b/Tests/SwiftParserTest/StatementTests.swift @@ -80,7 +80,12 @@ final class StatementTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected expression, '=', and expression in pattern matching", fixIts: ["insert expression, '=', and expression"]), DiagnosticSpec(message: "unexpected code '* ! = x' in 'if' statement"), - ] + ], + fixedSource: """ + if case <#expression#> = <#expression#> * ! = x { + bar() + } + """ ) assertParse( @@ -286,7 +291,18 @@ final class StatementTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code 'foo()' before conditional compilation clause"), DiagnosticSpec(locationMarker: "2️⃣", message: "all statements inside a switch must be covered by a 'case' or 'default' label", fixIts: ["insert label"]), - ] + ], + fixedSource: """ + switch x { + foo() + #if true + case <#identifier#>: + bar() + #endif + case .A, .B: + break + } + """ ) assertParse( @@ -615,7 +631,10 @@ final class StatementTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'forget' statement", fixIts: ["insert expression"]), DiagnosticSpec(locationMarker: "1️⃣", message: "'case' can only appear inside a 'switch' statement or 'enum' declaration"), - ] + ], + fixedSource: """ + _forget <#expression#>case + """ ) // It's important that we don't parse this one as a forget statement! @@ -682,7 +701,11 @@ final class StatementTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '}' to end 'if' statement", fixIts: ["insert '}'"]) - ] + ], + fixedSource: """ + if p{"" + } + """ ) } @@ -696,7 +719,11 @@ final class StatementTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected '->' and return type in subscript", fixIts: ["insert '->' and return type"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end subscript", fixIts: ["insert '}'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "extraneous code '@self _modify' at top level"), - ] + ], + fixedSource: """ + subscript() -> <#type#> { + }@self _modify + """ ) } } diff --git a/Tests/SwiftParserTest/TypeMemberTests.swift b/Tests/SwiftParserTest/TypeMemberTests.swift index fa3eac6a698..ac6fcf20598 100644 --- a/Tests/SwiftParserTest/TypeMemberTests.swift +++ b/Tests/SwiftParserTest/TypeMemberTests.swift @@ -42,7 +42,12 @@ final class TypeMemberTests: XCTestCase { name: .identifier("", presence: .missing) ) ), - diagnostics: [DiagnosticSpec(message: "expected name in member type", fixIts: ["insert name"])] + diagnostics: [ + DiagnosticSpec(message: "expected name in member type", fixIts: ["insert name"]) + ], + fixedSource: """ + MyType.<#identifier#> + """ ) } diff --git a/Tests/SwiftParserTest/TypeTests.swift b/Tests/SwiftParserTest/TypeTests.swift index 90eaf0f0683..cb8f709eb17 100644 --- a/Tests/SwiftParserTest/TypeTests.swift +++ b/Tests/SwiftParserTest/TypeTests.swift @@ -62,7 +62,10 @@ final class TypeTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected type in function type", fixIts: ["insert type"]), DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code '..' in function type"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected return type in function type", fixIts: ["insert return type"]), - ] + ], + fixedSource: """ + t as(<#type#>..)-> <#type#> + """ ) } @@ -97,7 +100,11 @@ final class TypeTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in closure capture item", fixIts: ["insert identifier"]), DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected 'class' keyword in closure capture signature"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end closure", fixIts: ["insert '}'"]), - ] + ], + fixedSource: """ + {[<#identifier#>class]in + } + """ ) assertParse( @@ -114,7 +121,10 @@ final class TypeTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected identifier in closure capture item", fixIts: ["insert identifier"]), DiagnosticSpec(message: "unexpected code '^' in closure capture signature"), - ] + ], + fixedSource: """ + {[weak <#identifier#>^]in} + """ ) } diff --git a/Tests/SwiftParserTest/VariadicGenericsTests.swift b/Tests/SwiftParserTest/VariadicGenericsTests.swift index 85124384aae..e8b0355f255 100644 --- a/Tests/SwiftParserTest/VariadicGenericsTests.swift +++ b/Tests/SwiftParserTest/VariadicGenericsTests.swift @@ -61,7 +61,10 @@ final class VariadicGenericsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected ',' in tuple type", fixIts: ["insert ','"]) - ] + ], + fixedSource: """ + func invalid() -> (each any, T) {} + """ ) assertParse( @@ -101,7 +104,10 @@ final class VariadicGenericsTests: XCTestCase { message: "ellipsis operator cannot be used with a type parameter pack", fixIts: ["remove '...'"] ) - ] + ], + fixedSource: """ + func invalid(_ t: repeat each T) {} + """ ) } @@ -335,7 +341,12 @@ final class TypeParameterPackTests: XCTestCase { message: "associated types cannot be variadic", fixIts: ["remove 'each'"] ) - ] + ], + fixedSource: """ + protocol P { + associatedtype T + } + """ ) } func testParameterPacks4EarlySyntax() { @@ -350,7 +361,12 @@ final class TypeParameterPackTests: XCTestCase { message: "associated types cannot be variadic", fixIts: ["remove '...'"] ) - ] + ], + fixedSource: """ + protocol P { + associatedtype T + } + """ ) } func testParameterPacks5() { @@ -574,7 +590,10 @@ final class TypeParameterPackTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected ',' in tuple type", fixIts: ["insert ','"]) - ] + ], + fixedSource: """ + var foo: (bar: Int, Int) + """ ) assertParse( @@ -595,7 +614,10 @@ final class TypeParameterPackTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected ',' in tuple type", fixIts: ["insert ','"]) - ] + ], + fixedSource: """ + var foo: (A, Int) + """ ) assertParse( @@ -605,7 +627,10 @@ final class TypeParameterPackTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected ':' in tuple type", fixIts: ["insert ':'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected ',' in tuple type", fixIts: ["insert ','"]), - ] + ], + fixedSource: """ + var foo: (_: a, Int) + """ ) assertParse( diff --git a/Tests/SwiftParserTest/translated/ActorTests.swift b/Tests/SwiftParserTest/translated/ActorTests.swift index d087221ed7f..a0098ebd1cc 100644 --- a/Tests/SwiftParserTest/translated/ActorTests.swift +++ b/Tests/SwiftParserTest/translated/ActorTests.swift @@ -22,7 +22,11 @@ final class ActorTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected member block in actor", fixIts: ["insert member block"]) - ] + ], + fixedSource: """ + actor MyActor1 { + } + """ ) } @@ -42,7 +46,14 @@ final class ActorTests: XCTestCase { ], fixIts: ["insert '}'"] ) - ] + ], + fixedSource: """ + actor MyActor2 { + init() { + } + func hello() { } + } + """ ) } } diff --git a/Tests/SwiftParserTest/translated/AsyncTests.swift b/Tests/SwiftParserTest/translated/AsyncTests.swift index 21b2e14e383..370e0789dc0 100644 --- a/Tests/SwiftParserTest/translated/AsyncTests.swift +++ b/Tests/SwiftParserTest/translated/AsyncTests.swift @@ -120,7 +120,21 @@ final class AsyncTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "deinitializers cannot have a name", fixIts: ["remove 'async'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code 'async' in subscript"), - ] + ], + fixedSource: """ + class X { + init() async { } + deinit { } + func f() async { } + subscript(x: Int) async -> Int { + get { + return 0 + } + set async { + } + } + } + """ ) } diff --git a/Tests/SwiftParserTest/translated/AvailabilityQueryTests.swift b/Tests/SwiftParserTest/translated/AvailabilityQueryTests.swift index d14eac569c5..5705816c546 100644 --- a/Tests/SwiftParserTest/translated/AvailabilityQueryTests.swift +++ b/Tests/SwiftParserTest/translated/AvailabilityQueryTests.swift @@ -82,7 +82,11 @@ final class AvailabilityQueryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "availability condition cannot be used in an expression; did you mean '#unavailable'?", fixIts: ["replace '!#available' with '#unavailable'"]) - ] + ], + fixedSource: """ + if let _ = Optional(5), #unavailable(OSX 10.52, *) { + } + """ ) } @@ -114,7 +118,11 @@ final class AvailabilityQueryTests: XCTestCase { message: "expected '(', '@availability' arguments, and ')' in availability condition", fixIts: ["insert '(', '@availability' arguments, and ')'"] ) - ] + ], + fixedSource: """ + if #available (<#identifier#>) { + } + """ ) } @@ -126,7 +134,11 @@ final class AvailabilityQueryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected platform and ')' to end availability condition", fixIts: ["insert platform and ')'"]) - ] + ], + fixedSource: """ + if #available(<#identifier#>) { + } + """ ) } @@ -138,7 +150,11 @@ final class AvailabilityQueryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected version restriction in availability argument", fixIts: ["insert version restriction"]) - ] + ], + fixedSource: """ + if #available(<#identifier#>) { + } + """ ) } @@ -156,7 +172,11 @@ final class AvailabilityQueryTests: XCTestCase { ], fixIts: ["insert ')'"] ) - ] + ], + fixedSource: """ + if #available(OSX) { + } + """ ) } @@ -183,7 +203,11 @@ final class AvailabilityQueryTests: XCTestCase { ], fixIts: ["insert ')'"] ) - ] + ], + fixedSource: """ + if #available(OSX 10.51) { + } + """ ) } @@ -308,7 +332,11 @@ final class AvailabilityQueryTests: XCTestCase { ], fixIts: ["insert ')'"] ) - ] + ], + fixedSource: """ + if #available(*) { + } + """ ) } @@ -331,7 +359,11 @@ final class AvailabilityQueryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected version restriction in availability argument", fixIts: ["insert version restriction"]), DiagnosticSpec(message: "expected ')' to end availability condition", fixIts: ["insert ')'"]), - ] + ], + fixedSource: """ + if #available(OSX 10.51, <#identifier#>) { + } + """ ) } @@ -343,7 +375,11 @@ final class AvailabilityQueryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected version restriction in availability argument", fixIts: ["insert version restriction"]) - ] + ], + fixedSource: """ + if #available(OSX 10.51, <#identifier#>) { + } + """ ) } @@ -361,7 +397,11 @@ final class AvailabilityQueryTests: XCTestCase { ], fixIts: ["insert ')'"] ) - ] + ], + fixedSource: """ + if #available(OSX 10.51, iOS) { + } + """ ) } diff --git a/Tests/SwiftParserTest/translated/AvailabilityQueryUnavailabilityTests.swift b/Tests/SwiftParserTest/translated/AvailabilityQueryUnavailabilityTests.swift index 86587ee3fb3..4f23ab006ad 100644 --- a/Tests/SwiftParserTest/translated/AvailabilityQueryUnavailabilityTests.swift +++ b/Tests/SwiftParserTest/translated/AvailabilityQueryUnavailabilityTests.swift @@ -36,9 +36,18 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { (3️⃣#unavailable(OSX 10.51) ? 1 : 0) """, diagnostics: [ - DiagnosticSpec(locationMarker: "1️⃣", message: "availability condition cannot be used in an expression, only as a condition of 'if' or 'guard'"), - DiagnosticSpec(locationMarker: "2️⃣", message: "availability condition cannot be used in an expression, only as a condition of 'if' or 'guard'"), - DiagnosticSpec(locationMarker: "3️⃣", message: "availability condition cannot be used in an expression, only as a condition of 'if' or 'guard'"), + DiagnosticSpec( + locationMarker: "1️⃣", + message: "availability condition cannot be used in an expression, only as a condition of 'if' or 'guard'" + ), + DiagnosticSpec( + locationMarker: "2️⃣", + message: "availability condition cannot be used in an expression, only as a condition of 'if' or 'guard'" + ), + DiagnosticSpec( + locationMarker: "3️⃣", + message: "availability condition cannot be used in an expression, only as a condition of 'if' or 'guard'" + ), ] ) } @@ -50,7 +59,10 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "availability condition cannot be used in an expression; did you mean '#available'?", fixIts: ["replace '!#unavailable' with '#available'"]) + DiagnosticSpec( + message: "availability condition cannot be used in an expression; did you mean '#available'?", + fixIts: ["replace '!#unavailable' with '#available'"] + ) ], fixedSource: """ if #available(OSX 10.52) { @@ -66,8 +78,15 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "availability condition cannot be used in an expression; did you mean '#available'?", fixIts: ["replace '!#unavailable' with '#available'"]) - ] + DiagnosticSpec( + message: "availability condition cannot be used in an expression; did you mean '#available'?", + fixIts: ["replace '!#unavailable' with '#available'"] + ) + ], + fixedSource: """ + if let _ = Optional(5), #available(OSX 10.52) { + } + """ ) } @@ -78,8 +97,15 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "expected ',' joining parts of a multi-clause condition", fixIts: ["replace '&&' with ','"]) - ] + DiagnosticSpec( + message: "expected ',' joining parts of a multi-clause condition", + fixIts: ["replace '&&' with ','"] + ) + ], + fixedSource: """ + if #unavailable(OSX 10.51) , #unavailable(OSX 10.52) { + } + """ ) } @@ -90,7 +116,10 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "expected '(', '@availability' arguments, and ')' in availability condition", fixIts: ["insert '(', '@availability' arguments, and ')'"]) + DiagnosticSpec( + message: "expected '(', '@availability' arguments, and ')' in availability condition", + fixIts: ["insert '(', '@availability' arguments, and ')'"] + ) ], fixedSource: """ if #unavailable(<#identifier#>) { @@ -122,7 +151,10 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "expected version restriction in availability argument", fixIts: ["insert version restriction"]) + DiagnosticSpec( + message: "expected version restriction in availability argument", + fixIts: ["insert version restriction"] + ) ], fixedSource: """ if #unavailable(<#identifier#>) { @@ -145,7 +177,11 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { ], fixIts: ["insert ')'"] ) - ] + ], + fixedSource: """ + if #unavailable(OSX) { + } + """ ) } @@ -270,7 +306,10 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "expected version restriction in availability argument", fixIts: ["insert version restriction"]) + DiagnosticSpec( + message: "expected version restriction in availability argument", + fixIts: ["insert version restriction"] + ) ], fixedSource: """ // Should this be a valid spelling since `#unvailable(*)` cannot be written? @@ -319,8 +358,14 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "expected version restriction in availability argument", fixIts: ["insert version restriction"]), - DiagnosticSpec(message: "expected ')' to end availability condition", fixIts: ["insert ')'"]), + DiagnosticSpec( + message: "expected version restriction in availability argument", + fixIts: ["insert version restriction"] + ), + DiagnosticSpec( + message: "expected ')' to end availability condition", + fixIts: ["insert ')'"] + ), ], fixedSource: """ if #unavailable(OSX 10.51, <#identifier#>) { @@ -336,7 +381,10 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "expected version restriction in availability argument", fixIts: ["insert version restriction"]) + DiagnosticSpec( + message: "expected version restriction in availability argument", + fixIts: ["insert version restriction"] + ) ], fixedSource: """ if #unavailable(OSX 10.51, <#identifier#>) { @@ -392,7 +440,10 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "expected ',' joining platforms in availability condition", fixIts: ["replace '||' with ','"]) + DiagnosticSpec( + message: "expected ',' joining platforms in availability condition", + fixIts: ["replace '||' with ','"] + ) ], fixedSource: """ if #unavailable(OSX 10.51 , iOS 8.0) { @@ -410,7 +461,12 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "version comparison not needed", fixIts: ["remove '>='"]) - ] + ], + fixedSource: """ + // Emit Fix-It removing un-needed >=, for the moment. + if #unavailable(OSX 10.51) { + } + """ ) } @@ -484,7 +540,10 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "#available cannot be used as an expression, did you mean to use '#unavailable'?", fixIts: ["replace '#available(*) == false' with '#unavailable(*)'"]) + DiagnosticSpec( + message: "#available cannot be used as an expression, did you mean to use '#unavailable'?", + fixIts: ["replace '#available(*) == false' with '#unavailable(*)'"] + ) ], fixedSource: """ if #unavailable(*) { @@ -500,8 +559,16 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(locationMarker: "1️⃣", message: "#available cannot be used as an expression, did you mean to use '#unavailable'?", fixIts: ["replace '#available(*) == false' with '#unavailable(*)'"]), - DiagnosticSpec(locationMarker: "2️⃣", message: "expected ',' joining parts of a multi-clause condition", fixIts: ["replace '&&' with ','"]), + DiagnosticSpec( + locationMarker: "1️⃣", + message: "#available cannot be used as an expression, did you mean to use '#unavailable'?", + fixIts: ["replace '#available(*) == false' with '#unavailable(*)'"] + ), + DiagnosticSpec( + locationMarker: "2️⃣", + message: "expected ',' joining parts of a multi-clause condition", + fixIts: ["replace '&&' with ','"] + ), ], fixedSource: """ if #unavailable(*) , true { @@ -517,7 +584,10 @@ final class AvailabilityQueryUnavailabilityTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "availability condition cannot be used in an expression; did you mean '#unavailable'?", fixIts: ["replace '!#available' with '#unavailable'"]) + DiagnosticSpec( + message: "availability condition cannot be used in an expression; did you mean '#unavailable'?", + fixIts: ["replace '!#available' with '#unavailable'"] + ) ], fixedSource: """ if #unavailable(*) { diff --git a/Tests/SwiftParserTest/translated/BraceRecoveryEofTests.swift b/Tests/SwiftParserTest/translated/BraceRecoveryEofTests.swift index 6dd408cf043..a9320c71c10 100644 --- a/Tests/SwiftParserTest/translated/BraceRecoveryEofTests.swift +++ b/Tests/SwiftParserTest/translated/BraceRecoveryEofTests.swift @@ -30,7 +30,13 @@ final class BraceRecoveryEofTests: XCTestCase { ], fixIts: ["insert '}'"] ) - ] + ], + fixedSource: """ + // Make sure source ranges satisfy the verifier. + for foo in [1, 2] { + _ = foo + } + """ ) } } diff --git a/Tests/SwiftParserTest/translated/ConsecutiveStatementsTests.swift b/Tests/SwiftParserTest/translated/ConsecutiveStatementsTests.swift index 47e3cee123c..144dd3f3fe4 100644 --- a/Tests/SwiftParserTest/translated/ConsecutiveStatementsTests.swift +++ b/Tests/SwiftParserTest/translated/ConsecutiveStatementsTests.swift @@ -64,7 +64,20 @@ final class ConsecutiveStatementsTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), - ] + ], + fixedSource: """ + // Within a function + func test(i: inout Int, j: inout Int) { + // Okay + let q : Int; i = j; j = i; _ = q + if i != j { i = j } + // Errors + i = j; j = i + let r : Int; i = j + let s : Int; let t : Int + _ = r; _ = s; _ = t + } + """ ) } @@ -94,7 +107,25 @@ final class ConsecutiveStatementsTests: XCTestCase { DiagnosticSpec(locationMarker: "3️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "4️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "5️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), - ] + ], + fixedSource: """ + struct X { + // In a sequence of declarations. + var a, b : Int; func d() -> Int {} + var prop : Int { return 4 + }; var other : Float + // Within property accessors + subscript(i: Int) -> Float { + get { + var x = i; x = i + x; return Float(x) + } + set { + var x = i; x = i + 1 + _ = x + } + } + } + """ ) } @@ -174,7 +205,11 @@ final class ConsecutiveStatementsTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), - ] + ], + fixedSource: """ + // At the top level + var i, j : Int; i = j; j = i + """ ) } } diff --git a/Tests/SwiftParserTest/translated/DeprecatedWhereTests.swift b/Tests/SwiftParserTest/translated/DeprecatedWhereTests.swift index aadceeb012f..277f64acaaa 100644 --- a/Tests/SwiftParserTest/translated/DeprecatedWhereTests.swift +++ b/Tests/SwiftParserTest/translated/DeprecatedWhereTests.swift @@ -166,7 +166,10 @@ final class DeprecatedWhereTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected identifier in protocol", fixIts: ["insert identifier"]), DiagnosticSpec(locationMarker: "4️⃣", message: "unexpected code '>(x: T)' in protocol"), - ] + ], + fixedSource: """ + func testCombinedConstraintsOld>()protocol <#identifier#> where T: ProtoC>(x: T) {} + """ ) } @@ -181,8 +184,10 @@ final class DeprecatedWhereTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected identifier in protocol", fixIts: ["insert identifier"]), DiagnosticSpec(locationMarker: "4️⃣", message: "unexpected code '>(x: T) where T: ProtoD' in protocol"), - ] + ], + fixedSource: """ + func testCombinedConstraintsOld>()protocol <#identifier#> where T: ProtoC>(x: T) where T: ProtoD {} + """ ) } - } diff --git a/Tests/SwiftParserTest/translated/DiagnoseDynamicReplacementTests.swift b/Tests/SwiftParserTest/translated/DiagnoseDynamicReplacementTests.swift index 51d1d93d819..8a0283c5909 100644 --- a/Tests/SwiftParserTest/translated/DiagnoseDynamicReplacementTests.swift +++ b/Tests/SwiftParserTest/translated/DiagnoseDynamicReplacementTests.swift @@ -33,7 +33,12 @@ final class DiagnoseDynamicReplacementTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '(', @_dynamicReplacement argument, and ')' in attribute", fixIts: ["insert '(', @_dynamicReplacement argument, and ')'"]) - ] + ], + fixedSource: """ + @_dynamicReplacement(for: <#identifier#>) + func test_dynamic_replacement_for() { + } + """ ) } @@ -47,7 +52,12 @@ final class DiagnoseDynamicReplacementTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected argument for '@_dynamicReplacement' attribute", fixIts: ["insert attribute argument"]), DiagnosticSpec(message: "expected ')' to end attribute", fixIts: ["insert ')'"]), - ] + ], + fixedSource: """ + @_dynamicReplacement(for: <#identifier#>) + func test_dynamic_replacement_for2() { + } + """ ) } diff --git a/Tests/SwiftParserTest/translated/DiagnoseInitializerAsTypedPatternTests.swift b/Tests/SwiftParserTest/translated/DiagnoseInitializerAsTypedPatternTests.swift index 712ef3a5e27..69d46f057a1 100644 --- a/Tests/SwiftParserTest/translated/DiagnoseInitializerAsTypedPatternTests.swift +++ b/Tests/SwiftParserTest/translated/DiagnoseInitializerAsTypedPatternTests.swift @@ -127,7 +127,10 @@ final class DiagnoseInitializerAsTypedPatternTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "unexpected initializer in pattern; did you mean to use '='?", fixIts: ["replace ':' with '='"]) - ] + ], + fixedSource: """ + let g= X(x) + """ ) } @@ -138,7 +141,10 @@ final class DiagnoseInitializerAsTypedPatternTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "unexpected initializer in pattern; did you mean to use '='?", fixIts: ["replace ':' with '='"]) - ] + ], + fixedSource: """ + let h= X(x, y) + """ ) } @@ -149,7 +155,10 @@ final class DiagnoseInitializerAsTypedPatternTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "unexpected initializer in pattern; did you mean to use '='?", fixIts: ["replace ':' with '='"]) - ] + ], + fixedSource: """ + let i= X() { foo() } + """ ) } @@ -160,7 +169,10 @@ final class DiagnoseInitializerAsTypedPatternTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "unexpected initializer in pattern; did you mean to use '='?", fixIts: ["replace ':' with '='"]) - ] + ], + fixedSource: """ + let j= X(x) { foo() } + """ ) } @@ -171,7 +183,10 @@ final class DiagnoseInitializerAsTypedPatternTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "unexpected initializer in pattern; did you mean to use '='?", fixIts: ["replace ':' with '='"]) - ] + ], + fixedSource: """ + let k= X(x, y) { foo() } + """ ) } @@ -184,7 +199,12 @@ final class DiagnoseInitializerAsTypedPatternTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "unexpected initializer in pattern; did you mean to use '='?", fixIts: ["replace ':' with '='"]) - ] + ], + fixedSource: """ + func nonTopLevel() { + let a=[X]() + } + """ ) } @@ -197,7 +217,12 @@ final class DiagnoseInitializerAsTypedPatternTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "unexpected initializer in pattern; did you mean to use '='?", fixIts: ["replace ':' with '='"]) - ] + ], + fixedSource: """ + func nonTopLevel() { + let i= X() { foo() } + } + """ ) } @@ -210,7 +235,12 @@ final class DiagnoseInitializerAsTypedPatternTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "unexpected initializer in pattern; did you mean to use '='?", fixIts: ["replace ':' with '='"]) - ] + ], + fixedSource: """ + func nonTopLevel() { + let j= X(x) { foo() } + } + """ ) } @@ -223,7 +253,12 @@ final class DiagnoseInitializerAsTypedPatternTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "unexpected initializer in pattern; did you mean to use '='?", fixIts: ["replace ':' with '='"]) - ] + ], + fixedSource: """ + func nonTopLevel() { + let k= X(x, y) { foo() } + } + """ ) } diff --git a/Tests/SwiftParserTest/translated/DiagnosticMissingFuncKeywordTests.swift b/Tests/SwiftParserTest/translated/DiagnosticMissingFuncKeywordTests.swift index e8a55685bfc..18bffaff61d 100644 --- a/Tests/SwiftParserTest/translated/DiagnosticMissingFuncKeywordTests.swift +++ b/Tests/SwiftParserTest/translated/DiagnosticMissingFuncKeywordTests.swift @@ -148,7 +148,12 @@ final class DiagnosticMissingFuncKeywordTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected 'var' in variable", fixIts: ["insert 'var'"]) - ] + ], + fixedSource: """ + struct Bar { + var fisr = 0x5F3759DF + } + """ ) } @@ -163,7 +168,14 @@ final class DiagnosticMissingFuncKeywordTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected 'func' in function", fixIts: ["insert 'func'"]) - ] + ], + fixedSource: """ + struct Bar { + func %% (lhs: T, rhs: T) -> T { + lhs + lhs + rhs + rhs + } + } + """ ) } @@ -176,7 +188,12 @@ final class DiagnosticMissingFuncKeywordTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected 'var' in variable", fixIts: ["insert 'var'"]) - ] + ], + fixedSource: """ + struct Bar { + var _: Int = 42 + } + """ ) } @@ -189,7 +206,12 @@ final class DiagnosticMissingFuncKeywordTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected 'var' in variable", fixIts: ["insert 'var'"]) - ] + ], + fixedSource: """ + struct Bar { + var (light, dark) = (100, 200) + } + """ ) } @@ -220,7 +242,12 @@ final class DiagnosticMissingFuncKeywordTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected 'func' in function", fixIts: ["insert 'func'"]) - ] + ], + fixedSource: """ + class Baz { + func instanceMethod() {} + } + """ ) } @@ -233,7 +260,12 @@ final class DiagnosticMissingFuncKeywordTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected 'func' in function", fixIts: ["insert 'func'"]) - ] + ], + fixedSource: """ + class Baz { + static func staticMethod() {} + } + """ ) } @@ -246,7 +278,12 @@ final class DiagnosticMissingFuncKeywordTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected 'var' in variable", fixIts: ["insert 'var'"]) - ] + ], + fixedSource: """ + class Baz { + var instanceProperty: Int { 0 } + } + """ ) } @@ -259,7 +296,12 @@ final class DiagnosticMissingFuncKeywordTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected 'var' in variable", fixIts: ["insert 'var'"]) - ] + ], + fixedSource: """ + class Baz { + static var staticProperty: Int { 0 } + } + """ ) } diff --git a/Tests/SwiftParserTest/translated/DollarIdentifierTests.swift b/Tests/SwiftParserTest/translated/DollarIdentifierTests.swift index 8f5371b7c52..d0482bde3f6 100644 --- a/Tests/SwiftParserTest/translated/DollarIdentifierTests.swift +++ b/Tests/SwiftParserTest/translated/DollarIdentifierTests.swift @@ -36,7 +36,14 @@ final class DollarIdentifierTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'$' is not a valid identifier", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + func dollarVar() { + var `$` : Int = 42 + $ += 1 + print($) + } + """ ) } @@ -50,7 +57,13 @@ final class DollarIdentifierTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'$' is not a valid identifier", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + func dollarLet() { + let `$` = 42 + print($) + } + """ ) } @@ -81,7 +94,12 @@ final class DollarIdentifierTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'$' is not a valid identifier", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + func dollarEnum() { + enum `$` {} + } + """ ) } @@ -94,7 +112,12 @@ final class DollarIdentifierTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'$' is not a valid identifier", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + func dollarStruct() { + struct `$` {} + } + """ ) } @@ -118,7 +141,10 @@ final class DollarIdentifierTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'$' is not a valid identifier", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + $(`$`: 24) + """ ) } diff --git a/Tests/SwiftParserTest/translated/EffectfulPropertiesTests.swift b/Tests/SwiftParserTest/translated/EffectfulPropertiesTests.swift index 7041c8b5d5b..57afebd2dbc 100644 --- a/Tests/SwiftParserTest/translated/EffectfulPropertiesTests.swift +++ b/Tests/SwiftParserTest/translated/EffectfulPropertiesTests.swift @@ -188,7 +188,13 @@ final class EffectfulPropertiesTests: XCTestCase { message: "expected throwing specifier; did you mean 'throws'?", fixIts: ["replace 'rethrows' with 'throws'"] ), - ] + ], + fixedSource: """ + var bad1 : Int { + get throws { 0 } + set throws { } + } + """ ) } @@ -211,7 +217,13 @@ final class EffectfulPropertiesTests: XCTestCase { message: "expected async specifier; did you mean 'async'?", fixIts: ["replace 'reasync' with 'async'"] ), - ] + ], + fixedSource: """ + var bad2 : Int { + get async { 0 } + set async { } + } + """ ) } @@ -245,7 +257,12 @@ final class EffectfulPropertiesTests: XCTestCase { notes: [NoteSpec(locationMarker: "3️⃣", message: "'throws' declared here")], fixIts: ["remove redundant 'rethrows'"] ), - ] + ], + fixedSource: """ + var bad4 : Int = 0 { + willSet(theValue) async async throws {} + } + """ ) } @@ -289,7 +306,12 @@ final class EffectfulPropertiesTests: XCTestCase { fixIts: ["replace 'rethrows' with 'throws'"] ), DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '-> Int' in accessor"), - ] + ], + fixedSource: """ + var bad6 : Int { + get throws -> Int { 0 } + } + """ ) } @@ -302,7 +324,12 @@ final class EffectfulPropertiesTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'async' must precede 'throws'", fixIts: ["move 'async' in front of 'throws'"]) - ] + ], + fixedSource: """ + var bad7 : Double { + get async throws { 3.14 } + } + """ ) } @@ -316,7 +343,13 @@ final class EffectfulPropertiesTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'async' must precede 'throws'", fixIts: ["move 'async' in front of 'throws'"]) - ] + ], + fixedSource: """ + var bad8 : Double { + get {} + _modify async throws { yield &bad8 } + } + """ ) } @@ -349,7 +382,15 @@ final class EffectfulPropertiesTests: XCTestCase { message: "'async' must precede 'throws'", fixIts: ["move 'async' in front of 'throws'"] ), - ] + ], + fixedSource: """ + protocol BadP { + var prop2 : Int { get bogus rethrows set } + var prop3 : Int { get throws bogus set } + var prop4 : Int { get async bogus set } + var prop5 : Int { get async throws } + } + """ ) } } diff --git a/Tests/SwiftParserTest/translated/EnumTests.swift b/Tests/SwiftParserTest/translated/EnumTests.swift index 2bdf1d1b9e4..159624e0d2f 100644 --- a/Tests/SwiftParserTest/translated/EnumTests.swift +++ b/Tests/SwiftParserTest/translated/EnumTests.swift @@ -333,9 +333,9 @@ final class EnumTests: XCTestCase { } func testEnum20() { + // We used to crash on this. rdar://14678675 assertParse( """ - // We used to crash on this. rdar://14678675 enum rdar14678675 { case U1, 1️⃣ case U2 @@ -344,7 +344,14 @@ final class EnumTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected identifier in enum case", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + enum rdar14678675 { + case U1, <#identifier#> + case U2 + case U3 + } + """ ) } @@ -358,7 +365,12 @@ final class EnumTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected identifier in enum case", fixIts: ["insert identifier"]), DiagnosticSpec(message: "unexpected code ':' in enum"), - ] + ], + fixedSource: """ + enum Recovery1 { + case <#identifier#>: + } + """ ) } @@ -396,9 +408,18 @@ final class EnumTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(locationMarker: "1️⃣", message: "keyword 'Self' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]), + DiagnosticSpec( + locationMarker: "1️⃣", + message: "keyword 'Self' cannot be used as an identifier here", + fixIts: ["if this name is unavoidable, use backticks to escape it"] + ), DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected 'Self' keyword in enum"), - ] + ], + fixedSource: """ + enum Recovery4 { + case `Self` Self + } + """ ) } @@ -431,7 +452,14 @@ final class EnumTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "'_' cannot be used as an identifier here"), DiagnosticSpec(locationMarker: "2️⃣", message: "'_' cannot be used as an identifier here"), DiagnosticSpec(locationMarker: "3️⃣", message: "expected identifier in enum case", fixIts: ["insert identifier"]), - ] + ], + fixedSource: """ + enum Recovery6 { + case Snout, _; + case _; + case Tusk, <#identifier#> + } + """ ) } @@ -1207,8 +1235,14 @@ final class EnumTests: XCTestCase { enum 1️⃣switch {} """, diagnostics: [ - DiagnosticSpec(message: "keyword 'switch' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + DiagnosticSpec( + message: "keyword 'switch' cannot be used as an identifier here", + fixIts: ["if this name is unavoidable, use backticks to escape it"] + ) + ], + fixedSource: """ + enum `switch` {} + """ ) } @@ -1240,8 +1274,18 @@ final class EnumTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "keyword 'operator' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + DiagnosticSpec( + message: "keyword 'operator' cannot be used as an identifier here", + fixIts: ["if this name is unavoidable, use backticks to escape it"] + ) + ], + fixedSource: """ + enum E_53662 { + case identifier + case `operator` + case identifier2 + } + """ ) } @@ -1255,8 +1299,18 @@ final class EnumTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "keyword 'var' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + DiagnosticSpec( + message: "keyword 'var' cannot be used as an identifier here", + fixIts: ["if this name is unavoidable, use backticks to escape it"] + ) + ], + fixedSource: """ + enum E_53662_var { + case identifier + case `var` + case identifier2 + } + """ ) } @@ -1283,8 +1337,16 @@ final class EnumTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "keyword 'func' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + DiagnosticSpec( + message: "keyword 'func' cannot be used as an identifier here", + fixIts: ["if this name is unavoidable, use backticks to escape it"] + ) + ], + fixedSource: """ + enum E_53662_Comma { + case a, b, c, `func`, d + } + """ ) } @@ -1300,7 +1362,15 @@ final class EnumTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected identifier in enum case", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + enum E_53662_Newline { + case identifier1 + case identifier2 + case <#identifier#> + case identifier + } + """ ) } @@ -1314,7 +1384,13 @@ final class EnumTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected identifier in enum case", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + enum E_53662_Newline2 { + case <#identifier#> + func foo() {} + } + """ ) } @@ -1326,9 +1402,21 @@ final class EnumTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(locationMarker: "1️⃣", message: "keyword 'let' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]), - DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '.foo(x, y):' in enum"), - ] + DiagnosticSpec( + locationMarker: "1️⃣", + message: "keyword 'let' cannot be used as an identifier here", + fixIts: ["if this name is unavoidable, use backticks to escape it"] + ), + DiagnosticSpec( + locationMarker: "2️⃣", + message: "unexpected code '.foo(x, y):' in enum" + ), + ], + fixedSource: """ + enum E_53662_PatternMatching { + case `let` .foo(x, y): + } + """ ) } @@ -1343,7 +1431,13 @@ final class EnumTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in enum case", fixIts: ["insert identifier"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in enum case", fixIts: ["insert identifier"]), - ] + ], + fixedSource: #""" + enum CasesWithMissingElement: Int { + case a = "hello", <#identifier#> + case b = "hello", <#identifier#> + } + """# ) } diff --git a/Tests/SwiftParserTest/translated/ErrorsTests.swift b/Tests/SwiftParserTest/translated/ErrorsTests.swift index 1b3bde275c1..e57eecaaa80 100644 --- a/Tests/SwiftParserTest/translated/ErrorsTests.swift +++ b/Tests/SwiftParserTest/translated/ErrorsTests.swift @@ -41,53 +41,12 @@ final class ErrorsTests: XCTestCase { func testErrors3() { assertParse( """ - func one() { - do { - true ? () : 1️⃣throw opaque_error() - } catch _ { - } - do { - } catch { - let error2 = error - } - do { - } catch 2️⃣where true { - let error2 = error - } catch { - } - // QoI: improve diagnostic on improper pattern match on type - do { - throw opaque_error() - } catch MSV { - } catch { - } - do { - throw opaque_error() - } catch is Error { - } - func foo() throws {} - do { - #if false - try foo() - #endif - } catch { // don't warn, #if code should be scanned. - } - do { - #if false - throw opaque_error() - #endif - } catch { // don't warn, #if code should be scanned. - } - do { - throw opaque_error() - } catch MSV.Foo, MSV.CarriesInt(let num) { - } catch { - } + do { + throw opaque_error() + } catch MSV.Foo, MSV.CarriesInt(let num) { + } catch { } - """, - diagnostics: [ - DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression after ternary operator", fixIts: ["insert expression"]) - ] + """ ) } @@ -173,7 +132,12 @@ final class ErrorsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'throws' must preceed '->'", fixIts: ["move 'throws' in front of '->'"]) - ] + ], + fixedSource: """ + func postThrows2() throws -> Int { + return try postThrows() + } + """ ) } @@ -204,7 +168,12 @@ final class ErrorsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'rethrows' must preceed '->'", fixIts: ["move 'rethrows' in front of '->'"]) - ] + ], + fixedSource: """ + func postRethrows2(_ f: () throws -> Int) rethrows -> Int { + return try f() + } + """ ) } @@ -217,7 +186,12 @@ final class ErrorsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'throws' must preceed '->'", fixIts: ["move 'throws' in front of '->'"]) - ] + ], + fixedSource: """ + func postThrows3() { + _ = { () throws -> Int in } + } + """ ) } @@ -394,7 +368,10 @@ final class ErrorsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected throwing specifier; did you mean 'throws'?", fixIts: ["replace 'try' with 'throws'"]) - ] + ], + fixedSource: """ + func fixitTry0(a: T) throws where T:ExpressibleByStringLiteral {} + """ ) } @@ -419,7 +396,10 @@ final class ErrorsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected throwing specifier; did you mean 'throws'?", fixIts: ["replace 'try' with 'throws'"]) - ] + ], + fixedSource: """ + func fixitTry2() throws {} + """ ) } @@ -430,7 +410,10 @@ final class ErrorsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected throwing specifier; did you mean 'throws'?", fixIts: ["replace 'try' with 'throws'"]) - ] + ], + fixedSource: """ + let fixitTry3 : () throws -> Int + """ ) } @@ -476,6 +459,93 @@ final class ErrorsTests: XCTestCase { ) } + func testErrors27() { + assertParse( + """ + do { + true ? () : 1️⃣throw opaque_error() + } catch _ { + } + """, + diagnostics: [ + DiagnosticSpec(message: "expected expression after ternary operator", fixIts: ["insert expression"]) + ], + fixedSource: """ + do { + true ? () : <#expression#>throw opaque_error() + } catch _ { + } + """ + ) + } + + func testErrors28() { + assertParse( + """ + do { + } catch { + let error2 = error + } + """ + ) + } + + func testErrors29() { + assertParse( + """ + do { + } catch where true { + let error2 = error + } catch { + } + """ + ) + } + + // QoI: improve diagnostic on improper pattern match on type + func testErrors30() { + assertParse( + """ + do { + throw opaque_error() + } catch MSV { + } catch { + } + """ + ) + } + + func testErrors31() { + assertParse( + """ + do { + throw opaque_error() + } catch is Error { + } + """ + ) + } + + func testErrors32() { + assertParse( + """ + func foo() throws {} + do { + #if false + try foo() + #endif + } catch { // don't warn, #if code should be scanned. + } + do { + #if false + throw opaque_error() + #endif + } catch { // don't warn, #if code should be scanned. + } + """ + ) + } + func testAwaitBetwenAsyncAndThrows() { assertParse( """ diff --git a/Tests/SwiftParserTest/translated/ForeachAsyncTests.swift b/Tests/SwiftParserTest/translated/ForeachAsyncTests.swift index 518de0e6a18..30c9b0ba773 100644 --- a/Tests/SwiftParserTest/translated/ForeachAsyncTests.swift +++ b/Tests/SwiftParserTest/translated/ForeachAsyncTests.swift @@ -60,30 +60,88 @@ final class ForeachAsyncTests: XCTestCase { for await i in r { sum = sum + i } - // Check scoping of variable introduced with foreach loop - i = 0 - // For-each loops with two variables and varying degrees of typedness + } + """ + ) + } + + // Check scoping of variable introduced with foreach loop + // For-each loops with two variables and varying degrees of typedness + func testForeachAsync5() { + assertParse( + """ + func for_each(r: AsyncRange, iir: AsyncIntRange) async { + var sum = 0 for await (i, j) in iir { sum = sum + i + j } + } + """ + ) + + assertParse( + """ + func for_each(r: AsyncRange, iir: AsyncIntRange) async { + var sum = 0 for await (i, j) in iir { sum = sum + i + j } + } + """ + ) + + assertParse( + """ + func for_each(r: AsyncRange, iir: AsyncIntRange) async { + var sum = 0 for await (i, j) : (Int, Int) in iir { sum = sum + i + j } - // Parse errors + } + """ + ) + } + + // Parse errors + func testForeachAsync6() { + assertParse( + """ + func for_each(r: AsyncRange, iir: AsyncIntRange) async { + var sum = 0 for await i 1️⃣r { } - for await i in r 2️⃣sum = sum + i;3️⃣ } """, diagnostics: [ - DiagnosticSpec(locationMarker: "1️⃣", message: "expected 'in' in 'for' statement", fixIts: ["insert 'in'"]), - DiagnosticSpec(locationMarker: "2️⃣", message: "expected '{' in 'for' statement", fixIts: ["insert '{'"]), - DiagnosticSpec(locationMarker: "3️⃣", message: "expected '}' to end 'for' statement", fixIts: ["insert '}'"]), - ] + DiagnosticSpec(message: "expected 'in' in 'for' statement", fixIts: ["insert 'in'"]) + ], + fixedSource: """ + func for_each(r: AsyncRange, iir: AsyncIntRange) async { + var sum = 0 + for await i in r { + } + } + """ ) - } + assertParse( + """ + func for_each(r: AsyncRange, iir: AsyncIntRange) async { + var sum = 0 + for await i in r 1️⃣sum = sum + i;2️⃣ + } + """, + diagnostics: [ + DiagnosticSpec(locationMarker: "1️⃣", message: "expected '{' in 'for' statement", fixIts: ["insert '{'"]), + DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end 'for' statement", fixIts: ["insert '}'"]), + ], + fixedSource: """ + func for_each(r: AsyncRange, iir: AsyncIntRange) async { + var sum = 0 + for await i in r {sum = sum + i; + } + } + """ + ) + } } diff --git a/Tests/SwiftParserTest/translated/ForeachTests.swift b/Tests/SwiftParserTest/translated/ForeachTests.swift index 60171bbce90..5aa1edcd5b6 100644 --- a/Tests/SwiftParserTest/translated/ForeachTests.swift +++ b/Tests/SwiftParserTest/translated/ForeachTests.swift @@ -29,38 +29,83 @@ final class ForeachTests: XCTestCase { } func testForeach2() { + // Simple foreach loop, using the variable in the body assertParse( """ func for_each(r: Range, iir: IntRange) { var sum = 0 - // Simple foreach loop, using the variable in the body for i in r { sum = sum + i } - // Check scoping of variable introduced with foreach loop - i = 0 - // For-each loops with two variables and varying degrees of typedness - for (i, j) in iir { - sum = sum + i + j - } + } + """ + ) + + // Check scoping of variable introduced with foreach loop + // For-each loops with two variables and varying degrees of typedness + assertParse( + """ + func for_each(r: Range, iir: IntRange) { + var sum = 0 for (i, j) in iir { sum = sum + i + j } + } + """ + ) + + assertParse( + """ + func for_each(r: Range, iir: IntRange) { + var sum = 0 for (i, j) : (Int, Int) in iir { sum = sum + i + j } - // Parse errors + } + """ + ) + } + + // Parse errors + func testForeach3() { + assertParse( + """ + func for_each(r: Range, iir: IntRange) { + var sum = 0 for i 1️⃣r { } - for i in r 2️⃣sum = sum + i;3️⃣ } """, diagnostics: [ - DiagnosticSpec(locationMarker: "1️⃣", message: "expected 'in' in 'for' statement", fixIts: ["insert 'in'"]), - DiagnosticSpec(locationMarker: "2️⃣", message: "expected '{' in 'for' statement", fixIts: ["insert '{'"]), - DiagnosticSpec(locationMarker: "3️⃣", message: "expected '}' to end 'for' statement", fixIts: ["insert '}'"]), - ] + DiagnosticSpec(message: "expected 'in' in 'for' statement", fixIts: ["insert 'in'"]) + ], + fixedSource: """ + func for_each(r: Range, iir: IntRange) { + var sum = 0 + for i in r { + } + } + """ ) - } + assertParse( + """ + func for_each(r: Range, iir: IntRange) { + var sum = 0 + for i in r 1️⃣sum = sum + i;2️⃣ + } + """, + diagnostics: [ + DiagnosticSpec(locationMarker: "1️⃣", message: "expected '{' in 'for' statement", fixIts: ["insert '{'"]), + DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end 'for' statement", fixIts: ["insert '}'"]), + ], + fixedSource: """ + func for_each(r: Range, iir: IntRange) { + var sum = 0 + for i in r {sum = sum + i; + } + } + """ + ) + } } diff --git a/Tests/SwiftParserTest/translated/ForwardSlashRegexSkippingAllowedTests.swift b/Tests/SwiftParserTest/translated/ForwardSlashRegexSkippingAllowedTests.swift index 5666ee81cc2..3c18b179e87 100644 --- a/Tests/SwiftParserTest/translated/ForwardSlashRegexSkippingAllowedTests.swift +++ b/Tests/SwiftParserTest/translated/ForwardSlashRegexSkippingAllowedTests.swift @@ -23,7 +23,10 @@ final class ForwardSlashRegexSkippingAllowedTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected pattern in variable", fixIts: ["insert pattern"]) - ] + ], + fixedSource: """ + var <#pattern#>: Int + """ ) } diff --git a/Tests/SwiftParserTest/translated/ForwardSlashRegexSkippingInvalidTests.swift b/Tests/SwiftParserTest/translated/ForwardSlashRegexSkippingInvalidTests.swift index b381ee90204..361f098f823 100644 --- a/Tests/SwiftParserTest/translated/ForwardSlashRegexSkippingInvalidTests.swift +++ b/Tests/SwiftParserTest/translated/ForwardSlashRegexSkippingInvalidTests.swift @@ -65,7 +65,12 @@ final class ForwardSlashRegexSkippingInvalidTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "bare slash regex literal may not start with space"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '/' to end regex literal", fixIts: ["insert '/'"]), - ] + ], + fixedSource: """ + func e() { + _ = / }/ + } + """ ) } @@ -79,7 +84,12 @@ final class ForwardSlashRegexSkippingInvalidTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "bare slash regex literal may not start with space"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '/' to end regex literal", fixIts: ["insert '/'"]), - ] + ], + fixedSource: """ + func f() { + _ = / {/ + } + """ ) } @@ -117,7 +127,12 @@ final class ForwardSlashRegexSkippingInvalidTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + func i() { + _ = /x; "[abc] {" + } + """# ) } @@ -130,7 +145,12 @@ final class ForwardSlashRegexSkippingInvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '/' to end regex literal", fixIts: ["insert '/'"]) - ] + ], + fixedSource: """ + func j() { + _ = /^ [abc] {/ + } + """ ) } @@ -143,7 +163,12 @@ final class ForwardSlashRegexSkippingInvalidTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected '/' to end regex literal", fixIts: ["insert '/'"]) - ] + ], + fixedSource: #""" + func k() { + _ = /^ "[abc] {/ + } + """# ) } @@ -156,7 +181,12 @@ final class ForwardSlashRegexSkippingInvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '/' to end regex literal", fixIts: ["insert '/'"]) - ] + ], + fixedSource: """ + func l() { + _ = /^ } abc {/ + } + """ ) } @@ -172,8 +202,13 @@ final class ForwardSlashRegexSkippingInvalidTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "bare slash regex literal may not start with space"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '/' to end regex literal", fixIts: ["insert '/'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "extraneous brace at top level"), - - ] + ], + fixedSource: #""" + func m() { + _ = / "/ + } + } + """# ) } diff --git a/Tests/SwiftParserTest/translated/ForwardSlashRegexTests.swift b/Tests/SwiftParserTest/translated/ForwardSlashRegexTests.swift index 71b1740499a..37e41e03feb 100644 --- a/Tests/SwiftParserTest/translated/ForwardSlashRegexTests.swift +++ b/Tests/SwiftParserTest/translated/ForwardSlashRegexTests.swift @@ -206,7 +206,10 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '/' to end regex literal", fixIts: ["insert '/'"]) - ] + ], + fixedSource: """ + _ = /^)/ + """ ) } @@ -289,7 +292,12 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + do { + _ = 0; /x / <#expression#> + } + """ ) } @@ -304,7 +312,13 @@ final class ForwardSlashRegexTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]), DiagnosticSpec(message: "unexpected code '? 0 : 1' in 'do' statement"), - ] + ], + fixedSource: """ + _ = /x/ ? 0 : 1 + do { + _ = /x / <#expression#>? 0 : 1 + } + """ ) } @@ -327,7 +341,13 @@ final class ForwardSlashRegexTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]), DiagnosticSpec(message: "unexpected code '?? /x /' in 'do' statement"), - ] + ], + fixedSource: """ + _ = /x/ ?? /x/ + do { + _ = /x / <#expression#>?? /x / + } + """ ) } @@ -393,7 +413,12 @@ final class ForwardSlashRegexTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected expression in operator", fixIts: ["insert expression"]), DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '...' in 'do' statement"), - ] + ], + fixedSource: """ + do { + _ = /x; /<#expression#>... + } + """ ) } @@ -406,7 +431,12 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + do { + _ = true / false / <#expression#>; + } + """ ) } @@ -441,7 +471,10 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + foo(/abc/, y: /abc / <#expression#>) + """ ) } @@ -471,7 +504,14 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + func testSubscript(_ x: S) { + x[/x/] + x[/x / <#expression#>] + _ = x[/] / 2 + } + """ ) } @@ -487,7 +527,15 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + func testReturn() -> Regex { + if .random() { + return /x/ + } + return /x / <#expression#> + } + """ ) } @@ -510,7 +558,12 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + do { + _ = [/abc/, /abc / <#expression#>] + } + """ ) } @@ -524,7 +577,12 @@ final class ForwardSlashRegexTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression after operator", fixIts: ["insert expression"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected expression after operator", fixIts: ["insert expression"]), - ] + ], + fixedSource: """ + do { + _ = [/abc / <#expression#>: /abc / <#expression#>] + } + """ ) } @@ -597,7 +655,12 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + do { + _ = ((/abc / <#expression#>)) + } + """ ) } @@ -750,7 +813,10 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected name in member access", fixIts: ["insert name"]) - ] + ], + fixedSource: """ + _ = 0.<#identifier#> / 1 / 2 + """ ) } @@ -761,7 +827,10 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected name in member access", fixIts: ["insert name"]) - ] + ], + fixedSource: """ + _ = 0 .<#identifier#> / 1 / 2 + """ ) } @@ -864,7 +933,12 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected pattern in variable", fixIts: ["insert pattern"]) - ] + ], + fixedSource: """ + do { + let <#pattern#>/x/ + } + """ ) } @@ -877,7 +951,12 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + do { + _ = try /x/; _ = try /x / <#expression#> + } + """ ) } @@ -890,7 +969,12 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + do { + _ = try? /x/; _ = try? /x / <#expression#> + } + """ ) } @@ -903,7 +987,12 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after operator", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + do { + _ = try! /x/; _ = try! /x / <#expression#> + } + """ ) } @@ -1067,7 +1156,14 @@ final class ForwardSlashRegexTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected ')' to end function call", fixIts: ["insert ')'"]) - ] + ], + fixedSource: #""" + _ = qux(/, 1) / 2 + do { + _ = qux(/, "(") / 2 + _ = qux(/, "(")/)2 + } + """# ) } @@ -1224,7 +1320,10 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '/' to end regex literal", fixIts: ["insert '/'"]) - ] + ], + fixedSource: """ + _ = // + """ ) } @@ -1235,7 +1334,10 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '/' to end regex literal", fixIts: ["insert '/'"]) - ] + ], + fixedSource: """ + _ = /)/ + """ ) } @@ -1273,7 +1375,12 @@ final class ForwardSlashRegexTests: XCTestCase { ], fixIts: ["insert ')'"] ) - ] + ], + fixedSource: #""" + do { + let _: Regex = (/whatever\)/) + } + """# ) } @@ -1313,7 +1420,12 @@ final class ForwardSlashRegexTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected root in key path", fixIts: ["insert root"]), DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '])/' in 'do' statement"), - ] + ], + fixedSource: #""" + do { + _ = /[\<#type#>]])/ + } + """# ) } @@ -1349,7 +1461,10 @@ final class ForwardSlashRegexTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + _ = ^/"/; "" + """# ) } @@ -1361,7 +1476,10 @@ final class ForwardSlashRegexTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + _ = ^/"[/; "" + """# ) } @@ -1453,7 +1571,10 @@ final class ForwardSlashRegexTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "bare slash regex literal may not start with space"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '/' to end regex literal", fixIts: ["insert '/'"]), - ] + ], + fixedSource: """ + _ = / / + """ ) } @@ -1465,7 +1586,10 @@ final class ForwardSlashRegexTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '/' to end regex literal", fixIts: ["insert '/'"]) - ] + ], + fixedSource: """ + _ = /^ / + """ ) } diff --git a/Tests/SwiftParserTest/translated/GuardTests.swift b/Tests/SwiftParserTest/translated/GuardTests.swift index 598c779bcfc..2164e4941c5 100644 --- a/Tests/SwiftParserTest/translated/GuardTests.swift +++ b/Tests/SwiftParserTest/translated/GuardTests.swift @@ -24,7 +24,13 @@ final class GuardTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected 'else' and body in 'guard' statement", fixIts: ["insert 'else' and body"]) - ] + ], + fixedSource: """ + func noConditionNoElse() { + guard {} else { + } + } + """ ) } @@ -37,7 +43,12 @@ final class GuardTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected condition in 'guard' statement", fixIts: ["insert condition"]) - ] + ], + fixedSource: """ + func noCondition() { + guard <#expression#> else {} + } + """ ) } } diff --git a/Tests/SwiftParserTest/translated/IdentifiersTests.swift b/Tests/SwiftParserTest/translated/IdentifiersTests.swift index b491dbc01db..e369a6ed213 100644 --- a/Tests/SwiftParserTest/translated/IdentifiersTests.swift +++ b/Tests/SwiftParserTest/translated/IdentifiersTests.swift @@ -114,7 +114,10 @@ final class IdentifiersTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "keyword 'Self' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + struct `Self` {} + """ ) } @@ -133,7 +136,10 @@ final class IdentifiersTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "keyword 'Any' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + struct `Any` {} + """ ) } @@ -144,7 +150,10 @@ final class IdentifiersTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "keyword 'enum' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + protocol `enum` {} + """ ) } @@ -159,7 +168,13 @@ final class IdentifiersTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "keyword 'public' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]), DiagnosticSpec(locationMarker: "2️⃣", message: "'_' cannot be used as an identifier here"), - ] + ], + fixedSource: """ + protocol test { + associatedtype `public` + } + func _(_ x: Int) {} + """ ) } diff --git a/Tests/SwiftParserTest/translated/IfconfigExprTests.swift b/Tests/SwiftParserTest/translated/IfconfigExprTests.swift index ae33c113f4b..16861f6fb07 100644 --- a/Tests/SwiftParserTest/translated/IfconfigExprTests.swift +++ b/Tests/SwiftParserTest/translated/IfconfigExprTests.swift @@ -331,7 +331,12 @@ final class IfconfigExprTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected value in function call", fixIts: ["insert value"]) - ] + ], + fixedSource: """ + #if canImport(A, <#expression#>) + let a = 1 + #endif + """ ) } @@ -370,7 +375,12 @@ final class IfconfigExprTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected value in function call", fixIts: ["insert value"]) - ] + ], + fixedSource: """ + #if canImport(A, _version: <#expression#>) + let a = 1 + #endif + """ ) } diff --git a/Tests/SwiftParserTest/translated/ImplicitGetterIncompleteTests.swift b/Tests/SwiftParserTest/translated/ImplicitGetterIncompleteTests.swift index 3d09f025b6d..7fc0f31b991 100644 --- a/Tests/SwiftParserTest/translated/ImplicitGetterIncompleteTests.swift +++ b/Tests/SwiftParserTest/translated/ImplicitGetterIncompleteTests.swift @@ -43,8 +43,16 @@ final class ImplicitGetterIncompleteTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected '}' to end variable", fixIts: ["insert '}'"]), DiagnosticSpec(message: "expected '}' to end function", fixIts: ["insert '}'"]), - ] + ], + fixedSource: #""" + // Would trigger assertion when AST verifier checks source ranges ("child source range not contained within its parent") + func test2() { + var a : Int { + switch i { + } + } + } + """# ) } - } diff --git a/Tests/SwiftParserTest/translated/InitDeinitTests.swift b/Tests/SwiftParserTest/translated/InitDeinitTests.swift index ac213675820..3638980ee02 100644 --- a/Tests/SwiftParserTest/translated/InitDeinitTests.swift +++ b/Tests/SwiftParserTest/translated/InitDeinitTests.swift @@ -26,7 +26,12 @@ final class InitDeinitTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]) - ] + ], + fixedSource: """ + struct FooStructConstructorA { + init() + } + """ ) } @@ -49,7 +54,12 @@ final class InitDeinitTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]) - ] + ], + fixedSource: """ + struct FooStructConstructorC { + init() {} + } + """ ) } @@ -62,7 +72,12 @@ final class InitDeinitTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]) - ] + ], + fixedSource: """ + struct FooStructConstructorC { + init() {} + } + """ ) } @@ -75,7 +90,12 @@ final class InitDeinitTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]) - ] + ], + fixedSource: """ + struct FooStructConstructorC { + init?() { self.init() } + } + """ ) } @@ -215,7 +235,12 @@ final class InitDeinitTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected parameter clause in function signature", fixIts: ["insert parameter clause"]) - ] + ], + fixedSource: """ + init() {} + init() + init() {} + """ ) } diff --git a/Tests/SwiftParserTest/translated/InvalidTests.swift b/Tests/SwiftParserTest/translated/InvalidTests.swift index 4dc17123de2..4ada6972a96 100644 --- a/Tests/SwiftParserTest/translated/InvalidTests.swift +++ b/Tests/SwiftParserTest/translated/InvalidTests.swift @@ -35,7 +35,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'inout' before a parameter name is not allowed", fixIts: ["move 'inout' in front of type"]) - ] + ], + fixedSource: """ + func test2(let x : inout Int) {} + """ ) } @@ -58,7 +61,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'__shared' before a parameter name is not allowed", fixIts: ["move '__shared' in front of type"]) - ] + ], + fixedSource: """ + func test1s(var x : __shared Int) {} + """ ) } @@ -69,7 +75,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'__shared' before a parameter name is not allowed", fixIts: ["move '__shared' in front of type"]) - ] + ], + fixedSource: """ + func test2s(let x : __shared Int) {} + """ ) } @@ -80,7 +89,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'__owned' before a parameter name is not allowed", fixIts: ["move '__owned' in front of type"]) - ] + ], + fixedSource: """ + func test1o(var x : __owned Int) {} + """ ) } @@ -91,7 +103,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'__owned' before a parameter name is not allowed", fixIts: ["move '__owned' in front of type"]) - ] + ], + fixedSource: """ + func test2o(let x : __owned Int) {} + """ ) } @@ -104,7 +119,12 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected value and ')' to end function call", fixIts: ["insert value and ')'"]) - ] + ], + fixedSource: """ + func test3() { + undeclared_func(<#expression#>) + } + """ ) } @@ -117,9 +137,9 @@ final class InvalidTests: XCTestCase { } func testInvalid6() { + // rdar://16601779 assertParse( """ - // rdar://16601779 func foo() { runAction(SKAction.sequence()1️⃣ skview! @@ -127,7 +147,13 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected ')' to end function call", fixIts: ["insert ')'"]) - ] + ], + fixedSource: """ + func foo() { + runAction(SKAction.sequence()) + skview! + } + """ ) } @@ -150,7 +176,15 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "all statements inside a switch must be covered by a 'case' or 'default' label", fixIts: ["insert label"]) - ] + ], + fixedSource: """ + switch state { + case <#identifier#>: + let duration : Int = 0 + case 1: + break + } + """ ) } @@ -176,14 +210,32 @@ final class InvalidTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "all statements inside a switch must be covered by a 'case' or 'default' label", fixIts: ["insert label"]), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), - ] + ], + fixedSource: #""" + func testNotCoveredCase(x: Int) { + switch x { + case <#identifier#>: + let y = "foo" + switch y { + case "bar": + blah; blah // ignored + } + case "baz": + break + case 1: + break + default: + break + } + } + """# ) } func testInvalid10() { + // rdar://18926814 assertParse( ##""" - // rdar://18926814 func test4() { let abc = 123 _ = " >> \( abc 1️⃣} ) << "2️⃣ @@ -191,7 +243,13 @@ final class InvalidTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected brace in string literal"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end function", fixIts: ["insert '}'"]), - ] + ], + fixedSource: ##""" + func test4() { + let abc = 123 + _ = " >> \( abc } ) << " + } + """## ) } @@ -207,14 +265,17 @@ final class InvalidTests: XCTestCase { DiagnosticSpec(locationMarker: "3️⃣", message: "expected return type in function type", fixIts: ["insert return type"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected ')' to end parameter clause", fixIts: ["insert ')'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected code '() -> T)' in function"), - ] + ], + fixedSource: """ + func d(_ b: (String) -> <#type#>) () -> T) {} + """ ) } func testInvalid12() { + // QoI: terrible diagnostic when trying to form a generic protocol assertParse( """ - // QoI: terrible diagnostic when trying to form a generic protocol protocol Animal { func feed(_ food: Food) } @@ -223,10 +284,10 @@ final class InvalidTests: XCTestCase { } func testInvalid13() { + // https://github.com/apple/swift/issues/43190 + // Crash with invalid parameter declaration assertParse( """ - // https://github.com/apple/swift/issues/43190 - // Crash with invalid parameter declaration do { class Starfish {} struct Salmon {} @@ -237,14 +298,23 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected ':' and type in parameter", fixIts: ["insert ':' and type"]) - ] + ], + fixedSource: """ + do { + class Starfish {} + struct Salmon {} + func f(s Starfish: <#type#>, + _ ss: Salmon) -> [Int] {} + func g() { f(Starfish(), Salmon()) } + } + """ ) } func testInvalid14() { + // https://github.com/apple/swift/issues/43313 assertParse( """ - // https://github.com/apple/swift/issues/43313 do { func f(_ a: Int, b: Int) {} f(1, b: 2,1️⃣) @@ -252,20 +322,19 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected value in function call", fixIts: ["insert value"]) - ] - ) - } - - func testInvalid15() { - assertParse( - """ - // https://github.com/apple/swift/issues/43591 - // Two inout crash compiler - """ + ], + fixedSource: """ + do { + func f(_ a: Int, b: Int) {} + f(1, b: 2, <#expression#>) + } + """ ) } func testInvalid16a() { + // https://github.com/apple/swift/issues/43591 + // Two inout crash compiler assertParse( """ func f1_43591(a : inout 1️⃣inout Int) {} @@ -306,7 +375,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'inout' before a parameter name is not allowed", fixIts: ["remove redundant 'inout'"]) - ] + ], + fixedSource: """ + func f4_43591(x: inout String) {} + """ ) } @@ -317,7 +389,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'inout' before a parameter name is not allowed", fixIts: ["remove redundant 'inout'"]) - ] + ], + fixedSource: """ + func f5_43591(i: inout Int) {} + """ ) } @@ -328,7 +403,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "keyword 'repeat' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + func `repeat`() {} + """ ) } @@ -339,7 +417,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "keyword 'for' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + let `for` = 2 + """ ) } @@ -350,7 +431,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'inout' before a parameter name is not allowed", fixIts: ["remove redundant 'inout'"]) - ] + ], + fixedSource: """ + func f4_43591(x: inout String) {} + """ ) } @@ -373,7 +457,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "keyword 'repeat' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + func `repeat`() {} + """ ) } @@ -384,7 +471,10 @@ final class InvalidTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "keyword 'for' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + let `for` = 2 + """ ) } @@ -498,7 +588,11 @@ final class InvalidTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "expected ':' and type in parameter", fixIts: ["insert ':' and type"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected ')' to end parameter clause", fixIts: ["insert ')'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '(x: T)' in function"), - ] + ], + fixedSource: """ + func hammer( + leavings: <#type#>) (x: T) {} + """ ) } diff --git a/Tests/SwiftParserTest/translated/MultilineErrorsTests.swift b/Tests/SwiftParserTest/translated/MultilineErrorsTests.swift index 951dd3d0f24..412ce3d397d 100644 --- a/Tests/SwiftParserTest/translated/MultilineErrorsTests.swift +++ b/Tests/SwiftParserTest/translated/MultilineErrorsTests.swift @@ -50,13 +50,7 @@ final class MultilineErrorsTests: XCTestCase { ) } - func testMultilineErrors2() { - assertParseWithAllNewlineEndings( - """ - // ===---------- Multiline --------=== - """ - ) - } + // MARK: - Multiline func testMultilineErrors3() { // expecting at least 4 columns of leading indentation @@ -261,7 +255,13 @@ final class MultilineErrorsTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "unexpected space in indentation of line in multi-line string literal", fixIts: ["change indentation of this line to match closing delimiter"]) - ] + ], + fixedSource: #""" + _ = """ + Fourteen 2 + Pi 2 + """ + """# ) } @@ -453,7 +453,13 @@ final class MultilineErrorsTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected ')' in string literal", fixIts: [#"insert ')'"#]), DiagnosticSpec(locationMarker: "1️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(locationMarker: "2️⃣", message: #"extraneous code ')!"' at top level"#), - ] + ], + fixedSource: ##""" + _ = "hello\(""" + world + """)" + )!" + """## ) } @@ -469,7 +475,13 @@ final class MultilineErrorsTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected value and ')' in string literal", fixIts: ["insert value and ')'"]), DiagnosticSpec(locationMarker: "1️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(locationMarker: "2️⃣", message: #"extraneous code ')!"' at top level"#), - ] + ], + fixedSource: ##""" + _ = "h\(<#expression#>)" + """ + world + """)!" + """## ) } @@ -588,7 +600,11 @@ final class MultilineErrorsTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "invalid escape sequence in literal"), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"""' to end string literal"#, fixIts: [#"insert '"""'"#]), - ] + ], + fixedSource: ##""" + _ = """ + foo\""" + """## ) } @@ -667,7 +683,15 @@ final class MultilineErrorsTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(locationMarker: "2️⃣", message: #"unexpected code 'baz' in string literal"#), DiagnosticSpec(locationMarker: "3️⃣", message: #"expected ')' in string literal"#, notes: [NoteSpec(message: "to match this opening '('")], fixIts: ["insert ')'"]), - ] + ], + fixedSource: ##""" + let _ = """ + foo + \("bar" + baz) + """ + abc + """## ) } @@ -767,7 +791,12 @@ final class MultilineErrorsTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "multi-line string literal content must begin on a new line", fixIts: ["insert newline"]) - ] + ], + fixedSource: #""" + """ + \#(" ") + """ + """# ) } } diff --git a/Tests/SwiftParserTest/translated/MultilinePoundDiagnosticArgRdar41154797Tests.swift b/Tests/SwiftParserTest/translated/MultilinePoundDiagnosticArgRdar41154797Tests.swift index 26e33c8df88..87ddcaf84a5 100644 --- a/Tests/SwiftParserTest/translated/MultilinePoundDiagnosticArgRdar41154797Tests.swift +++ b/Tests/SwiftParserTest/translated/MultilinePoundDiagnosticArgRdar41154797Tests.swift @@ -23,7 +23,10 @@ final class MultilinePoundDiagnosticArgRdar41154797Tests: XCTestCase { diagnostics: [ DiagnosticSpec(message: #"expected '"""' to end string literal"#, fixIts: [#"insert '"""'"#]), DiagnosticSpec(message: "expected ')' to end macro expansion", fixIts: ["insert ')'"]), - ] + ], + fixedSource: ##""" + #error("""""") + """## ) } diff --git a/Tests/SwiftParserTest/translated/ObjectLiteralsTests.swift b/Tests/SwiftParserTest/translated/ObjectLiteralsTests.swift index 2f7e132db54..72dc952b6c3 100644 --- a/Tests/SwiftParserTest/translated/ObjectLiteralsTests.swift +++ b/Tests/SwiftParserTest/translated/ObjectLiteralsTests.swift @@ -22,7 +22,10 @@ final class ObjectLiteralsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + let _ = [#Color(colorLiteralRed: red, green: green, blue: blue, alpha: alpha)#<#identifier#>] + """ ) } @@ -33,7 +36,10 @@ final class ObjectLiteralsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + let _ = [#Image(imageLiteral: localResourceNameAsString)#<#identifier#>] + """ ) } @@ -44,7 +50,10 @@ final class ObjectLiteralsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + let _ = [#FileReference(fileReferenceLiteral: localResourceNameAsString)#<#identifier#>] + """ ) } @@ -104,7 +113,10 @@ final class ObjectLiteralsTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]), - ] + ], + fixedSource: """ + let _ = [#<#identifier#> #<#identifier#>] + """ ) } @@ -115,7 +127,10 @@ final class ObjectLiteralsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "2️⃣", message: "expected ']' to end array", fixIts: ["insert ']'"]) - ] + ], + fixedSource: """ + let _ = [#Color(_: 1, green: 1, 2)] + """ ) } @@ -127,7 +142,10 @@ final class ObjectLiteralsTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected ']' to end array", fixIts: ["insert ']'"]), - ] + ], + fixedSource: """ + let _ = [#Color(red: 1, green: 1, blue: 1)#<#identifier#>] + """ ) } @@ -138,7 +156,10 @@ final class ObjectLiteralsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + let _ = [#Color(withRed: 1, green: 1, whatever: 2)#<#identifier#>] + """ ) } diff --git a/Tests/SwiftParserTest/translated/OperatorDeclTests.swift b/Tests/SwiftParserTest/translated/OperatorDeclTests.swift index 35527ff1e2c..80b73422f34 100644 --- a/Tests/SwiftParserTest/translated/OperatorDeclTests.swift +++ b/Tests/SwiftParserTest/translated/OperatorDeclTests.swift @@ -34,7 +34,10 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "operator should not be declared with body", fixIts: ["remove operator body"]) - ] + ], + fixedSource: """ + postfix operator +++ + """ ) } @@ -45,7 +48,10 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "operator should not be declared with body", fixIts: ["remove operator body"]) - ] + ], + fixedSource: """ + infix operator +++ + """ ) } @@ -72,7 +78,10 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "operator should not be declared with body", fixIts: ["remove operator body"]) - ] + ], + fixedSource: """ + infix operator +++*+ : A + """ ) } @@ -83,7 +92,10 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "operator should not be declared with body", fixIts: ["remove operator body"]) - ] + ], + fixedSource: """ + prefix operator +++** : A + """ ) } @@ -102,7 +114,10 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "operator should not be declared with body", fixIts: ["remove operator body"]) - ] + ], + fixedSource: """ + postfix operator ++*+* : A + """ ) } @@ -133,7 +148,10 @@ final class OperatorDeclTests: XCTestCase { diagnostics: [ // TODO: Old parser expected error on line 1: operator must be declared as 'prefix', 'postfix', or 'infix' DiagnosticSpec(message: "operator should not be declared with body", fixIts: ["remove operator body"]) - ] + ], + fixedSource: """ + operator +*+++ + """ ) } @@ -145,7 +163,10 @@ final class OperatorDeclTests: XCTestCase { diagnostics: [ // TODO: Old parser expected error on line 1: operator must be declared as 'prefix', 'postfix', or 'infix' DiagnosticSpec(message: "operator should not be declared with body", fixIts: ["remove operator body"]) - ] + ], + fixedSource: """ + operator +*++* : A + """ ) } @@ -156,7 +177,10 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected binary operator in operator declaration", fixIts: ["insert binary operator"]) - ] + ], + fixedSource: """ + prefix operator <#binary operator#> + """ ) } @@ -259,7 +283,10 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'@aa' is not allowed in operator names", fixIts: ["remove '@aa'"]) - ] + ], + fixedSource: """ + infix operator !! + """ ) } @@ -282,7 +309,10 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'#' is not allowed in operator names", fixIts: ["remove '#'"]) - ] + ], + fixedSource: """ + infix operator ++= + """ ) } @@ -293,20 +323,26 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'#' is not allowed in operator names", fixIts: ["remove '#'"]) - ] + ], + fixedSource: """ + infix operator -> + """ ) } func testOperatorDecl13() { + // FIXME: Ideally, we shouldn't emit the «consistent whitespace» diagnostic + // where = cannot possibly mean an assignment. assertParse( """ - // FIXME: Ideally, we shouldn't emit the «consistent whitespace» diagnostic - // where = cannot possibly mean an assignment. infix operator =1️⃣#= """, diagnostics: [ DiagnosticSpec(message: "'#=' is not allowed in operator names", fixIts: ["remove '#='"]) - ] + ], + fixedSource: """ + infix operator = + """ ) } @@ -319,7 +355,12 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected precedence group in operator declaration", fixIts: ["insert precedence group"]) - ] + ], + fixedSource: """ + infix operator +++= + infix operator *** : A + infix operator --- : <#identifier#>; + """ ) } @@ -332,7 +373,12 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected identifier in precedencegroup", fixIts: ["insert identifier"]) - ] + ], + fixedSource: """ + precedencegroup <#identifier#> { + associativity: right + } + """ ) } @@ -345,7 +391,12 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected ':' in 'associativity' property of precedencegroup", fixIts: ["insert ':'"]) - ] + ], + fixedSource: """ + precedencegroup A { + associativity: right + } + """ ) } @@ -397,7 +448,12 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected name in 'relation' property of precedencegroup", fixIts: ["insert name"]) - ] + ], + fixedSource: """ + precedencegroup E { + higherThan: <#identifier#> + } + """ ) } @@ -476,7 +532,10 @@ final class OperatorDeclTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected precedence group in operator declaration", fixIts: ["insert precedence group"]) - ] + ], + fixedSource: """ + postfix operator ++: <#identifier#> + """ ) } diff --git a/Tests/SwiftParserTest/translated/OperatorsTests.swift b/Tests/SwiftParserTest/translated/OperatorsTests.swift index 6684266e9a5..4a7a8f62ab2 100644 --- a/Tests/SwiftParserTest/translated/OperatorsTests.swift +++ b/Tests/SwiftParserTest/translated/OperatorsTests.swift @@ -338,7 +338,10 @@ final class OperatorsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]) - ] + ], + fixedSource: """ + foo!!; foo + """ ) } @@ -349,8 +352,10 @@ final class OperatorsTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]) - ] + ], + fixedSource: """ + foo??; bar + """ ) } - } diff --git a/Tests/SwiftParserTest/translated/OriginalDefinedInAttrTests.swift b/Tests/SwiftParserTest/translated/OriginalDefinedInAttrTests.swift index 226a8527a5d..aa7b41489fd 100644 --- a/Tests/SwiftParserTest/translated/OriginalDefinedInAttrTests.swift +++ b/Tests/SwiftParserTest/translated/OriginalDefinedInAttrTests.swift @@ -60,10 +60,15 @@ final class OriginalDefinedInAttrTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec( + locationMarker: "1️⃣", message: "expected ',' and version list in @_originallyDefinedIn arguments", fixIts: ["insert ',' and version list"] ) - ] + ], + fixedSource: #""" + @_originallyDefinedIn(module: "foo", <#identifier#>) + public class ToplevelClass1 {} + """# ) } @@ -116,7 +121,11 @@ final class OriginalDefinedInAttrTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected version restriction in version", fixIts: ["insert version restriction"]), DiagnosticSpec(message: "expected ')' to end attribute", fixIts: ["insert ')'"]), - ] + ], + fixedSource: #""" + @_originallyDefinedIn(module: "foo", <#identifier#>) + public class ToplevelClass3 {} + """# ) } diff --git a/Tests/SwiftParserTest/translated/PoundAssertTests.swift b/Tests/SwiftParserTest/translated/PoundAssertTests.swift index 5eaa82ea99f..7bc6d95899c 100644 --- a/Tests/SwiftParserTest/translated/PoundAssertTests.swift +++ b/Tests/SwiftParserTest/translated/PoundAssertTests.swift @@ -39,7 +39,10 @@ final class PoundAssertTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: #"extraneous code ', "error message")' at top level"#), - ] + ], + fixedSource: #""" + #assert; true, "error message") + """# ) } @@ -50,7 +53,10 @@ final class PoundAssertTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected value in macro expansion", fixIts: ["insert value"]) - ] + ], + fixedSource: #""" + #assert(<#expression#>, "error message") + """# ) } @@ -69,7 +75,12 @@ final class PoundAssertTests: XCTestCase { ], fixIts: ["insert ')'"] ) - ] + ], + fixedSource: """ + func unbalanced1() { + #assert(true) + } + """ ) } @@ -88,7 +99,12 @@ final class PoundAssertTests: XCTestCase { ], fixIts: ["insert ')'"] ) - ] + ], + fixedSource: #""" + func unbalanced2() { + #assert(true, "hello world") + } + """# ) } } diff --git a/Tests/SwiftParserTest/translated/RawStringErrorsTests.swift b/Tests/SwiftParserTest/translated/RawStringErrorsTests.swift index ce06deb436e..78f89575322 100644 --- a/Tests/SwiftParserTest/translated/RawStringErrorsTests.swift +++ b/Tests/SwiftParserTest/translated/RawStringErrorsTests.swift @@ -22,7 +22,10 @@ final class RawStringErrorsTests: XCTestCase { """###, diagnostics: [ DiagnosticSpec(message: "too many '#' characters in closing delimiter", fixIts: ["remove extraneous delimiters"]) - ] + ], + fixedSource: ###""" + let _ = "foo\(#"bar"#)baz" + """### ) } @@ -61,7 +64,10 @@ final class RawStringErrorsTests: XCTestCase { """#####, diagnostics: [ DiagnosticSpec(message: #####"expected '"####' to end string literal"#####, fixIts: [#####"insert '"####'"#####]) - ] + ], + fixedSource: #####""" + let _ = ####"invalid"###"#### + """##### ) } @@ -72,7 +78,10 @@ final class RawStringErrorsTests: XCTestCase { """#####, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "too many '#' characters in closing delimiter", fixIts: ["remove extraneous delimiters"]) - ] + ], + fixedSource: #####""" + let _ = ###"invalid"### + """##### ) } diff --git a/Tests/SwiftParserTest/translated/RecoveryTests.swift b/Tests/SwiftParserTest/translated/RecoveryTests.swift index c01e24282da..2299c584726 100644 --- a/Tests/SwiftParserTest/translated/RecoveryTests.swift +++ b/Tests/SwiftParserTest/translated/RecoveryTests.swift @@ -3,30 +3,6 @@ import XCTest final class RecoveryTests: XCTestCase { - func testRecovery1() { - assertParse( - """ - //===--- Helper types used in this file. - """ - ) - } - - func testRecovery2() { - assertParse( - """ - protocol FooProtocol {} - """ - ) - } - - func testRecovery3() { - assertParse( - """ - //===--- Tests. - """ - ) - } - func testRecovery4() { assertParse( #""" @@ -82,7 +58,14 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected code 'this greater: >' in subscript"), DiagnosticSpec(locationMarker: "4️⃣", message: "expected expression after operator", fixIts: ["insert expression"]), DiagnosticSpec(locationMarker: "4️⃣", message: "unexpected code in function"), - ] + ], + fixedSource: """ + func useContainer() -> () { + var a : Containera; type [skip this greater: >] > <#expression#>, b : Int + b = 5 // no-warning + a.exists() + } + """ ) } @@ -119,7 +102,15 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected brace before function"), DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), - ] + ], + fixedSource: """ + // Here is an extra random close-brace! + } + //===--- Recovery for braced blocks. + func braceStmt1() { + { braceStmt1(); }; a + } + """ ) } @@ -145,10 +136,11 @@ final class RecoveryTests: XCTestCase { ) } + // MARK: - Recovery for misplaced 'static' + func testRecovery13() { assertParse( """ - //===--- Recovery for misplaced 'static'. static func toplevelStaticFunc() {} static struct StaticStruct {} static class StaticClass {} @@ -164,11 +156,15 @@ final class RecoveryTests: XCTestCase { func testRecovery13b() { assertParse( """ - if1️⃣ + if1️⃣ """, diagnostics: [ DiagnosticSpec(message: "expected expression and body in 'if' statement", fixIts: ["insert expression and body"]) - ] + ], + fixedSource: """ + if <#expression#> { + } + """ ) } @@ -241,10 +237,10 @@ final class RecoveryTests: XCTestCase { } func testRecovery19() { + // assertParse( """ - // - if 1️⃣{ { } } + if 1️⃣{ { } } """, diagnostics: [ DiagnosticSpec(message: "missing condition in 'if' statement") @@ -261,7 +257,11 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression and code block in 'while' statement", fixIts: ["insert expression and code block"]) - ] + ], + fixedSource: """ + while <#expression#> { + } + """ ) } @@ -291,10 +291,10 @@ final class RecoveryTests: XCTestCase { } func testRecovery23() { + // It is debatable if we should do recovery here and parse { true } as the + // body, but the error message should be sensible. assertParse( """ - // It is debatable if we should do recovery here and parse { true } as the - // body, but the error message should be sensible. while 1️⃣{ true } { } """, @@ -321,9 +321,9 @@ final class RecoveryTests: XCTestCase { } func testRecovery25() { + // assertParse( """ - // while 1️⃣{ { } } """, diagnostics: [ @@ -342,7 +342,11 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected condition in 'repeat' statement", fixIts: ["insert condition"]) - ] + ], + fixedSource: """ + repeat { + } while <#expression#> + """ ) } @@ -379,7 +383,11 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected 'while' and condition in 'repeat' statement", fixIts: ["insert 'while' and condition"]) - ] + ], + fixedSource: """ + repeat { + } while <#expression#> + """ ) } @@ -392,7 +400,11 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected pattern, 'in', and expression in 'for' statement", fixIts: ["insert pattern, 'in', and expression"]), DiagnosticSpec(message: "unexpected ';' separator", fixIts: ["remove ';'"]), - ] + ], + fixedSource: """ + for <#pattern#> in <#expression#> { + } + """ ) } @@ -406,7 +418,12 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected pattern, 'in', and expression in 'for' statement", fixIts: ["insert pattern, 'in', and expression"]), DiagnosticSpec(message: "unexpected ';' separator", fixIts: ["remove ';'"]), - ] + ], + fixedSource: """ + for <#pattern#> in <#expression#> + { + } + """ ) } @@ -419,7 +436,11 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected pattern, 'in', and expression in 'for' statement", fixIts: ["insert pattern, 'in', and expression"]), DiagnosticSpec(message: "unexpected code '; true' in 'for' statement"), - ] + ], + fixedSource: """ + for <#pattern#> in <#expression#> ; true { + } + """ ) } @@ -433,7 +454,12 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected 'in' and expression in 'for' statement", fixIts: ["insert 'in' and expression"]), DiagnosticSpec(message: "unexpected code '= 0; true' in 'for' statement"), - ] + ], + fixedSource: """ + for var i in <#expression#> = 0; true { + i += 1 + } + """ ) } @@ -444,7 +470,11 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected pattern, 'in', expression, and body in 'for' statement", fixIts: ["insert pattern, 'in', expression, and body"]) - ] + ], + fixedSource: """ + for <#pattern#> in <#expression#> { + } + """ ) } @@ -456,7 +486,11 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected pattern, 'in', and expression in 'for' statement", fixIts: ["insert pattern, 'in', and expression"]) - ] + ], + fixedSource: """ + for <#pattern#> in <#expression#> { + } + """ ) } @@ -469,7 +503,12 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected pattern, 'in', and expression in 'for' statement", fixIts: ["insert pattern, 'in', and expression"]) - ] + ], + fixedSource: """ + for <#pattern#> in <#expression#> + { + } + """ ) } @@ -481,7 +520,11 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected 'in' and expression in 'for' statement", fixIts: ["insert 'in' and expression"]) - ] + ], + fixedSource: """ + for i in <#expression#> { + } + """ ) } @@ -493,7 +536,11 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected 'in' and expression in 'for' statement", fixIts: ["insert 'in' and expression"]) - ] + ], + fixedSource: """ + for var i in <#expression#> { + } + """ ) } @@ -506,7 +553,11 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "keyword 'in' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected 'in' and expression in 'for' statement", fixIts: ["insert 'in' and expression"]), - ] + ], + fixedSource: """ + for `in` in <#expression#> { + } + """ ) } @@ -518,7 +569,11 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected pattern and 'in' in 'for' statement", fixIts: ["insert pattern and 'in'"]) - ] + ], + fixedSource: """ + for <#pattern#> in 0..<12 { + } + """ ) } @@ -531,7 +586,11 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "keyword 'for' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected Sequence expression for for-each loop"), - ] + ], + fixedSource: """ + for `for` in { + } + """ ) } @@ -547,18 +606,12 @@ final class RecoveryTests: XCTestCase { ) } - func testRecovery43() { - assertParse( - """ - // https://github.com/apple/swift/issues/48502 - struct User { let name: String? } - """ - ) - } - func testRecovery44() { + // https://github.com/apple/swift/issues/48502 assertParse( #""" + struct User { let name: String? } + let users = [User]() for user in users 1️⃣whe { if let name = user.name { @@ -583,7 +636,11 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected pattern, 'in', and expression in 'for' statement", fixIts: ["insert pattern, 'in', and expression"]), DiagnosticSpec(locationMarker: "1️⃣", message: "expected '{' in 'for' statement", fixIts: ["insert '{'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "standalone ';' statements are not allowed", fixIts: ["remove ';'"]), - ] + ], + fixedSource: """ + for <#pattern#> in <#expression#> { + } + """ ) } @@ -594,7 +651,11 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression and '{}' to end 'switch' statement", fixIts: ["insert expression and '{}'"]) - ] + ], + fixedSource: """ + switch <#expression#> { + } + """ ) } @@ -606,7 +667,11 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + switch <#expression#> { + } + """ ) } @@ -619,7 +684,12 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + switch <#expression#> + { + } + """ ) } @@ -662,7 +732,13 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression in 'switch' statement"), DiagnosticSpec(locationMarker: "2️⃣", message: "all statements inside a switch must be covered by a 'case' or 'default' label", fixIts: ["insert label"]), DiagnosticSpec(locationMarker: "3️⃣", message: "'case' can only appear inside a 'switch' statement or 'enum' declaration"), - ] + ], + fixedSource: """ + switch { + case <#identifier#>: 42 } { + case _: return + } + """ ) } @@ -678,11 +754,18 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "all statements inside a switch must be covered by a 'case' or 'default' label", fixIts: ["insert label"]), DiagnosticSpec(locationMarker: "3️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "4️⃣", message: "'case' can only appear inside a 'switch' statement or 'enum' declaration"), - ] + ], + fixedSource: """ + switch { + case <#identifier#>: 42 }(); { + case _: return + } + """ ) } - //===--- Recovery for missing braces in nominal type decls. + // MARK: - Recovery for missing braces in nominal type decls. + func testRecovery54() { assertParse( """ @@ -690,7 +773,11 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected member block in struct", fixIts: ["insert member block"]) - ] + ], + fixedSource: """ + struct NoBracesStruct1 { + }() + """ ) } @@ -713,7 +800,17 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "4️⃣", message: "expected '}' to end protocol", fixIts: ["insert '}'"]), DiagnosticSpec(locationMarker: "4️⃣", message: "expected '}' to end class", fixIts: ["insert '}'"]), DiagnosticSpec(locationMarker: "4️⃣", message: "expected '}' to end enum", fixIts: ["insert '}'"]), - ] + ], + fixedSource: """ + enum NoBracesUnion1 {() + class NoBracesClass1 {() + protocol NoBracesProtocol1 {() + extension NoBracesStruct1 { + } + } + } + }() + """ ) } @@ -736,11 +833,24 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "5️⃣", message: "expected '}' to end class", fixIts: ["insert '}'"]), DiagnosticSpec(locationMarker: "5️⃣", message: "expected '}' to end enum", fixIts: ["insert '}'"]), DiagnosticSpec(locationMarker: "5️⃣", message: "expected '}' to end struct", fixIts: ["insert '}'"]), - ] + ], + fixedSource: """ + struct NoBracesStruct2 { + enum NoBracesUnion2 { + class NoBracesClass2 { + protocol NoBracesProtocol2 { + extension NoBracesStruct2 { + } + } + } + } + } + """ ) } - //===--- Recovery for multiple identifiers in decls + // MARK: - Recovery for multiple identifiers in decls + func testRecovery58() { let testCases: [UInt: (fixIt: String, fixedSource: String)] = [ #line: ("join the identifiers together", "protocol Multiident {}"), @@ -805,7 +915,13 @@ final class RecoveryTests: XCTestCase { fixIts: ["insert ';'"] ), DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected code 'a' before enum case"), - ] + ], + fixedSource: """ + enum EEEE where T : Multi { + case a;a + case b + } + """ ) } @@ -903,7 +1019,7 @@ final class RecoveryTests: XCTestCase { ) } - //===--- Recovery for parse errors in types. + // MARK: - Recovery for parse errors in types. func testRecovery67() { assertParse( @@ -914,7 +1030,12 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected type in type annotation", fixIts: ["insert type"]) - ] + ], + fixedSource: """ + struct ErrorTypeInVarDecl1 { + var v1 : <#type#> + } + """ ) } @@ -928,7 +1049,13 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected name in member type", fixIts: ["insert name"]) - ] + ], + fixedSource: """ + struct ErrorTypeInVarDecl2 { + var v1 : Int.<#identifier#> + var v2 : Int + } + """ ) } @@ -942,7 +1069,13 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '>' to end generic argument clause", fixIts: ["insert '>'"]) - ] + ], + fixedSource: """ + struct ErrorTypeInVarDecl3 { + var v1 : Int< > + var v2 : Int + } + """ ) } @@ -956,7 +1089,13 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '>' to end generic argument clause", fixIts: ["insert '>'"]) - ] + ], + fixedSource: """ + struct ErrorTypeInVarDecl4 { + var v1 : Int< >, + var v2 : Int + } + """ ) } @@ -970,7 +1109,13 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '>' to end generic argument clause", fixIts: ["insert '>'"]) - ] + ], + fixedSource: """ + struct ErrorTypeInVarDecl5 { + var v1 : Int + var v2 : Int + } + """ ) } @@ -984,8 +1129,21 @@ final class RecoveryTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(message: "expected '>' to end generic argument clause", notes: [NoteSpec(message: "to match this opening '<'")], fixIts: ["insert '>'"]) - ] + DiagnosticSpec( + message: "expected '>' to end generic argument clause", + notes: [ + NoteSpec(message: "to match this opening '<'") + ], + fixIts: ["insert '>'"] + ) + ], + fixedSource: """ + struct ErrorTypeInVarDecl6 { + var v1 : Int + var v2 : Int + } + """ ) } @@ -1000,7 +1158,13 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected type in generic argument", fixIts: ["insert type"]), DiagnosticSpec(message: "expected '>' to end generic argument clause", fixIts: ["insert '>'"]), - ] + ], + fixedSource: """ + struct ErrorTypeInVarDecl7 { + var v1 : Int> + var v2 : Int + } + """ ) } @@ -1014,7 +1178,13 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected type in type composition", fixIts: ["insert type"]) - ] + ], + fixedSource: """ + struct ErrorTypeInVarDecl12 { + var v1 : FooProtocol & <#type#> + var v2 : Int + } + """ ) } @@ -1028,7 +1198,13 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected type in type composition", fixIts: ["insert type"]) - ] + ], + fixedSource: """ + struct ErrorTypeInVarDecl13 { + var v1 : <#type#> & FooProtocol + var v2 : Int + } + """ ) } @@ -1042,7 +1218,13 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected type in type composition", fixIts: ["insert type"]) - ] + ], + fixedSource: """ + struct ErrorTypeInVarDecl16 { + var v1 : FooProtocol & <#type#> + var v2 : Int + } + """ ) } @@ -1053,7 +1235,10 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected type in type composition", fixIts: ["insert type"]) - ] + ], + fixedSource: """ + func ErrorTypeInPattern4(_: FooProtocol & <#type#>) { } + """ ) } @@ -1065,7 +1250,11 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected '>' to end generic parameter clause", fixIts: ["insert '>'"]), DiagnosticSpec(message: "expected member block in struct", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + struct ErrorGenericParameterList1< > { + } + """ ) } @@ -1078,7 +1267,11 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(message: "expected name in generic parameter", fixIts: ["insert name"]), DiagnosticSpec(message: "expected '>' to end generic parameter clause", fixIts: ["insert '>'"]), DiagnosticSpec(message: "expected member block in struct", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + struct ErrorGenericParameterList1> { + } + """ ) } @@ -1090,7 +1283,11 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected '>' to end generic parameter clause", fixIts: ["insert '>'"]), DiagnosticSpec(message: "expected member block in struct", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + struct ErrorGenericParameterList2 { + } + """ ) } @@ -1103,42 +1300,56 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(message: "expected generic parameter in generic parameter clause", fixIts: ["insert generic parameter"]), DiagnosticSpec(message: "expected '>' to end generic parameter clause", fixIts: ["insert '>'"]), DiagnosticSpec(message: "expected member block in struct", fixIts: ["insert member block"]), - ] + ], + fixedSource: """ + struct ErrorGenericParameterList3> { + } + """ ) } func testRecovery90() { + // Note: Don't move braces to a different line here. assertParse( """ - // Note: Don't move braces to a different line here. struct ErrorGenericParameterList4<1️⃣ { } """, diagnostics: [ DiagnosticSpec(message: "expected '>' to end generic parameter clause", fixIts: ["insert '>'"]) - ] + ], + fixedSource: """ + struct ErrorGenericParameterList4< > + { + } + """ ) } func testRecovery91() { + // Note: Don't move braces to a different line here. assertParse( """ - // Note: Don't move braces to a different line here. struct ErrorGenericParameterList5' to end generic parameter clause", fixIts: ["insert '>'"]) - ] + ], + fixedSource: """ + struct ErrorGenericParameterList5 + { + } + """ ) } func testRecovery92() { + // Note: Don't move braces to a different line here. assertParse( """ - // Note: Don't move braces to a different line here. struct ErrorGenericParameterList6' to end generic parameter clause", fixIts: ["insert '>'"]), - ] + ], + fixedSource: """ + struct ErrorGenericParameterList6> + { + } + """ ) } @@ -1160,7 +1376,13 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected return type in function type", fixIts: ["insert return type"]) - ] + ], + fixedSource: """ + struct ErrorTypeInVarDeclFunctionType1 { + var v1 : () -> <#type#> + var v2 : Int + } + """ ) } @@ -1195,7 +1417,10 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected '>' to end generic argument clause", fixIts: ["insert '>'"]), DiagnosticSpec(message: "extraneous code ']>' at top level"), - ] + ], + fixedSource: """ + let a2: Set]> + """ ) } @@ -1250,7 +1475,6 @@ final class RecoveryTests: XCTestCase { message: "expected '[' to start dictionary type", fixIts: ["insert '['"] ), - ], fixedSource: """ struct ErrorTypeInVarDeclDictionaryType { @@ -1281,7 +1505,18 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "expected ']' to end array", fixIts: ["insert ']'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected ']' in type; did you mean to write an array type?", fixIts: ["insert '['"]), DiagnosticSpec(locationMarker: "4️⃣", message: "extraneous brace at top level"), - ] + ], + fixedSource: """ + struct ErrorInFunctionSignatureResultArrayType1 { + func foo() -> Int + }[ { + return [0] + }] + func bar() -> [Int] { + return [0] + } + } + """ ) } @@ -1300,7 +1535,15 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected '}' to end struct", fixIts: ["insert '}'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected ']' to end array", fixIts: ["insert ']'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "extraneous brace at top level"), - ] + ], + fixedSource: """ + struct ErrorInFunctionSignatureResultArrayType2 { + func foo() -> Int + }[0 { + return [0] + }] + } + """ ) } @@ -1360,17 +1603,18 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '}' to end struct", fixIts: ["insert '}'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "extraneous brace at top level"), - ] + ], + fixedSource: """ + struct ErrorInFunctionSignatureResultArrayType11 { + func foo() -> Int + }[(a){a++}] { + } + } + """ ) } - func testRecovery106() { - assertParse( - """ - //===--- Recovery for missing initial value in var decls. - """ - ) - } + // Recovery for missing initial value in var decls. func testRecovery107() { assertParse( @@ -1381,17 +1625,16 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression in variable", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + struct MissingInitializer1 { + var v1 : Int = <#expression#> + } + """ ) } - func testRecovery108() { - assertParse( - """ - //===--- Recovery for expr-postfix. - """ - ) - } + // MARK: - Recovery for expr-postfix. func testRecovery109() { assertParse( @@ -1402,7 +1645,12 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected name in member access", fixIts: ["insert name"]) - ] + ], + fixedSource: """ + func exprPostfix1(x : Int) { + x.<#identifier#> + } + """ ) } @@ -1416,17 +1664,23 @@ final class RecoveryTests: XCTestCase { diagnostics: [ // TODO: Old parser expected error on line 2: '.42' is not a valid floating point literal; it must be written '0.42', Fix-It replacements: 7 - 7 = '0' DiagnosticSpec(message: "expected name in member access", fixIts: ["insert name"]) - ] + ], + fixedSource: """ + func exprPostfix2() { + _ = .<#identifier#>42 + } + """ ) } func testRecovery111() { assertParse( """ - //===--- Recovery for expr-super. + //===--- """ ) } + // MARK: - Recovery for expr-super. func testRecovery112() { assertParse( @@ -1459,7 +1713,14 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected name in member access", fixIts: ["insert name"]) - ] + ], + fixedSource: """ + class ExprSuper2 { + init() { + super.<#identifier#> + } + } + """ ) } @@ -1499,9 +1760,9 @@ final class RecoveryTests: XCTestCase { } func testRecovery118() { + // https://github.com/apple/swift/issues/43383 assertParse( #""" - // https://github.com/apple/swift/issues/43383 class С_43383 { 1️⃣print(2️⃣"No one else was in the room where it happened") } @@ -1509,7 +1770,12 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected 'func' in function", fixIts: ["insert 'func'"]), DiagnosticSpec(locationMarker: "2️⃣", message: #"unexpected code '"No one else was in the room where it happened"' in parameter clause"#), - ] + ], + fixedSource: #""" + class С_43383 { + func print("No one else was in the room where it happened") + } + """# ) } @@ -1523,7 +1789,12 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected 'func' in function", fixIts: ["insert 'func'"]), DiagnosticSpec(locationMarker: "2️⃣", message: #"unexpected code '"The room where it happened, the room where it happened"' in parameter clause"#), - ] + ], + fixedSource: #""" + extension С_43383 { + func print("The room where it happened, the room where it happened") + } + """# ) } @@ -1708,9 +1979,9 @@ final class RecoveryTests: XCTestCase { } func testRecovery133() { + // Parser hangs at swift::Parser::parseType assertParse( #""" - // Parser hangs at swift::Parser::parseType public enum TestA { public static func convertFromExtenndition( s1️⃣._core.count != 0, "Can't form a Character from an empty String") @@ -1719,7 +1990,13 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected ':' and type in parameter", fixIts: ["insert ':' and type"]), DiagnosticSpec(message: #"unexpected code '._core.count != 0, "Can't form a Character from an empty String"' in parameter clause"#), - ] + ], + fixedSource: #""" + public enum TestA { + public static func convertFromExtenndition( + s: <#type#>._core.count != 0, "Can't form a Character from an empty String") + } + """# ) } @@ -1734,29 +2011,29 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected ':' and type in parameter", fixIts: ["insert ':' and type"]), DiagnosticSpec(message: #"unexpected code '._core.count ?= 0, "Can't form a Character from an empty String"' in parameter clause"#), - ] - ) - } - - func testRecovery135() { - assertParse( - """ - // Infinite loop and unbounded memory consumption in parser - class bar {} - """ + ], + fixedSource: #""" + public enum TestB { + public static func convertFromExtenndition( + s: <#type#>._core.count ?= 0, "Can't form a Character from an empty String") + } + """# ) } func testRecovery136() { + // Infinite loop and unbounded memory consumption in parser assertParse( """ - var baz: bar func foo1(bar1️⃣!=baz) {} """, diagnostics: [ DiagnosticSpec(message: "expected ':' and type in parameter", fixIts: ["insert ':' and type"]), DiagnosticSpec(message: "unexpected code '!=baz' in parameter clause"), - ] + ], + fixedSource: """ + func foo1(bar: <#type#>!=baz) {} + """ ) } @@ -1768,14 +2045,17 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected ':' and type in parameter", fixIts: ["insert ':' and type"]), DiagnosticSpec(message: "unexpected code '! = baz' in parameter clause"), - ] + ], + fixedSource: """ + func foo2(bar: <#type#>! = baz) {} + """ ) } func testRecovery138() { + // rdar://19605567 assertParse( """ - // rdar://19605567 switch esp { case let (jeb): class Ceac<1️⃣}2️⃣> {} @@ -1785,15 +2065,21 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected '>' to end generic parameter clause", fixIts: ["insert '>'"]), DiagnosticSpec(locationMarker: "1️⃣", message: "expected '{' in class", fixIts: ["insert '{'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '> {}' in 'switch' statement"), - ] + ], + fixedSource: """ + switch esp { + case let (jeb): + class Ceac< > {}> {} + } + """ ) } func testRecovery141() { + // rdar://19605164 assertParse( """ #if true - // rdar://19605164 struct Foo19605164 { func a(s: S1️⃣[{{g2️⃣) -> Int {} }}3️⃣} @@ -1805,14 +2091,22 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code ') -> Int {}' in closure"), DiagnosticSpec(locationMarker: "3️⃣", message: "expected ']' to end array", fixIts: ["insert ']'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected brace in conditional compilation block"), - ] + ], + fixedSource: """ + #if true + struct Foo19605164 { + func a(s: S) + }[{{g) -> Int {} + }}]} + #endif + """ ) } func testRecovery143() { + // rdar://19605567 assertParse( """ - // rdar://19605567 func F() { init<1️⃣( 2️⃣} 3️⃣)} struct InitializerWithName { init 4️⃣x() {}5️⃣ @@ -1823,7 +2117,13 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "expected ')' to end parameter clause", fixIts: ["insert ')'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected code ')}' before struct"), DiagnosticSpec(locationMarker: "4️⃣", message: "initializers cannot have a name", fixIts: ["remove 'x'"]), - ] + ], + fixedSource: """ + func F() { init< >()} )} + struct InitializerWithName { + init() {} + } + """ ) } @@ -1891,7 +2191,10 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '(' to start parameter clause", fixIts: ["insert '('"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected ')' to end parameter clause", fixIts: ["insert ')'"]), - ] + ], + fixedSource: """ + init(c d: Int) {} + """ ) } @@ -1908,9 +2211,9 @@ final class RecoveryTests: XCTestCase { } func testRecovery151() { + // QoI: Nonsensical error and fixit if "let" is missing between 'if let ... where' clauses assertParse( #""" - // QoI: Nonsensical error and fixit if "let" is missing between 'if let ... where' clauses if let y = x 1️⃣where y == 0, let z = x { _ = y _ = z @@ -1921,7 +2224,14 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected '{' in 'if' statement", fixIts: ["insert '{'"]), DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code 'where y == 0,' before variable"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end 'if' statement", fixIts: ["insert '}'"]), - ] + ], + fixedSource: #""" + if let y = x {where y == 0, let z = x { + _ = y + _ = z + } + } + """# ) } @@ -2170,9 +2480,9 @@ final class RecoveryTests: XCTestCase { } func testRecovery170() { + // QoI: terrible recovery when using '·' for an operator assertParse( """ - // QoI: terrible recovery when using '·' for an operator infix operator 1️⃣· 2️⃣{ associativity none precedence3️⃣ 150 4️⃣} @@ -2182,7 +2492,11 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "operator should not be declared with body", fixIts: ["remove operator body"]), DiagnosticSpec(locationMarker: "3️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "4️⃣", message: "extraneous brace at top level"), - ] + ], + fixedSource: """ + infix operator · precedence; 150 + } + """ ) } @@ -2193,7 +2507,10 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'@-class' is not allowed in operator names", fixIts: ["remove '@-class'"]) - ] + ], + fixedSource: """ + infix operator - Recover1 {} + """ ) } @@ -2204,14 +2521,17 @@ final class RecoveryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "'фф--class' is not allowed in operator names", fixIts: ["remove 'фф--class'"]) - ] + ], + fixedSource: """ + prefix operator - Recover2 {} + """ ) } func testRecovery173() { + // Swift Compiler bug: String subscripts with range should require closing bracket. assertParse( #""" - // Swift Compiler bug: String subscripts with range should require closing bracket. func r21712891(s : String) -> String { let a = s.startIndex.. String { + let a = s.startIndex.. "Postfix '.' is reserved" error message" isn't helpful assertParse( #""" - // "Postfix '.' is reserved" error message" isn't helpful func postfixDot(a : String) { _ = a.utf8 _ = a1️⃣. utf8 @@ -2240,21 +2568,34 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "extraneous whitespace after '.' is not permitted", fixIts: ["remove whitespace"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected name in member access", fixIts: ["insert name"]), DiagnosticSpec(locationMarker: "3️⃣", message: "expected name in member access", fixIts: ["insert name"]), - ] + ], + fixedSource: #""" + func postfixDot(a : String) { + _ = a.utf8 + _ = a.utf8 + _ = a.<#identifier#> + a.<#identifier#> + } + """# ) } func testRecovery175() { + // QoI: "UIColor." gives two issues, should only give one assertParse( #""" - // QoI: "UIColor." gives two issues, should only give one func f() { // expected-note 2{{did you mean 'f'?}} _ = ClassWithStaticDecls.1️⃣ } """#, diagnostics: [ DiagnosticSpec(message: "expected name in member access", fixIts: ["insert name"]) - ] + ], + fixedSource: #""" + func f() { // expected-note 2{{did you mean 'f'?}} + _ = ClassWithStaticDecls.<#identifier#> + } + """# ) } @@ -2299,7 +2640,13 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '}' to end function", fixIts: ["insert '}'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "extraneous code at top level"), - ] + ], + fixedSource: """ + func testSkipUnbalancedParen() { + } + ?( + } + """ ) } @@ -2314,7 +2661,13 @@ final class RecoveryTests: XCTestCase { DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression, '=', and expression in pattern matching", fixIts: ["insert expression, '=', and expression"]), DiagnosticSpec(locationMarker: "1️⃣", message: "expected '{' in 'if' statement", fixIts: ["insert '{'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end function", fixIts: ["insert '}'"]), - ] + ], + fixedSource: """ + func testSkipToFindOpenBrace1() { + do { if case <#expression#> = <#expression#> {} + } + } + """ ) } @@ -2328,7 +2681,13 @@ final class RecoveryTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '{' or 'if' after 'else'"), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end function", fixIts: ["insert '}'"]), - ] + ], + fixedSource: """ + func testSkipToFindOpenBrace2() { + do { if true {} else false } + } + } + """ ) } diff --git a/Tests/SwiftParserTest/translated/RegexParseEndOfBufferTests.swift b/Tests/SwiftParserTest/translated/RegexParseEndOfBufferTests.swift index 18cd41a31ae..63f744d0938 100644 --- a/Tests/SwiftParserTest/translated/RegexParseEndOfBufferTests.swift +++ b/Tests/SwiftParserTest/translated/RegexParseEndOfBufferTests.swift @@ -20,7 +20,10 @@ final class RegexParseEndOfBufferTests: XCTestCase { "var unterminated = #/(xy1️⃣", diagnostics: [ DiagnosticSpec(message: "expected '/#' to end regex literal", fixIts: ["insert '/#'"]) - ] + ], + fixedSource: """ + var unterminated = #/(xy/# + """ ) } } diff --git a/Tests/SwiftParserTest/translated/RegexParseErrorTests.swift b/Tests/SwiftParserTest/translated/RegexParseErrorTests.swift index 228d1b0ccb1..0cf27fe4543 100644 --- a/Tests/SwiftParserTest/translated/RegexParseErrorTests.swift +++ b/Tests/SwiftParserTest/translated/RegexParseErrorTests.swift @@ -54,7 +54,10 @@ final class RegexParseErrorTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected '#' to end regex literal", fixIts: ["insert '#'"]) - ] + ], + fixedSource: #""" + _ = #/\\/''/# + """# ) } @@ -65,7 +68,10 @@ final class RegexParseErrorTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected '/#' to end regex literal", fixIts: ["insert '/#'"]) - ] + ], + fixedSource: #""" + _ = #/\|/# + """# ) } @@ -76,7 +82,10 @@ final class RegexParseErrorTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '#' to end regex literal", fixIts: ["insert '#'"]) - ] + ], + fixedSource: """ + _ = #//# + """ ) } @@ -87,7 +96,10 @@ final class RegexParseErrorTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '/#' to end regex literal", fixIts: ["insert '/#'"]) - ] + ], + fixedSource: """ + _ = #/xy/# + """ ) } @@ -132,7 +144,12 @@ final class RegexParseErrorTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '/#' to end regex literal", fixIts: ["insert '/#'"]) - ] + ], + fixedSource: """ + do { + _ = #/(?'a/# + } + """ ) } @@ -155,7 +172,13 @@ final class RegexParseErrorTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected root in key path", fixIts: ["insert root"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected expression after operator", fixIts: ["insert expression"]), - ] + ], + fixedSource: #""" + do { + _ = /\<#type#> + / <#expression#> + } + """# ) } @@ -170,7 +193,13 @@ final class RegexParseErrorTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '/#' to end regex literal", fixIts: ["insert '/#'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in macro expansion", fixIts: ["insert identifier"]), - ] + ], + fixedSource: #""" + do { + _ = #/\/# + /#<#identifier#> + } + """# ) } diff --git a/Tests/SwiftParserTest/translated/SelfRebindingTests.swift b/Tests/SwiftParserTest/translated/SelfRebindingTests.swift index 2e9cbf9d48f..e1db6a807ad 100644 --- a/Tests/SwiftParserTest/translated/SelfRebindingTests.swift +++ b/Tests/SwiftParserTest/translated/SelfRebindingTests.swift @@ -64,7 +64,15 @@ final class SelfRebindingTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "keyword 'self' cannot be used as an identifier here", fixIts: ["if this name is unavoidable, use backticks to escape it"]) - ] + ], + fixedSource: """ + struct T { + var mutable: Int = 0 + func f() { + let `self` = self + } + } + """ ) } diff --git a/Tests/SwiftParserTest/translated/StringLiteralEofTests.swift b/Tests/SwiftParserTest/translated/StringLiteralEofTests.swift index ea10d0e065b..362bcd4d7ec 100644 --- a/Tests/SwiftParserTest/translated/StringLiteralEofTests.swift +++ b/Tests/SwiftParserTest/translated/StringLiteralEofTests.swift @@ -24,7 +24,11 @@ final class StringLiteralEofTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected value and ')' in string literal", fixIts: ["insert value and ')'"]), DiagnosticSpec(message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: ##""" + // NOTE: DO NOT add a newline at EOF. + _ = "foo\(<#expression#>)" + """## ) } @@ -65,7 +69,10 @@ final class StringLiteralEofTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "invalid escape sequence in literal"), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: ##""" + _ = "foo \" + """## ) } @@ -78,7 +85,11 @@ final class StringLiteralEofTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "invalid escape sequence in literal"), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: ##""" + // NOTE: DO NOT add a newline at EOF. + _ = "foo \" + """## ) } @@ -91,7 +102,12 @@ final class StringLiteralEofTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: #"expected '"""' to end string literal"#, fixIts: [#"insert '"""'"#]) - ] + ], + fixedSource: #""" + // NOTE: DO NOT add a newline at EOF. + _ = """ + foo""" + """# ) } @@ -128,7 +144,12 @@ final class StringLiteralEofTests: XCTestCase { DiagnosticSpec(message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(message: "expected ')' in string literal", fixIts: ["insert ')'"]), DiagnosticSpec(message: #"expected '"""' to end string literal"#, fixIts: [#"insert '"""'"#]), - ] + ], + fixedSource: ##""" + _ = """ + foo + \("bar")""" + """## ) } @@ -144,8 +165,12 @@ final class StringLiteralEofTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code 'baz' in string literal"), DiagnosticSpec(locationMarker: "3️⃣", message: "expected ')' in string literal", fixIts: ["insert ')'"]), DiagnosticSpec(locationMarker: "3️⃣", message: #"expected '"""' to end string literal"#, fixIts: [#"insert '"""'"#]), - ] + ], + fixedSource: ##""" + _ = """ + \("bar" + baz)""" + """## ) } - } diff --git a/Tests/SwiftParserTest/translated/SubscriptingTests.swift b/Tests/SwiftParserTest/translated/SubscriptingTests.swift index ea420323e94..161c185f028 100644 --- a/Tests/SwiftParserTest/translated/SubscriptingTests.swift +++ b/Tests/SwiftParserTest/translated/SubscriptingTests.swift @@ -235,7 +235,15 @@ final class SubscriptingTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected parameter clause in subscript", fixIts: ["insert parameter clause"]) - ] + ], + fixedSource: """ + // Parsing errors + struct A0 { + subscript() -> Int { + return 1 + } + } + """ ) } @@ -255,8 +263,21 @@ final class SubscriptingTests: XCTestCase { } """, diagnostics: [ - DiagnosticSpec(locationMarker: "1️⃣", message: "expected '->' in subscript", fixIts: ["insert '->'"]) - ] + DiagnosticSpec(message: "expected '->' in subscript", fixIts: ["insert '->'"]) + ], + fixedSource: """ + struct A1 { + subscript (i : Int) -> + Int { + get { + return stored + } + set { + stored = newValue + } + } + } + """ ) } @@ -277,7 +298,20 @@ final class SubscriptingTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected return type in subscript", fixIts: ["insert return type"]) - ] + ], + fixedSource: """ + struct A2 { + subscript (i : Int) -> <#type#> + { + get { + return stored + } + set { + stored = newValue + } + } + } + """ ) } @@ -295,7 +329,17 @@ final class SubscriptingTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '->' and return type in subscript", fixIts: ["insert '->' and return type"]) - ] + ], + fixedSource: """ + struct A3 { + subscript(i : Int) -> <#type#> + { + get { + return i + } + } + } + """ ) } @@ -312,7 +356,16 @@ final class SubscriptingTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '->' and return type in subscript", fixIts: ["insert '->' and return type"]) - ] + ], + fixedSource: """ + struct A4 { + subscript(i : Int) -> <#type#> { + get { + return i + } + } + } + """ ) } @@ -387,7 +440,19 @@ final class SubscriptingTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '{' in subscript", fixIts: ["insert '{'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end struct", fixIts: ["insert '}'"]), - ] + ], + fixedSource: """ + struct A8 { + subscript(i : Int) -> Int { + get { + return stored + } + set { + stored = value + } + } + } + """ ) } diff --git a/Tests/SwiftParserTest/translated/SuperTests.swift b/Tests/SwiftParserTest/translated/SuperTests.swift index 2d19b54e0a5..603f5832856 100644 --- a/Tests/SwiftParserTest/translated/SuperTests.swift +++ b/Tests/SwiftParserTest/translated/SuperTests.swift @@ -116,7 +116,14 @@ final class SuperTests: XCTestCase { """#, diagnostics: [ DiagnosticSpec(message: "expected name in member access", fixIts: ["insert name"]) - ] + ], + fixedSource: #""" + class D : B { + func bad_super_1() { + super.<#identifier#>$0 + } + } + """# ) } diff --git a/Tests/SwiftParserTest/translated/SwitchIncompleteTests.swift b/Tests/SwiftParserTest/translated/SwitchIncompleteTests.swift index 80bbf194d6d..f2f50f35bab 100644 --- a/Tests/SwiftParserTest/translated/SwitchIncompleteTests.swift +++ b/Tests/SwiftParserTest/translated/SwitchIncompleteTests.swift @@ -31,7 +31,12 @@ final class SwitchIncompleteTests: XCTestCase { ], fixIts: ["insert '}'"] ) - ] + ], + fixedSource: """ + switch 1 { + case 1: + } + """ ) } } diff --git a/Tests/SwiftParserTest/translated/SwitchTests.swift b/Tests/SwiftParserTest/translated/SwitchTests.swift index 48d22e636c6..bfcb21e39c7 100644 --- a/Tests/SwiftParserTest/translated/SwitchTests.swift +++ b/Tests/SwiftParserTest/translated/SwitchTests.swift @@ -35,7 +35,13 @@ final class SwitchTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected expression and '{}' to end 'switch' statement", fixIts: ["insert expression and '{}'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier and function signature in function", fixIts: ["insert identifier and function signature"]), - ] + ], + fixedSource: """ + func parseError1(x: Int) { + switch <#expression#> { + }func <#identifier#>() {} + } + """ ) } @@ -48,7 +54,13 @@ final class SwitchTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '{}' in 'switch' statement", fixIts: ["insert '{}'"]) - ] + ], + fixedSource: """ + func parseError2(x: Int) { + switch x { + } + } + """ ) } @@ -63,7 +75,14 @@ final class SwitchTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression and ':' in switch case", fixIts: ["insert expression and ':'"]) - ] + ], + fixedSource: """ + func parseError3(x: Int) { + switch x { + case <#expression#>: + } + } + """ ) } @@ -79,7 +98,14 @@ final class SwitchTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected expression in 'where' clause", fixIts: ["insert expression"]), DiagnosticSpec(message: "expected ':' in switch case", fixIts: ["insert ':'"]), - ] + ], + fixedSource: """ + func parseError4(x: Int) { + switch x { + case var z where <#expression#>: + } + } + """ ) } @@ -94,7 +120,14 @@ final class SwitchTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected ':' in switch case", fixIts: ["insert ':'"]) - ] + ], + fixedSource: """ + func parseError5(x: Int) { + switch x { + case let z: + } + } + """ ) } @@ -109,7 +142,14 @@ final class SwitchTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected ':' in switch case", fixIts: ["insert ':'"]) - ] + ], + fixedSource: """ + func parseError6(x: Int) { + switch x { + default: + } + } + """ ) } @@ -251,7 +291,19 @@ final class SwitchTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "all statements inside a switch must be covered by a 'case' or 'default' label", fixIts: ["insert label"]) - ] + ], + fixedSource: """ + switch x { + case <#identifier#>: + x = 1 + default: + x = 0 + case 0: + x = 0 + case 1: + x = 0 + } + """ ) } @@ -300,7 +352,13 @@ final class SwitchTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "all statements inside a switch must be covered by a 'case' or 'default' label", fixIts: ["insert label"]) - ] + ], + fixedSource: """ + switch x { + case <#identifier#>: + x = 1 + } + """ ) } @@ -314,7 +372,14 @@ final class SwitchTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "all statements inside a switch must be covered by a 'case' or 'default' label", fixIts: ["insert label"]) - ] + ], + fixedSource: """ + switch x { + case <#identifier#>: + x = 1 + x = 2 + } + """ ) } @@ -1191,7 +1256,16 @@ final class SwitchTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected ':' in switch case", fixIts: ["insert ':'"]) - ] + ], + fixedSource: """ + func testReturnBeforeIncompleteUnknownDefault() { + switch x { + case 1: + return + @unknown default: + } + } + """ ) } @@ -1208,7 +1282,16 @@ final class SwitchTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected label in switch case", fixIts: ["insert label"]) - ] + ], + fixedSource: """ + func testReturnBeforeIncompleteUnknownDefault2() { + switch x { + case 1: + return + @unknown case <#identifier#>: + } + } + """ ) } @@ -1232,7 +1315,17 @@ final class SwitchTests: XCTestCase { ], fixIts: ["insert ']'"] ) - ] + ], + fixedSource: """ + func testIncompleteArrayLiteral() { + switch x { + case 1: + _ = [1] + @unknown default: + () + } + } + """ ) } } diff --git a/Tests/SwiftParserTest/translated/TrailingClosuresTests.swift b/Tests/SwiftParserTest/translated/TrailingClosuresTests.swift index 4acd9591066..19074f89137 100644 --- a/Tests/SwiftParserTest/translated/TrailingClosuresTests.swift +++ b/Tests/SwiftParserTest/translated/TrailingClosuresTests.swift @@ -212,7 +212,14 @@ final class TrailingClosuresTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive statements on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "2️⃣", message: "'default' label can only appear inside a 'switch' statement"), - ] + ], + fixedSource: """ + func produce(fn: () -> Int?, default d: () -> Int) -> Int { + return fn() ?? d() + } + _ = produce { 0 }; default: { 1 } + _ = produce { 2 } `default`: { 3 } + """ ) } diff --git a/Tests/SwiftParserTest/translated/TrailingSemiTests.swift b/Tests/SwiftParserTest/translated/TrailingSemiTests.swift index b27aab489ac..90fa62dd45d 100644 --- a/Tests/SwiftParserTest/translated/TrailingSemiTests.swift +++ b/Tests/SwiftParserTest/translated/TrailingSemiTests.swift @@ -43,7 +43,16 @@ final class TrailingSemiTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected ';' separator", fixIts: ["remove ';'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected ';' separator", fixIts: ["remove ';'"]), DiagnosticSpec(locationMarker: "4️⃣", message: "unexpected ';' separator", fixIts: ["remove ';;'"]), - ] + ], + fixedSource: """ + struct SpuriousSemi { + + var a : Int ; + func b () {}; + static func c () {}; + + } + """ ) } @@ -68,7 +77,21 @@ final class TrailingSemiTests: XCTestCase { DiagnosticSpec(locationMarker: "2️⃣", message: "consecutive declarations on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "3️⃣", message: "consecutive declarations on a line must be separated by ';'", fixIts: ["insert ';'"]), DiagnosticSpec(locationMarker: "4️⃣", message: "consecutive declarations on a line must be separated by ';'", fixIts: ["insert ';'"]), - ] + ], + fixedSource: """ + class C { + var a : Int = 10; func aa() {}; + #if FLAG1 + var aaa: Int = 42; func aaaa() {}; + #elseif FLAG2 + var aaa: Int = 42; func aaaa() {} + #else + var aaa: Int = 42; func aaaa() {} + #endif + func b () {}; + class func c () {}; + } + """ ) } @@ -84,7 +107,15 @@ final class TrailingSemiTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "consecutive declarations on a line must be separated by ';'", fixIts: ["insert ';'"]) - ] + ], + fixedSource: """ + extension S { + //var a : Int ; + func bb () {}; + static func cc () {}; + func dd() {}; subscript(i: Int) -> Int { return 1 } + } + """ ) } diff --git a/Tests/SwiftParserTest/translated/TryTests.swift b/Tests/SwiftParserTest/translated/TryTests.swift index 12893c1ce8b..1c486113296 100644 --- a/Tests/SwiftParserTest/translated/TryTests.swift +++ b/Tests/SwiftParserTest/translated/TryTests.swift @@ -249,7 +249,11 @@ final class TryTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected expression after 'try'", fixIts: ["insert expression"]) - ] + ], + fixedSource: """ + try <#expression#> + func method() {} + """ ) } diff --git a/Tests/SwiftParserTest/translated/TypeExprTests.swift b/Tests/SwiftParserTest/translated/TypeExprTests.swift index c9377870ce7..63e51e4a350 100644 --- a/Tests/SwiftParserTest/translated/TypeExprTests.swift +++ b/Tests/SwiftParserTest/translated/TypeExprTests.swift @@ -573,7 +573,10 @@ final class TypeExprTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '->' in array element", fixIts: ["insert '->'"]) - ] + ], + fixedSource: """ + let _ = [Int throws -> Int](); + """ ) } @@ -704,7 +707,10 @@ final class TypeExprTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '(' to start function type", fixIts: ["insert '('"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected ')' in function type", fixIts: ["insert ')'"]), - ] + ], + fixedSource: """ + func takesVoid(f: (Void) -> ()) {} + """ ) } diff --git a/Tests/SwiftParserTest/translated/TypealiasTests.swift b/Tests/SwiftParserTest/translated/TypealiasTests.swift index 42ac61c8f7f..2ef7e34292b 100644 --- a/Tests/SwiftParserTest/translated/TypealiasTests.swift +++ b/Tests/SwiftParserTest/translated/TypealiasTests.swift @@ -103,7 +103,10 @@ final class TypealiasTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '=' and type in typealias declaration", fixIts: ["insert '=' and type"]) - ] + ], + fixedSource: """ + typealias Recovery1 = <#type#> + """ ) } @@ -115,7 +118,10 @@ final class TypealiasTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '=' in typealias declaration", fixIts: ["replace ':' with '='"]), DiagnosticSpec(locationMarker: "2️⃣", message: "expected type in typealias declaration", fixIts: ["insert type"]), - ] + ], + fixedSource: """ + typealias Recovery2 =<#type#> + """ ) } @@ -126,7 +132,10 @@ final class TypealiasTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected type in typealias declaration", fixIts: ["insert type"]) - ] + ], + fixedSource: """ + typealias Recovery3 = <#type#> + """ ) } @@ -137,7 +146,10 @@ final class TypealiasTests: XCTestCase { """, diagnostics: [ DiagnosticSpec(message: "expected '=' in typealias declaration", fixIts: ["replace ':' with '='"]) - ] + ], + fixedSource: """ + typealias Recovery4 = Int + """ ) } @@ -149,7 +161,10 @@ final class TypealiasTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "expected '=' in typealias declaration", fixIts: ["replace ':' with '='"]), DiagnosticSpec(locationMarker: "2️⃣", message: "extraneous code ', Float' at top level"), - ] + ], + fixedSource: """ + typealias Recovery5 = Int, Float + """ ) } @@ -161,7 +176,10 @@ final class TypealiasTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected type in typealias declaration", fixIts: ["insert type"]), DiagnosticSpec(message: "extraneous code '=' at top level"), - ] + ], + fixedSource: """ + typealias Recovery6 = <#type#>= + """ ) } diff --git a/Tests/SwiftParserTest/translated/UnclosedStringInterpolationTests.swift b/Tests/SwiftParserTest/translated/UnclosedStringInterpolationTests.swift index 43b729de7d6..9630dbe6a64 100644 --- a/Tests/SwiftParserTest/translated/UnclosedStringInterpolationTests.swift +++ b/Tests/SwiftParserTest/translated/UnclosedStringInterpolationTests.swift @@ -46,7 +46,10 @@ final class UnclosedStringInterpolationTests: XCTestCase { DiagnosticSpec(message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(message: "expected ')' in string literal", fixIts: ["insert ')'"]), DiagnosticSpec(message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: ##""" + let theGoat = "kanye \("")" + """## ) } @@ -57,7 +60,10 @@ final class UnclosedStringInterpolationTests: XCTestCase { """##, diagnostics: [ DiagnosticSpec(message: "expected ')' in string literal", fixIts: ["insert ')'"]) - ] + ], + fixedSource: ##""" + let equation1 = "2 + 2 = \(2 + 2)" + """## ) } @@ -68,7 +74,10 @@ final class UnclosedStringInterpolationTests: XCTestCase { """##, diagnostics: [ DiagnosticSpec(message: "expected ')' in string literal", fixIts: ["insert ')'"]) - ] + ], + fixedSource: ##""" + let s = "\(x)"; print(x) + """## ) } @@ -80,7 +89,10 @@ final class UnclosedStringInterpolationTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code '; print(x' in string literal"), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: ##""" + let zzz = "\(x; print(x)" + """## ) } @@ -92,7 +104,10 @@ final class UnclosedStringInterpolationTests: XCTestCase { diagnostics: [ DiagnosticSpec(message: "expected ')' in string literal", fixIts: ["insert ')'"]), DiagnosticSpec(message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: ##""" + let goatedAlbum = "The Life Of \("Pablo")" + """## ) } @@ -107,7 +122,12 @@ final class UnclosedStringInterpolationTests: XCTestCase { DiagnosticSpec(message: #"expected '"""' to end string literal"#, fixIts: [#"insert '"""'"#]), DiagnosticSpec(message: "expected ')' in string literal", fixIts: ["insert ')'"]), DiagnosticSpec(message: #"expected '"""' to end string literal"#, fixIts: [#"insert '"""'"#]), - ] + ], + fixedSource: ##""" + _ = """ + \( + """""")""" + """## ) } @@ -119,7 +139,10 @@ final class UnclosedStringInterpolationTests: XCTestCase { diagnostics: [ DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code 'H(' in string literal"), DiagnosticSpec(locationMarker: "2️⃣", message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + "\(e H()r" + """# ) } @@ -132,7 +155,10 @@ final class UnclosedStringInterpolationTests: XCTestCase { DiagnosticSpec(message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), DiagnosticSpec(message: "expected ')' in string literal", fixIts: ["insert ')'"]), DiagnosticSpec(message: #"expected '"' to end string literal"#, fixIts: [#"insert '"'"#]), - ] + ], + fixedSource: #""" + "\("")" + """# ) } }