Skip to content

Commit ae274fa

Browse files
committed
Improve FixIt for function param with missing type
If the `node.secondName` starts with a capital letter, we now assume the user wanted it to be the type of the parameter. This commit makes the following changes to the FixIt of `name1 Name2`: - from `name1 Name2: TypeText` - to `name1: Name2`
1 parent 93e905c commit ae274fa

File tree

4 files changed

+65
-6
lines changed

4 files changed

+65
-6
lines changed

Sources/SwiftParser/Parameters.swift

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,39 @@ extension Parser {
9292
let modifiers = parseParameterModifiers(isClosure: false)
9393
let misplacedSpecifiers = parseMisplacedSpecifiers()
9494

95-
let names = self.parseParameterNames()
96-
let (unexpectedBeforeColon, colon) = self.expect(.colon)
97-
98-
let type = self.parseType(misplacedSpecifiers: misplacedSpecifiers)
95+
var names = self.parseParameterNames()
96+
var (unexpectedBeforeColon, colon) = self.expect(.colon)
97+
98+
let type: RawTypeSyntax
99+
100+
if colon.presence == .missing, let secondName = names.secondName, secondName.tokenText.isStartingWithUppercase {
101+
// Synthesize the secondName parameter as a type node.
102+
type = RawTypeSyntax(
103+
RawSimpleTypeIdentifierSyntax(
104+
name: RawTokenSyntax(
105+
kind: .identifier,
106+
text: secondName.tokenText,
107+
presence: .missing,
108+
arena: self.arena
109+
),
110+
genericArgumentClause: nil,
111+
arena: self.arena
112+
)
113+
)
114+
unexpectedBeforeColon = RawUnexpectedNodesSyntax(
115+
combining: unexpectedBeforeColon, names.secondName,
116+
arena: self.arena
117+
)
118+
names = ParameterNames(
119+
unexpectedBeforeFirstName: names.unexpectedBeforeFirstName,
120+
firstName: names.firstName,
121+
unexpectedBeforeSecondName: nil,
122+
secondName: nil
123+
)
124+
} else {
125+
// Parse the type node as we would normally do.
126+
type = self.parseType(misplacedSpecifiers: misplacedSpecifiers)
127+
}
99128

100129
let ellipsis = self.consumeIfContextualPunctuator("...", remapping: .ellipsis)
101130

Sources/SwiftParserDiagnostics/ParseDiagnosticsGenerator.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,27 @@ public class ParseDiagnosticsGenerator: SyntaxAnyVisitor {
797797
moveFixIt: { MoveTokensInFrontOfTypeFixIt(movedTokens: $0) },
798798
removeRedundantFixIt: { RemoveRedundantFixIt(removeTokens: $0) }
799799
)
800+
if let unexpectedBeforeColon = node.unexpectedBetweenSecondNameAndColon, node.colon.presence == .missing, node.type.isMissingAllTokens {
801+
addDiagnostic(
802+
unexpectedBeforeColon,
803+
StaticParserError.expectedColonAndType,
804+
fixIts: [
805+
FixIt(
806+
message: StaticParserFixIt.insertColonAndType,
807+
changes: [
808+
.makeMissing(unexpectedBeforeColon),
809+
.makePresent(node.colon, leadingTrivia: nil),
810+
.makePresent(node.type)
811+
]
812+
)
813+
],
814+
handledNodes: [
815+
unexpectedBeforeColon.id,
816+
node.colon.id,
817+
node.type.id
818+
]
819+
)
820+
}
800821
return .visitChildren
801822
}
802823

Sources/SwiftParserDiagnostics/ParserDiagnosticMessages.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ extension DiagnosticMessage where Self == StaticParserError {
135135
public static var expectedColonClass: Self {
136136
.init("expected ':' to begin inheritance clause")
137137
}
138+
public static var expectedColonAndType: Self {
139+
.init("expected ':' and type in parameter")
140+
}
138141
public static var expectedExpressionAfterTry: Self {
139142
.init("expected expression after 'try'")
140143
}
@@ -556,6 +559,9 @@ extension FixItMessage where Self == StaticParserFixIt {
556559
public static var insertSemicolon: Self {
557560
.init("insert ';'")
558561
}
562+
public static var insertColonAndType: Self {
563+
.init("insert ':' and type")
564+
}
559565
public static var insertAttributeArguments: Self {
560566
.init("insert attribute argument")
561567
}

Tests/SwiftParserTest/translated/InvalidTests.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,14 +305,17 @@ final class InvalidTests: XCTestCase {
305305
}
306306

307307
func testInvalid13() {
308+
// TODO: Determine if the comment below should be removed.
308309
// https://github.com/apple/swift/issues/43190
309310
// Crash with invalid parameter declaration
311+
312+
// TODO: Remove the trailing trivia from the firstName node (`s` and space).
310313
assertParse(
311314
"""
312315
do {
313316
class Starfish {}
314317
struct Salmon {}
315-
func f(s Starfish1️⃣,
318+
func f(s 1️⃣Starfish,
316319
_ ss: Salmon) -> [Int] {}
317320
func g() { f(Starfish(), Salmon()) }
318321
}
@@ -324,7 +327,7 @@ final class InvalidTests: XCTestCase {
324327
do {
325328
class Starfish {}
326329
struct Salmon {}
327-
func f(s Starfish: <#type#>,
330+
func f(s : Starfish,
328331
_ ss: Salmon) -> [Int] {}
329332
func g() { f(Starfish(), Salmon()) }
330333
}

0 commit comments

Comments
 (0)