Skip to content

Commit f34aaed

Browse files
committed
Emit specialized diagnostic for functions without parameters
rdar://98724207
1 parent 8c76dc3 commit f34aaed

File tree

5 files changed

+67
-1
lines changed

5 files changed

+67
-1
lines changed

Sources/SwiftParser/Declarations.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,9 @@ extension Parser {
10611061
public mutating func parseParameterClause(isClosure: Bool = false) -> RawParameterClauseSyntax {
10621062
let (unexpectedBeforeLParen, lparen) = self.expect(.leftParen)
10631063
var elements = [RawFunctionParameterSyntax]()
1064-
do {
1064+
// If we are missing the left parenthesis and the next token doesn't appear to be an argument label, don't parse any parameters.
1065+
let shouldSkipParameterParsing = lparen.isMissing && (!currentToken.canBeArgumentLabel || currentToken.isKeyword)
1066+
if !shouldSkipParameterParsing {
10651067
var keepGoing = true
10661068
while !self.at(.eof) && !self.at(.rightParen) && keepGoing {
10671069
// Attributes.

Sources/SwiftParser/Diagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,5 +158,16 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
158158
}
159159
return .visitChildren
160160
}
161+
162+
override public func visit(_ node: ParameterClauseSyntax) -> SyntaxVisitorContinueKind {
163+
if shouldSkip(node) {
164+
return .skipChildren
165+
}
166+
if node.leftParen.presence == .missing && node.parameterList.isEmpty && node.rightParen.presence == .missing {
167+
addDiagnostic(node, .missingFunctionParameterClause)
168+
markNodesAsHandled(node.leftParen.id, node.parameterList.id, node.rightParen.id)
169+
}
170+
return .visitChildren
171+
}
161172
}
162173

Sources/SwiftParser/Diagnostics/ParserDiagnosticMessages.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public extension ParserFixIt {
7676
/// Please order the cases in this enum alphabetically by case name.
7777
public enum StaticParserError: String, DiagnosticMessage {
7878
case cStyleForLoop = "C-style for statement has been removed in Swift 3"
79+
case missingFunctionParameterClause = "Expected argument list in function declaration"
7980
case throwsInReturnPosition = "'throws' may only occur before '->'"
8081

8182
public var message: String { self.rawValue }

Tests/SwiftParserTest/DiagnosticTests.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,20 @@ public class DiagnosticTests: XCTestCase {
7777
expectedFixedSource: "() throws -> Int"
7878
)
7979
}
80+
81+
public func testNoParamsForFunction() throws {
82+
let source = """
83+
class MyClass {
84+
func withoutParameters
85+
86+
func withParameters() {}
87+
}
88+
"""
89+
90+
let classDecl = withParser(source: source) {
91+
Syntax(raw: $0.parseDeclaration().raw).as(ClassDeclSyntax.self)!
92+
}
93+
94+
XCTAssertSingleDiagnostic(in: classDecl, line: 2, column: 25, message: "Expected argument list in function declaration")
95+
}
8096
}

Tests/SwiftParserTest/RecoveryTests.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,4 +349,40 @@ public class RecoveryTests: XCTestCase {
349349
"""
350350
}
351351
}
352+
353+
public func testNoParamsForFunction() throws {
354+
let source = """
355+
class MyClass {
356+
func withoutParameters
357+
358+
func withParameters() {}
359+
}
360+
"""
361+
362+
let classDecl = withParser(source: source) {
363+
Syntax(raw: $0.parseDeclaration().raw)
364+
}
365+
try XCTAssertHasSubstructure(
366+
classDecl,
367+
FunctionDeclSyntax(
368+
attributes: nil,
369+
modifiers: nil,
370+
funcKeyword: .funcKeyword(),
371+
identifier: .identifier("withoutParameters"),
372+
genericParameterClause: nil,
373+
signature: FunctionSignatureSyntax(
374+
input: ParameterClauseSyntax(
375+
leftParen: .leftParenToken(presence: .missing),
376+
parameterList: FunctionParameterListSyntax([]),
377+
rightParen: .rightParenToken(presence: .missing)
378+
),
379+
asyncOrReasyncKeyword: nil,
380+
throwsOrRethrowsKeyword: nil,
381+
output: nil
382+
),
383+
genericWhereClause: nil,
384+
body: nil
385+
)
386+
)
387+
}
352388
}

0 commit comments

Comments
 (0)