Skip to content

Commit 83d60db

Browse files
committed
Add diagnostic for array type
1 parent c2734b5 commit 83d60db

File tree

6 files changed

+88
-74
lines changed

6 files changed

+88
-74
lines changed

Sources/SwiftParser/Types.swift

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1052,7 +1052,35 @@ extension Parser {
10521052
)
10531053
)
10541054
} else {
1055-
return self.parseType()
1055+
var result = self.parseType()
1056+
1057+
guard !result.hasError else {
1058+
return result
1059+
}
1060+
1061+
if self.at(.rightSquareBracket) {
1062+
let (unexpectedBeforeRSquareBracket, rightSquareBracket) = self.expect(.rightSquareBracket)
1063+
result = RawTypeSyntax(
1064+
RawArrayTypeSyntax(
1065+
leftSquareBracket: missingToken(.leftSquareBracket),
1066+
elementType: result,
1067+
unexpectedBeforeRSquareBracket,
1068+
rightSquareBracket: rightSquareBracket,
1069+
arena: self.arena
1070+
)
1071+
)
1072+
}
1073+
1074+
if !self.currentToken.isAtStartOfLine {
1075+
if self.at(.postfixQuestionMark) {
1076+
result = RawTypeSyntax(self.parseOptionalType(result))
1077+
}
1078+
if self.at(.exclamationMark) {
1079+
result = RawTypeSyntax(self.parseImplicitlyUnwrappedOptionalType(result))
1080+
}
1081+
}
1082+
1083+
return result
10561084
}
10571085
}
10581086
}

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,23 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
410410
return .visitChildren
411411
}
412412

