Skip to content

Commit 7b7c748

Browse files
committed
Adjustments to split FunctionParameterSyntax into multiple nodes for function parameters, closure parameters and enum parameters
Companion of swiftlang/swift-syntax#1455
1 parent 3dd9b51 commit 7b7c748

9 files changed

+149
-19
lines changed

Sources/SwiftFormat/Pipelines+Generated.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ class LintPipeline: SyntaxVisitor {
5454
return .visitChildren
5555
}
5656

57+
override func visit(_ node: ClosureParameterSyntax) -> SyntaxVisitorContinueKind {
58+
visitIfEnabled(NoLeadingUnderscores.visit, for: node)
59+
return .visitChildren
60+
}
61+
5762
override func visit(_ node: ClosureSignatureSyntax) -> SyntaxVisitorContinueKind {
5863
visitIfEnabled(AlwaysUseLowerCamelCase.visit, for: node)
5964
visitIfEnabled(ReturnVoidInsteadOfEmptyTuple.visit, for: node)
@@ -90,6 +95,11 @@ class LintPipeline: SyntaxVisitor {
9095
return .visitChildren
9196
}
9297

98+
override func visit(_ node: EnumCaseParameterSyntax) -> SyntaxVisitorContinueKind {
99+
visitIfEnabled(NoLeadingUnderscores.visit, for: node)
100+
return .visitChildren
101+
}
102+
93103
override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind {
94104
visitIfEnabled(BeginDocumentationCommentWithOneLineSummary.visit, for: node)
95105
visitIfEnabled(DontRepeatTypeInStaticProperties.visit, for: node)

Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
10951095
// When it's parenthesized, the input is a `ParameterClauseSyntax`. Otherwise, it's a
10961096
// `ClosureParamListSyntax`. The parenthesized version is wrapped in open/close breaks so that
10971097
// the parens create an extra level of indentation.
1098-
if let parameterClause = input.as(ParameterClauseSyntax.self) {
1098+
if let parameterClause = input.as(ClosureParameterClauseSyntax.self) {
10991099
// Whether we should prioritize keeping ") throws -> <return_type>" together. We can only do
11001100
// this if the closure has arguments.
11011101
let keepOutputTogether =
@@ -1114,7 +1114,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
11141114
after(input.lastToken, tokens: .close)
11151115
}
11161116

1117-
arrangeParameterClause(parameterClause, forcesBreakBeforeRightParen: true)
1117+
arrangeClosureParameterClause(parameterClause, forcesBreakBeforeRightParen: true)
11181118
} else {
11191119
// Group around the arguments, but don't use open/close breaks because there are no parens
11201120
// to create a new scope.
@@ -1213,6 +1213,30 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
12131213
return .visitChildren
12141214
}
12151215

1216+
override func visit(_ node: ClosureParameterClauseSyntax) -> SyntaxVisitorContinueKind {
1217+
// Prioritize keeping ") throws -> <return_type>" together. We can only do this if the function
1218+
// has arguments.
1219+
if !node.parameterList.isEmpty && config.prioritizeKeepingFunctionOutputTogether {
1220+
// Due to visitation order, this .open corresponds to a .close added in FunctionDeclSyntax
1221+
// or SubscriptDeclSyntax.
1222+
before(node.rightParen, tokens: .open)
1223+
}
1224+
1225+
return .visitChildren
1226+
}
1227+
1228+
override func visit(_ node: EnumCaseParameterClauseSyntax) -> SyntaxVisitorContinueKind {
1229+
// Prioritize keeping ") throws -> <return_type>" together. We can only do this if the function
1230+
// has arguments.
1231+
if !node.parameterList.isEmpty && config.prioritizeKeepingFunctionOutputTogether {
1232+
// Due to visitation order, this .open corresponds to a .close added in FunctionDeclSyntax
1233+
// or SubscriptDeclSyntax.
1234+
before(node.rightParen, tokens: .open)
1235+
}
1236+
1237+
return .visitChildren
1238+
}
1239+
12161240
override func visit(_ node: ParameterClauseSyntax) -> SyntaxVisitorContinueKind {
12171241
// Prioritize keeping ") throws -> <return_type>" together. We can only do this if the function
12181242
// has arguments.
@@ -1225,6 +1249,37 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
12251249
return .visitChildren
12261250
}
12271251

1252+
override func visit(_ node: ClosureParameterSyntax) -> SyntaxVisitorContinueKind {
1253+
before(node.firstToken, tokens: .open)
1254+
arrangeAttributeList(node.attributes)
1255+
before(
1256+
node.secondName,
1257+
tokens: .break(.continue, newlines: .elective(ignoresDiscretionary: true)))
1258+
after(node.colon, tokens: .break)
1259+
1260+
if let trailingComma = node.trailingComma {
1261+
after(trailingComma, tokens: .close, .break(.same))
1262+
} else {
1263+
after(node.lastToken, tokens: .close)
1264+
}
1265+
return .visitChildren
1266+
}
1267+
1268+
override func visit(_ node: EnumCaseParameterSyntax) -> SyntaxVisitorContinueKind {
1269+
before(node.firstToken, tokens: .open)
1270+
before(
1271+
node.secondName,
1272+
tokens: .break(.continue, newlines: .elective(ignoresDiscretionary: true)))
1273+
after(node.colon, tokens: .break)
1274+
1275+
if let trailingComma = node.trailingComma {
1276+
after(trailingComma, tokens: .close, .break(.same))
1277+
} else {
1278+
after(node.lastToken, tokens: .close)
1279+
}
1280+
return .visitChildren
1281+
}
1282+
12281283
override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind {
12291284
before(node.firstToken, tokens: .open)
12301285
arrangeAttributeList(node.attributes)
@@ -1368,7 +1423,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
13681423
after(node.trailingComma, tokens: .break)
13691424

13701425
if let associatedValue = node.associatedValue {
1371-
arrangeParameterClause(associatedValue, forcesBreakBeforeRightParen: false)
1426+
arrangeEnumCaseParameterClause(associatedValue, forcesBreakBeforeRightParen: false)
13721427
}
13731428

13741429
return .visitChildren
@@ -2645,6 +2700,42 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
26452700
return contentsIterator.next() == nil && !commentPrecedesRightBrace
26462701
}
26472702

2703+
/// Applies formatting to a collection of parameters for a decl.
2704+
///
2705+
/// - Parameters:
2706+
/// - parameters: A node that contains the parameters that can be passed to a decl when its
2707+
/// called.
2708+
/// - forcesBreakBeforeRightParen: Whether a break should be required before the right paren
2709+
/// when the right paren is on a different line than the corresponding left paren.
2710+
private func arrangeClosureParameterClause(
2711+
_ parameters: ClosureParameterClauseSyntax, forcesBreakBeforeRightParen: Bool
2712+
) {
2713+
guard !parameters.parameterList.isEmpty else { return }
2714+
2715+
after(parameters.leftParen, tokens: .break(.open, size: 0), .open(argumentListConsistency()))
2716+
before(
2717+
parameters.rightParen,
2718+
tokens: .break(.close(mustBreak: forcesBreakBeforeRightParen), size: 0), .close)
2719+
}
2720+
2721+
/// Applies formatting to a collection of enum case parameters for a decl.
2722+
///
2723+
/// - Parameters:
2724+
/// - parameters: A node that contains the parameters that can be passed to a decl when its
2725+
/// called.
2726+
/// - forcesBreakBeforeRightParen: Whether a break should be required before the right paren
2727+
/// when the right paren is on a different line than the corresponding left paren.
2728+
private func arrangeEnumCaseParameterClause(
2729+
_ parameters: EnumCaseParameterClauseSyntax, forcesBreakBeforeRightParen: Bool
2730+
) {
2731+
guard !parameters.parameterList.isEmpty else { return }
2732+
2733+
after(parameters.leftParen, tokens: .break(.open, size: 0), .open(argumentListConsistency()))
2734+
before(
2735+
parameters.rightParen,
2736+
tokens: .break(.close(mustBreak: forcesBreakBeforeRightParen), size: 0), .close)
2737+
}
2738+
26482739
/// Applies formatting to a collection of parameters for a decl.
26492740
///
26502741
/// - Parameters:

Sources/SwiftFormatRules/AlwaysUseLowerCamelCase.swift

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,16 @@ public final class AlwaysUseLowerCamelCase: SyntaxLintRule {
8484
diagnoseLowerCamelCaseViolations(
8585
param.name, allowUnderscores: false, description: identifierDescription(for: node))
8686
}
87-
} else if let parameterClause = input.as(ParameterClauseSyntax.self) {
87+
} else if let parameterClause = input.as(ClosureParameterClauseSyntax.self) {
88+
for param in parameterClause.parameterList {
89+
diagnoseLowerCamelCaseViolations(
90+
param.firstName, allowUnderscores: false, description: identifierDescription(for: node))
91+
if let secondName = param.secondName {
92+
diagnoseLowerCamelCaseViolations(
93+
secondName, allowUnderscores: false, description: identifierDescription(for: node))
94+
}
95+
}
96+
} else if let parameterClause = input.as(EnumCaseParameterClauseSyntax.self) {
8897
for param in parameterClause.parameterList {
8998
if let firstName = param.firstName {
9099
diagnoseLowerCamelCaseViolations(
@@ -95,6 +104,15 @@ public final class AlwaysUseLowerCamelCase: SyntaxLintRule {
95104
secondName, allowUnderscores: false, description: identifierDescription(for: node))
96105
}
97106
}
107+
} else if let parameterClause = input.as(ParameterClauseSyntax.self) {
108+
for param in parameterClause.parameterList {
109+
diagnoseLowerCamelCaseViolations(
110+
param.firstName, allowUnderscores: false, description: identifierDescription(for: node))
111+
if let secondName = param.secondName {
112+
diagnoseLowerCamelCaseViolations(
113+
secondName, allowUnderscores: false, description: identifierDescription(for: node))
114+
}
115+
}
98116
}
99117
}
100118
return .visitChildren
@@ -117,10 +135,8 @@ public final class AlwaysUseLowerCamelCase: SyntaxLintRule {
117135
for param in node.signature.input.parameterList {
118136
// These identifiers aren't described using `identifierDescription(for:)` because no single
119137
// node can disambiguate the argument label from the parameter name.
120-
if let label = param.firstName {
121-
diagnoseLowerCamelCaseViolations(
122-
label, allowUnderscores: false, description: "argument label")
123-
}
138+
diagnoseLowerCamelCaseViolations(
139+
param.firstName, allowUnderscores: false, description: "argument label")
124140
if let paramName = param.secondName {
125141
diagnoseLowerCamelCaseViolations(
126142
paramName, allowUnderscores: false, description: "function parameter")

Sources/SwiftFormatRules/AmbiguousTrailingClosureOverload.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public final class AmbiguousTrailingClosureOverload: SyntaxLintRule {
4141
for fn in functions {
4242
let params = fn.signature.input.parameterList
4343
guard let firstParam = params.firstAndOnly else { continue }
44-
guard let type = firstParam.type, type.is(FunctionTypeSyntax.self) else { continue }
44+
guard firstParam.type.is(FunctionTypeSyntax.self) else { continue }
4545
if let mods = fn.modifiers, mods.has(modifier: "static") || mods.has(modifier: "class") {
4646
staticOverloads[fn.identifier.text, default: []].append(fn)
4747
} else {

Sources/SwiftFormatRules/FunctionDeclSyntax+Convenience.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ extension FunctionDeclSyntax {
1616
/// Constructs a name for a function that includes parameter labels, i.e. `foo(_:bar:)`.
1717
var fullDeclName: String {
1818
let params = signature.input.parameterList.map { param in
19-
"\(param.firstName?.text ?? "_"):"
19+
"\(param.firstName.text):"
2020
}
2121
return "\(identifier.text)(\(params.joined()))"
2222
}

Sources/SwiftFormatRules/NoLeadingUnderscores.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,15 @@ public final class NoLeadingUnderscores: SyntaxLintRule {
5656
return .visitChildren
5757
}
5858

59-
public override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind {
59+
public override func visit(_ node: ClosureParameterSyntax) -> SyntaxVisitorContinueKind {
60+
// If both names are provided, we want to check `secondName`, which will be the parameter name
61+
// (in that case, `firstName` is the label). If only one name is present, then it is recorded in
62+
// `firstName`, and it is both the label and the parameter name.
63+
diagnoseIfNameStartsWithUnderscore(node.secondName ?? node.firstName)
64+
return .visitChildren
65+
}
66+
67+
public override func visit(_ node: EnumCaseParameterSyntax) -> SyntaxVisitorContinueKind {
6068
// If both names are provided, we want to check `secondName`, which will be the parameter name
6169
// (in that case, `firstName` is the label). If only one name is present, then it is recorded in
6270
// `firstName`, and it is both the label and the parameter name.
@@ -66,6 +74,14 @@ public final class NoLeadingUnderscores: SyntaxLintRule {
6674
return .visitChildren
6775
}
6876

77+
public override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind {
78+
// If both names are provided, we want to check `secondName`, which will be the parameter name
79+
// (in that case, `firstName` is the label). If only one name is present, then it is recorded in
80+
// `firstName`, and it is both the label and the parameter name.
81+
diagnoseIfNameStartsWithUnderscore(node.secondName ?? node.firstName)
82+
return .visitChildren
83+
}
84+
6985
public override func visit(_ node: GenericParameterSyntax) -> SyntaxVisitorContinueKind {
7086
diagnoseIfNameStartsWithUnderscore(node.name)
7187
return .visitChildren

Sources/SwiftFormatRules/UseSynthesizedInitializer.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,7 @@ public final class UseSynthesizedInitializer: SyntaxLintRule {
106106
guard parameters.count == properties.count else { return false }
107107
for (idx, parameter) in parameters.enumerated() {
108108

109-
guard let paramId = parameter.firstName, parameter.secondName == nil else { return false }
110-
guard let paramType = parameter.type else { return false }
109+
guard parameter.secondName == nil else { return false }
111110

112111
let property = properties[idx]
113112
let propertyId = property.firstIdentifier
@@ -124,9 +123,9 @@ public final class UseSynthesizedInitializer: SyntaxLintRule {
124123
return false
125124
}
126125

127-
if propertyId.identifier.text != paramId.text
126+
if propertyId.identifier.text != parameter.firstName.text
128127
|| propertyType.description.trimmingCharacters(
129-
in: .whitespaces) != paramType.description.trimmingCharacters(in: .whitespacesAndNewlines)
128+
in: .whitespaces) != parameter.type.description.trimmingCharacters(in: .whitespacesAndNewlines)
130129
{ return false }
131130
}
132131
return true

Sources/SwiftFormatRules/ValidateDocumentationComments.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,7 @@ fileprivate func funcParametersIdentifiers(in paramList: FunctionParameterListSy
140140
// If there is a label and an identifier, then the identifier (`secondName`) is the name that
141141
// should be documented. Otherwise, the label and identifier are the same, occupying
142142
// `firstName`.
143-
guard let parameterIdentifier = parameter.secondName ?? parameter.firstName else {
144-
continue
145-
}
143+
let parameterIdentifier = parameter.secondName ?? parameter.firstName
146144
funcParameters.append(parameterIdentifier.text)
147145
}
148146
return funcParameters

Sources/generate-pipeline/RuleCollector.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ final class RuleCollector {
125125
guard let function = member.decl.as(FunctionDeclSyntax.self) else { continue }
126126
guard function.identifier.text == "visit" else { continue }
127127
let params = function.signature.input.parameterList
128-
guard let firstType = params.firstAndOnly?.type?.as(SimpleTypeIdentifierSyntax.self) else {
128+
guard let firstType = params.firstAndOnly?.type.as(SimpleTypeIdentifierSyntax.self) else {
129129
continue
130130
}
131131
visitedNodes.append(firstType.name.text)

0 commit comments

Comments
 (0)