Skip to content

If a missing token has a child name, use that instead of the generic token kind #935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions Sources/SwiftParser/Diagnostics/MissingNodesError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,20 @@ fileprivate func findCommonAncestor(_ nodes: [Syntax]) -> Syntax? {

fileprivate enum MissingNodesDescriptionPart {
case tokensWithDefaultText([TokenSyntax])
case tokenWithoutDefaultText(RawTokenKind)
case tokenWithoutDefaultText(TokenSyntax)
case node(Syntax)

var description: String? {
switch self {
case .tokensWithDefaultText(let tokens):
let tokenContents = tokens.map({ BasicFormat().visit($0).description }).joined()
return "'\(tokenContents.trimmingSpaces())'"
case .tokenWithoutDefaultText(let tokenKind):
return tokenKind.nameForDiagnostics
case .tokenWithoutDefaultText(let token):
if let parent = token.parent,
let childName = parent.childNameForDiagnostics(token.index) {
return childName
}
return token.tokenKind.decomposeToRaw().rawKind.nameForDiagnostics
case .node(let node):
if let parent = node.parent,
let childName = parent.childNameForDiagnostics(node.index) {
Expand All @@ -57,7 +61,7 @@ fileprivate enum MissingNodesDescriptionPart {
let presentToken = TokenSyntax(newKind, presence: .present)
newPart = .tokensWithDefaultText([presentToken])
} else {
newPart = .tokenWithoutDefaultText(rawKind)
newPart = .tokenWithoutDefaultText(missingToken)
}

switch (parts.last, newPart) {
Expand Down
6 changes: 3 additions & 3 deletions Tests/SwiftDiagnosticsTest/DiagnosticsFormatterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ final class DiagnosticsFormatterTests: XCTestCase {
"""
let expectedOutput = """
1 │ foo.[].[].[]
∣ │ │ ╰─ expected identifier in member access
∣ │ ╰─ expected identifier in member access
∣ ╰─ expected identifier in member access
∣ │ │ ╰─ expected name in member access
∣ │ ╰─ expected name in member access
∣ ╰─ expected name in member access

"""
AssertStringsEqualWithDiff(expectedOutput, try annotate(source: source))
Expand Down
10 changes: 5 additions & 5 deletions Tests/SwiftParserTest/Declarations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ final class DeclarationTests: XCTestCase {
AssertParse(
"func 1️⃣/^notoperator^/ (lhs: Int, rhs: Int) -> Int { 1 / 2 }",
diagnostics: [
DiagnosticSpec(message: "expected identifier in function"),
DiagnosticSpec(message: "expected name in function"),
DiagnosticSpec(message: "unexpected code '/^notoperator^/' before parameter clause")
]
)
Expand Down Expand Up @@ -159,7 +159,7 @@ final class DeclarationTests: XCTestCase {
"protocol P{1️⃣{}case2️⃣",
diagnostics: [
DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code '{}' before enum case"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in enum case"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected name in enum case"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end protocol"),
])
}
Expand Down Expand Up @@ -816,7 +816,7 @@ final class DeclarationTests: XCTestCase {
diagnostics: [
DiagnosticSpec(locationMarker: "1️⃣", message: "expected ':' in function parameter"),
DiagnosticSpec(locationMarker: "3️⃣", message: "expected ')' to end parameter clause"),
DiagnosticSpec(locationMarker: "4️⃣", message: "expected identifier and member block in struct"),
DiagnosticSpec(locationMarker: "4️⃣", message: "expected name and member block in struct"),
DiagnosticSpec(locationMarker: "4️⃣", message: "extraneous code ': Int) {}' at top level"),
]
)
Expand Down Expand Up @@ -1102,7 +1102,7 @@ final class DeclarationTests: XCTestCase {
""",
diagnostics: [
DiagnosticSpec(message: "expected name in attribute"),
DiagnosticSpec(message: "expected identifier in generic parameter"),
DiagnosticSpec(message: "expected name in generic parameter"),
DiagnosticSpec(message: "expected '>' to end generic parameter clause"),
DiagnosticSpec(message: "expected member block in struct"),
]
Expand All @@ -1126,7 +1126,7 @@ final class DeclarationTests: XCTestCase {
AssertParse(
"func 1️⃣{}",
diagnostics: [
DiagnosticSpec(message: "expected identifier and function signature in function")
DiagnosticSpec(message: "expected name and function signature in function")
]
)
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/SwiftParserTest/translated/DeprecatedWhereTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ final class DeprecatedWhereTests: XCTestCase {
DiagnosticSpec(locationMarker: "2️⃣", message: "expected inherited type in generic parameter"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected '>' to end generic parameter clause"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected parameter clause in function signature"),
DiagnosticSpec(locationMarker: "3️⃣", message: "expected identifier and member block in protocol"),
DiagnosticSpec(locationMarker: "3️⃣", message: "expected name and member block in protocol"),
DiagnosticSpec(locationMarker: "3️⃣", message: "extraneous code '<ProtoA, ProtoB> where T: ProtoC>(x: T) {}' at top level"),
]
)
Expand All @@ -199,7 +199,7 @@ final class DeprecatedWhereTests: XCTestCase {
DiagnosticSpec(locationMarker: "2️⃣", message: "expected inherited type in generic parameter"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected '>' to end generic parameter clause"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected parameter clause in function signature"),
DiagnosticSpec(locationMarker: "3️⃣", message: "expected identifier and member block in protocol"),
DiagnosticSpec(locationMarker: "3️⃣", message: "expected name and member block in protocol"),
DiagnosticSpec(locationMarker: "3️⃣", message: "extraneous code '<ProtoA, ProtoB> where T: ProtoC>(x: T) where T: ProtoD {}' at top level"),
]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ final class DollarIdentifierTests: XCTestCase {
""",
diagnostics: [
// TODO: Old parser expected error on line 2: '$' is not an identifier; use backticks to escape it, Fix-It replacements: 9 - 10 = '`$`'
DiagnosticSpec(message: "expected identifier and member block in class"),
DiagnosticSpec(message: "expected name and member block in class"),
]
)
}
Expand All @@ -71,7 +71,7 @@ final class DollarIdentifierTests: XCTestCase {
""",
diagnostics: [
// TODO: Old parser expected error on line 2: '$' is not an identifier; use backticks to escape it, Fix-It replacements: 8 - 9 = '`$`'
DiagnosticSpec(message: "expected identifier and member block in enum"),
DiagnosticSpec(message: "expected name and member block in enum"),
]
)
}
Expand All @@ -85,7 +85,7 @@ final class DollarIdentifierTests: XCTestCase {
""",
diagnostics: [
// TODO: Old parser expected error on line 2: '$' is not an identifier; use backticks to escape it, Fix-It replacements: 10 - 11 = '`$`'
DiagnosticSpec(message: "expected identifier and member block in struct"),
DiagnosticSpec(message: "expected name and member block in struct"),
]
)
}
Expand All @@ -102,7 +102,7 @@ final class DollarIdentifierTests: XCTestCase {
diagnostics: [
// TODO: Old parser expected error on line 2: '$' is not an identifier; use backticks to escape it, Fix-It replacements: 8 - 9 = '`$`'
// TODO: Old parser expected error on line 2: '$' is not an identifier; use backticks to escape it, Fix-It replacements: 10 - 11 = '`$`'
DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in function"),
DiagnosticSpec(locationMarker: "1️⃣", message: "expected name in function"),
DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code '$' before parameter clause"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected type in function parameter"),
DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '$ dollarParam: Int' in parameter clause"),
Expand Down
22 changes: 11 additions & 11 deletions Tests/SwiftParserTest/translated/EnumTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ final class EnumTests: XCTestCase {
""",
diagnostics: [
// TODO: Old parser expected error on line 2: 'case' label can only appear inside a 'switch' statement
DiagnosticSpec(message: "expected identifier in enum case"),
DiagnosticSpec(message: "expected name in enum case"),
DiagnosticSpec(message: "unexpected code '0:' in enum"),
]
)
Expand Down Expand Up @@ -293,7 +293,7 @@ final class EnumTests: XCTestCase {
""",
diagnostics: [
// TODO: Old parser expected error on line 2: 'case' label can only appear inside a 'switch' statement
DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in enum case"),
DiagnosticSpec(locationMarker: "1️⃣", message: "expected name in enum case"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected ':' and type in function parameter"),
DiagnosticSpec(locationMarker: "3️⃣", message: "expected type in function parameter"),
DiagnosticSpec(locationMarker: "3️⃣", message: "unexpected code '0' in parameter clause"),
Expand Down Expand Up @@ -349,7 +349,7 @@ final class EnumTests: XCTestCase {
""",
diagnostics: [
// TODO: Old parser expected error on line 3: expected identifier after comma in enum 'case' declaration
DiagnosticSpec(message: "expected identifier in enum case"),
DiagnosticSpec(message: "expected name in enum case"),
]
)
}
Expand All @@ -364,7 +364,7 @@ final class EnumTests: XCTestCase {
diagnostics: [
// TODO: Old parser expected error on line 2: 'case' label can only appear inside a 'switch' statement
// TODO: Old parser expected error on line 2: expected pattern
DiagnosticSpec(message: "expected identifier in enum case"),
DiagnosticSpec(message: "expected name in enum case"),
DiagnosticSpec(message: "unexpected code ':' in enum"),
]
)
Expand Down Expand Up @@ -426,11 +426,11 @@ final class EnumTests: XCTestCase {
""",
diagnostics: [
// TODO: Old parser expected error on line 2: extraneous code '.' in enum 'case' declaration, Fix-It replacements: 8 - 9 = ''
DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in enum case"),
DiagnosticSpec(locationMarker: "1️⃣", message: "expected name in enum case"),
DiagnosticSpec(locationMarker: "1️⃣", message: "unexpected code '.UE3' before enum case"),
// TODO: Old parser expected error on line 3: extraneous code '.' in enum 'case' declaration, Fix-It replacements: 8 - 9 = ''
// TODO: Old parser expected error on line 3: extraneous code '.' in enum 'case' declaration, Fix-It replacements: 14 - 15 = ''
DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in enum case"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected name in enum case"),
DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '.UE4, .UE5' in enum"),
]
)
Expand All @@ -449,7 +449,7 @@ 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"),
// TODO: Old parser expected error on line 20: expected identifier after comma in enum 'case' declaration
DiagnosticSpec(locationMarker: "3️⃣", message: "expected identifier in enum case"),
DiagnosticSpec(locationMarker: "3️⃣", message: "expected name in enum case"),
]
)
}
Expand Down Expand Up @@ -1330,7 +1330,7 @@ final class EnumTests: XCTestCase {
}
""",
diagnostics: [
DiagnosticSpec(message: "expected identifier in enum case"),
DiagnosticSpec(message: "expected name in enum case"),
// TODO: Old parser expected error on line 5: keyword 'case' cannot be used as an identifier here
// TODO: Old parser expected note on line 5: if this name is unavoidable, use backticks to escape it, Fix-It replacements: 3 - 7 = '`case`'
]
Expand All @@ -1346,7 +1346,7 @@ final class EnumTests: XCTestCase {
}
""",
diagnostics: [
DiagnosticSpec(message: "expected identifier in enum case"),
DiagnosticSpec(message: "expected name in enum case"),
]
)
}
Expand Down Expand Up @@ -1375,9 +1375,9 @@ final class EnumTests: XCTestCase {
"""#,
diagnostics: [
// TODO: Old parser expected error on line 2: expected identifier after comma in enum 'case' declaration
DiagnosticSpec(locationMarker: "1️⃣", message: "expected identifier in enum case"),
DiagnosticSpec(locationMarker: "1️⃣", message: "expected name in enum case"),
// TODO: Old parser expected error on line 3: expected identifier after comma in enum 'case' declaration
DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier in enum case"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected name in enum case"),
]
)
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/SwiftParserTest/translated/InvalidTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ final class InvalidTests: XCTestCase {
// TODO: Old parser expected note on line 1: did you mean to write an 'AnyObject' constraint?, Fix-It replacements: 16 - 21 = 'AnyObject'
DiagnosticSpec(locationMarker: "1️⃣", message: "expected '>' to end generic parameter clause"),
DiagnosticSpec(locationMarker: "1️⃣", message: "expected '{' in struct"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected identifier and member block in class"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected name and member block in class"),
DiagnosticSpec(locationMarker: "2️⃣", message: "expected '}' to end struct"),
DiagnosticSpec(locationMarker: "2️⃣", message: "extraneous code at top level"),
// TODO: Old parser expected error on line 2: 'weak' must be a mutable variable, because it may change at runtime
Expand Down
Loading