413+
public override func visit(_ node: ArrayTypeSyntax) -> SyntaxVisitorContinueKind {
414+
if shouldSkip(node) {
415+
return .skipChildren
416+
}
417+
418+
if node.leftSquareBracket.presence == .missing {
419+
addDiagnostic(
420+
node.rightSquareBracket,
421+
.extraRightBracket,
422+
fixIts: [.init(message: InsertFixIt(tokenToBeInserted: node.leftSquareBracket), changes: .makePresent(node.leftSquareBracket))],
423+
handledNodes: [node.leftSquareBracket.id]
424+
)
425+
}
426+
427+
return .visitChildren
428+
}
429+
413430
public override func visit(_ node: AttributeSyntax) -> SyntaxVisitorContinueKind {
414431
if shouldSkip(node) {
415432
return .skipChildren

Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ extension DiagnosticMessage where Self == StaticParserError {
140140
public static var expectedSequenceExpressionInForEachLoop: Self {
141141
.init("expected Sequence expression for for-each loop")
142142
}
143+
public static var extraRightBracket: Self {
144+
.init("unexpected ']' in type; did you mean to write an array type?")
145+
}
143146
public static var initializerInPattern: Self {
144147
.init("unexpected initializer in pattern; did you mean to use '='?")
145148
}
@@ -548,6 +551,14 @@ extension FixItMessage where Self == StaticParserFixIt {
548551
}
549552
}
550553

554+
public struct InsertFixIt: ParserFixIt {
555+
public let tokenToBeInserted: TokenSyntax
556+
557+
public var message: String {
558+
"insert '\(tokenToBeInserted.text)'"
559+
}
560+
}
561+
551562
public struct MoveTokensAfterFixIt: ParserFixIt {
552563
/// The token that should be moved
553564
public let movedTokens: [TokenSyntax]

Sources/SwiftSyntax/Raw/RawSyntaxNodeProtocol.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ public extension RawSyntaxNodeProtocol {
4646
var isEmpty: Bool {
4747
return raw.byteLength == 0
4848
}
49+
50+
/// Whether the tree contained by this layout has any
51+
/// - missing nodes or
52+
/// - unexpected nodes or
53+
/// - tokens with a `TokenDiagnostic` of severity `error`
54+
var hasError: Bool {
55+
return raw.recursiveFlags.contains(.hasError)
56+
}
4957
}
5058

5159
/// `RawSyntax` itself conforms to `RawSyntaxNodeProtocol`.

Sources/SwiftSyntax/Syntax.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,9 @@ public extension SyntaxProtocol {
246246
/// Whether the tree contained by this layout has any
247247
/// - missing nodes or
248248
/// - unexpected nodes or
249-
/// - tokens with a `TokenDiagnostic` of severity `error`
249+
/// - tokens with a ``TokenDiagnostic`` of severity ``TokenDiagnostic/Severity-swift.enum/error``.
250250
var hasError: Bool {
251-
return raw.recursiveFlags.contains(.hasError)
251+
return raw.hasError
252252
}
253253

254254
/// Whether the tree contained by this layout has any tokens with a

Tests/SwiftParserTest/translated/RecoveryTests.swift

Lines changed: 21 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,15 +1119,26 @@ final class RecoveryTests: XCTestCase {
11191119
)
11201120
}
11211121

1122-
func testRecovery98a() {
1123-
assertParse(
1124-
"""
1125-
let a1: Swift.Int1️⃣]
1126-
""",
1127-
diagnostics: [
1128-
DiagnosticSpec(message: "extraneous code ']' at top level")
1129-
]
1130-
)
1122+
func testRecovery98() {
1123+
let testCases: [UInt: (testCase: String, fixedSource: String)] = [
1124+
#line: ("let a1: Swift.Int1️⃣]", "let a1: [Swift.Int]"),
1125+
#line: ("let a3: Set<Int>1️⃣]", "let a3: [Set<Int>]"),
1126+
#line: ("let a4: Int1️⃣]?", "let a4: [Int]?"),
1127+
#line: ("let a5: Int?1️⃣]", "let a5: [Int?]"),
1128+
#line: ("let a6: [Int]1️⃣]", "let a6: [[Int]]"),
1129+
#line: ("let a7: [String: Int]1️⃣]", "let a7: [[String: Int]]"),
1130+
]
1131+
1132+
for (line, testCase) in testCases {
1133+
assertParse(
1134+
testCase.testCase,
1135+
diagnostics: [
1136+
DiagnosticSpec(message: "unexpected ']' in type; did you mean to write an array type?", fixIts: ["insert '['"], line: line)
1137+
],
1138+
fixedSource: testCase.fixedSource,
1139+
line: line
1140+
)
1141+
}
11311142
}
11321143

11331144
func testRecovery98b() {
@@ -1142,66 +1153,6 @@ final class RecoveryTests: XCTestCase {
11421153
)
11431154
}
11441155

1145-
func testRecovery98c() {
1146-
assertParse(
1147-
"""
1148-
let a3: Set<Int>1️⃣]
1149-
""",
1150-
diagnostics: [
1151-
// TODO: Old parser expected error on line 4: unexpected ']' in type; did you mean to write an array type?, Fix-It replacements: 11 - 11 = '['
1152-
DiagnosticSpec(message: "extraneous code ']' at top level")
1153-
]
1154-
)
1155-
}
1156-
1157-
func testRecovery98d() {
1158-
assertParse(
1159-
"""
1160-
let a4: Int1️⃣]?
1161-
""",
1162-
diagnostics: [
1163-
// TODO: Old parser expected error on line 5: unexpected ']' in type; did you mean to write an array type?, Fix-It replacements: 11 - 11 = '['
1164-
DiagnosticSpec(message: "extraneous code ']?' at top level")
1165-
]
1166-
)
1167-
}
1168-
1169-
func testRecovery98e() {
1170-
assertParse(
1171-
"""
1172-
let a5: Int?1️⃣]
1173-
""",
1174-
diagnostics: [
1175-
// TODO: Old parser expected error on line 6: unexpected ']' in type; did you mean to write an array type?, Fix-It replacements: 11 - 11 = '['
1176-
DiagnosticSpec(message: "extraneous code ']' at top level")
1177-
]
1178-
)
1179-
}
1180-
1181-
func testRecovery98f() {
1182-
assertParse(
1183-
"""
1184-
let a6: [Int]1️⃣]
1185-
""",
1186-
diagnostics: [
1187-
// TODO: Old parser expected error on line 7: unexpected ']' in type; did you mean to write an array type?, Fix-It replacements: 11 - 11 = '['
1188-
DiagnosticSpec(message: "extraneous code ']' at top level")
1189-
]
1190-
)
1191-
}
1192-
1193-
func testRecovery98g() {
1194-
assertParse(
1195-
"""
1196-
let a7: [String: Int]1️⃣]
1197-
""",
1198-
diagnostics: [
1199-
// TODO: Old parser expected error on line 8: unexpected ']' in type; did you mean to write an array type?, Fix-It replacements: 11 - 11 = '['
1200-
DiagnosticSpec(message: "extraneous code ']' at top level")
1201-
]
1202-
)
1203-
}
1204-
12051156
func testRecovery99() {
12061157
assertParse(
12071158
"""
@@ -1241,8 +1192,7 @@ final class RecoveryTests: XCTestCase {
12411192
diagnostics: [
12421193
DiagnosticSpec(locationMarker: "1️⃣", message: "expected '}' to end struct"),
12431194
DiagnosticSpec(locationMarker: "2️⃣", message: "expected ']' to end array"),
1244-
// TODO: Old parser expected error on line 5: unexpected ']' in type; did you mean to write an array type?, Fix-It replacements: 17 - 17 = '['
1245-
DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected code ']' in function"),
1195+
DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected ']' in type; did you mean to write an array type?"),
12461196
DiagnosticSpec(locationMarker: "4️⃣", message: "extraneous brace at top level"),
12471197
]
12481198
)

0 commit comments

Comments
 (0)