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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions Sources/SwiftParserDiagnostics/MissingNodesError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,28 @@ func nodesDescriptionAndCommonParent(
return (nil, formatDescriptions(partDescriptions))
}

/// Like `nodesDescriptionAndCommonParent`, but applies special-case overrides
/// for missing-node arrangements whose surrounding context would otherwise
/// produce a misleading description.
private func missingNodesDescriptionAndCommonParent(
_ missingNodes: [Syntax],
format: Bool
) -> (commonAncestor: Syntax?, description: String) {
// When producing a description for a single `MissingDeclSyntax` that already
// carries attributes or modifiers, the parser has committed to "this should
// be a declaration"; describe it that way directly. The general climb logic
// in `nodesDescriptionAndCommonParent` would otherwise pick up the surrounding
// container's slot name (e.g. "statements" for a code block), which is accurate
// to the grammar but misleading as a description of the missing element.
if missingNodes.count == 1,
let missingDecl = missingNodes.first?.as(MissingDeclSyntax.self),
!missingDecl.attributes.isEmpty || !missingDecl.modifiers.isEmpty
{
return (nil, "declaration")
}
return nodesDescriptionAndCommonParent(missingNodes, format: format)
}

/// Formats an array of descriptions into a single string.
///
/// This function takes an array of descriptions and formats them into a single string. Depending on the number
Expand Down Expand Up @@ -337,7 +359,7 @@ public struct MissingNodesError: ParserError {
}

public var message: String {
let (anchor, description) = nodesDescriptionAndCommonParent(missingNodes, format: true)
let (anchor, description) = missingNodesDescriptionAndCommonParent(missingNodes, format: true)
var message = "expected \(description)"
if let afterClause {
message += " \(afterClause)"
Expand Down Expand Up @@ -367,7 +389,9 @@ public struct InsertTokenFixIt: ParserFixIt {
self.missingNodes = missingNodes
}

public var message: String { "insert \(nodesDescription(missingNodes, format: true))" }
public var message: String {
"insert \(missingNodesDescriptionAndCommonParent(missingNodes, format: true).description)"
}
}

// MARK: - Generate Error
Expand Down
3 changes: 1 addition & 2 deletions Tests/SwiftParserTest/translated/RecoveryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3419,8 +3419,7 @@ final class RecoveryTests: ParserTestCase {
),
]),
diagnostics: [
// FIXME: expected *declaration* after attribute
DiagnosticSpec(message: "expected statements after attribute", fixIts: ["insert statements"])
DiagnosticSpec(message: "expected declaration after attribute", fixIts: ["insert declaration"])
],
fixedSource: """
func foo() {
Expand Down