Skip to content

Commit 583e3d8

Browse files
authored
Merge pull request #959 from ahoppen/ahoppen/deinits-with-name
Add diagnostic if deinits have names and parameters
2 parents a5115a7 + 820768b commit 583e3d8

File tree

7 files changed

+148
-109
lines changed

7 files changed

+148
-109
lines changed

Sources/SwiftParser/Declarations.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,12 +1310,18 @@ extension Parser {
13101310
_ handle: RecoveryConsumptionHandle
13111311
) -> RawDeinitializerDeclSyntax {
13121312
let (unexpectedBeforeDeinitKeyword, deinitKeyword) = self.eat(handle)
1313+
var unexpectedNameAndSignature: [RawSyntax?] = []
1314+
unexpectedNameAndSignature.append(self.consume(if: .identifier, where: { !$0.isAtStartOfLine }).map(RawSyntax.init))
1315+
if self.at(.leftParen) && !self.currentToken.isAtStartOfLine {
1316+
unexpectedNameAndSignature.append(RawSyntax(parseFunctionSignature()))
1317+
}
13131318
let items = self.parseOptionalCodeBlock()
13141319
return RawDeinitializerDeclSyntax(
13151320
attributes: attrs.attributes,
13161321
modifiers: attrs.modifiers,
13171322
unexpectedBeforeDeinitKeyword,
13181323
deinitKeyword: deinitKeyword,
1324+
RawUnexpectedNodesSyntax(unexpectedNameAndSignature, arena: self.arena),
13191325
body: items,
13201326
arena: self.arena
13211327
)

Sources/SwiftParser/Diagnostics/DiagnosticExtensions.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ extension FixIt.Changes {
5252
return FixIt.Changes(changes: changes)
5353
}
5454

55+
static func makeMissing<SyntaxType: SyntaxProtocol>(node: SyntaxType) -> Self {
56+
return FixIt.Changes(changes: [
57+
.replace(oldNode: Syntax(node), newNode: MissingMaker().visit(Syntax(node)))
58+
])
59+
}
60+
5561
/// Remove the nodes in `unexpected`.
5662
static func remove(unexpected: UnexpectedNodesSyntax) -> Self {
5763
var changes: [FixIt.Change] = [

Sources/SwiftParser/Diagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
182182
if shouldSkip(node) {
183183
return .skipChildren
184184
}
185+
if node.allSatisfy({ handledNodes.contains($0.id) }) {
186+
return .skipChildren
187+
}
185188
if let tryKeyword = node.onlyToken(where: { $0.tokenKind == .tryKeyword }),
186189
let nextToken = tryKeyword.nextToken(viewMode: .sourceAccurate),
187190
nextToken.tokenKind.isKeyword {
@@ -447,6 +450,26 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
447450
return .visitChildren
448451
}
449452

453+
public override func visit(_ node: DeinitializerDeclSyntax) -> SyntaxVisitorContinueKind {
454+
if shouldSkip(node) {
455+
return .skipChildren
456+
}
457+
if let unexpected = node.unexpectedBetweenDeinitKeywordAndBody,
458+
let name = unexpected.filter({ $0.as(TokenSyntax.self)?.tokenKind.isIdentifier == true }).only?.as(TokenSyntax.self) {
459+
addDiagnostic(name, .deinitCannotHaveName, fixIts: [
460+
FixIt(message: RemoveNodesFixIt(name), changes: .makeMissing(token: name))
461+
], handledNodes: [name.id])
462+
}
463+
if let unexpected = node.unexpectedBetweenDeinitKeywordAndBody,
464+
let signature = unexpected.compactMap({ $0.as(FunctionSignatureSyntax.self) }).only {
465+
addDiagnostic(signature, .deinitCannotHaveParameters, fixIts: [
466+
FixIt(message: RemoveNodesFixIt(signature), changes: .makeMissing(node: signature))
467+
], handledNodes: [signature.id])
468+
}
469+
470+
return .visitChildren
471+
}
472+
450473
public override func visit(_ node: ForInStmtSyntax) -> SyntaxVisitorContinueKind {
451474
if shouldSkip(node) {
452475
return .skipChildren

Sources/SwiftParser/Diagnostics/ParserDiagnosticMessages.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ public enum StaticParserError: String, DiagnosticMessage {
7474
case cStyleForLoop = "C-style for statement has been removed in Swift 3"
7575
case defaultCannotBeUsedWithWhere = "'default' cannot be used with a 'where' guard expression"
7676
case defaultOutsideOfSwitch = "'default' label can only appear inside a 'switch' statement"
77+
case deinitCannotHaveName = "deinitializers cannot have a name"
78+
case deinitCannotHaveParameters = "deinitializers cannot have parameters"
7779
case editorPlaceholderInSourceFile = "editor placeholder in source file"
7880
case expectedExpressionAfterTry = "expected expression after 'try'"
7981
case invalidFlagAfterPrecedenceGroupAssignment = "expected 'true' or 'false' after 'assignment'"

Sources/SwiftParser/Diagnostics/PresenceUtils.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,12 @@ class PresentMaker: SyntaxRewriter {
124124
))
125125
}
126126
}
127+
128+
class MissingMaker: SyntaxRewriter {
129+
override func visit(_ node: TokenSyntax) -> Syntax {
130+
guard node.presence == .present else {
131+
return Syntax(node)
132+
}
133+
return Syntax(TokenSyntax(node.tokenKind, presence: .missing))
134+
}
135+
}

Tests/SwiftParserTest/translated/AsyncTests.swift

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ final class AsyncTests: XCTestCase {
112112
"""
113113
class X {
114114
init() async { }
115-
deinit1️⃣ async 2️⃣{ }
115+
deinit 1️⃣async { }
116116
func f() async { }
117-
subscript(x: Int) 4️⃣async -> Int {
117+
subscript(x: Int) 2️⃣async -> Int {
118118
get {
119119
return 0
120120
}
@@ -124,15 +124,8 @@ final class AsyncTests: XCTestCase {
124124
}
125125
""",
126126
diagnostics: [
127-
// TODO: Old parser expected error on line 3: deinitializers cannot have a name
128-
DiagnosticSpec(locationMarker: "1️⃣", message: "consecutive declarations on a line must be separated by ';'"),
129-
DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code '{ }' in function"),
130-
// TODO: Old parser expected error on line 5: expected '->' for subscript element type
131-
// TODO: Old parser expected error on line 5: single argument function types require parentheses
132-
// TODO: Old parser expected error on line 5: cannot find type 'async' in scope
133-
// TODO: Old parser expected note on line 5: cannot use module 'async' as a type
134-
DiagnosticSpec(locationMarker: "4️⃣", message: "unexpected code 'async' in subscript"),
135-
// TODO: Old parser expected error on line 9: 'set' accessor cannot have specifier 'async'
127+
DiagnosticSpec(locationMarker: "1️⃣", message: "deinitializers cannot have a name"),
128+
DiagnosticSpec(locationMarker: "2️⃣", message: "unexpected code 'async' in subscript"),
136129
]
137130
)
138131
}

0 commit comments

Comments
 (0)