Skip to content

Commit

Permalink
Adjustments to split FunctionParameterSyntax into multiple nodes fo…
Browse files Browse the repository at this point in the history
…r function parameters, closure parameters and enum parameters

Companion of swiftlang/swift-syntax#1455
  • Loading branch information
ahoppen committed Mar 31, 2023
1 parent 89a0b6f commit 0d22a27
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 20 deletions.
10 changes: 10 additions & 0 deletions Sources/SwiftFormat/Pipelines+Generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ class LintPipeline: SyntaxVisitor {
return .visitChildren
}

override func visit(_ node: ClosureParameterSyntax) -> SyntaxVisitorContinueKind {
visitIfEnabled(NoLeadingUnderscores.visit, for: node)
return .visitChildren
}

override func visit(_ node: ClosureSignatureSyntax) -> SyntaxVisitorContinueKind {
visitIfEnabled(AlwaysUseLowerCamelCase.visit, for: node)
visitIfEnabled(ReturnVoidInsteadOfEmptyTuple.visit, for: node)
Expand Down Expand Up @@ -92,6 +97,11 @@ class LintPipeline: SyntaxVisitor {
return .visitChildren
}

override func visit(_ node: EnumCaseParameterSyntax) -> SyntaxVisitorContinueKind {
visitIfEnabled(NoLeadingUnderscores.visit, for: node)
return .visitChildren
}

override func visit(_ node: EnumDeclSyntax) -> SyntaxVisitorContinueKind {
visitIfEnabled(BeginDocumentationCommentWithOneLineSummary.visit, for: node)
visitIfEnabled(DontRepeatTypeInStaticProperties.visit, for: node)
Expand Down
51 changes: 50 additions & 1 deletion Sources/SwiftFormatPrettyPrint/TokenStreamCreator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,37 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
return .visitChildren
}

override func visit(_ node: ClosureParameterSyntax) -> SyntaxVisitorContinueKind {
before(node.firstToken, tokens: .open)
arrangeAttributeList(node.attributes)
before(
node.secondName,
tokens: .break(.continue, newlines: .elective(ignoresDiscretionary: true)))
after(node.colon, tokens: .break)

if let trailingComma = node.trailingComma {
after(trailingComma, tokens: .close, .break(.same))
} else {
after(node.lastToken, tokens: .close)
}
return .visitChildren
}

override func visit(_ node: EnumCaseParameterSyntax) -> SyntaxVisitorContinueKind {
before(node.firstToken, tokens: .open)
before(
node.secondName,
tokens: .break(.continue, newlines: .elective(ignoresDiscretionary: true)))
after(node.colon, tokens: .break)

if let trailingComma = node.trailingComma {
after(trailingComma, tokens: .close, .break(.same))
} else {
after(node.lastToken, tokens: .close)
}
return .visitChildren
}

override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind {
before(node.firstToken, tokens: .open)
arrangeAttributeList(node.attributes)
Expand Down Expand Up @@ -1413,7 +1444,7 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
after(node.trailingComma, tokens: .break)

if let associatedValue = node.associatedValue {
arrangeParameterClause(associatedValue, forcesBreakBeforeRightParen: false)
arrangeEnumCaseParameterClause(associatedValue, forcesBreakBeforeRightParen: false)
}

return .visitChildren
Expand Down Expand Up @@ -2606,6 +2637,24 @@ fileprivate final class TokenStreamCreator: SyntaxVisitor {
tokens: .break(.close(mustBreak: forcesBreakBeforeRightParen), size: 0), .close)
}

/// Applies formatting to a collection of enum case parameters for a decl.
///
/// - Parameters:
/// - parameters: A node that contains the parameters that can be passed to a decl when its
/// called.
/// - forcesBreakBeforeRightParen: Whether a break should be required before the right paren
/// when the right paren is on a different line than the corresponding left paren.
private func arrangeEnumCaseParameterClause(
_ parameters: EnumCaseParameterClauseSyntax, forcesBreakBeforeRightParen: Bool
) {
guard !parameters.parameterList.isEmpty else { return }

after(parameters.leftParen, tokens: .break(.open, size: 0), .open(argumentListConsistency()))
before(
parameters.rightParen,
tokens: .break(.close(mustBreak: forcesBreakBeforeRightParen), size: 0), .close)
}

/// Applies consistent formatting to the braces and contents of the given node.
///
/// - Parameters:
Expand Down
12 changes: 4 additions & 8 deletions Sources/SwiftFormatRules/AlwaysUseLowerCamelCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,8 @@ public final class AlwaysUseLowerCamelCase: SyntaxLintRule {
}
} else if let parameterClause = input.as(ParameterClauseSyntax.self) {
for param in parameterClause.parameterList {
if let firstName = param.firstName {
diagnoseLowerCamelCaseViolations(
firstName, allowUnderscores: false, description: identifierDescription(for: node))
}
diagnoseLowerCamelCaseViolations(
param.firstName, allowUnderscores: false, description: identifierDescription(for: node))
if let secondName = param.secondName {
diagnoseLowerCamelCaseViolations(
secondName, allowUnderscores: false, description: identifierDescription(for: node))
Expand Down Expand Up @@ -106,10 +104,8 @@ public final class AlwaysUseLowerCamelCase: SyntaxLintRule {
for param in node.signature.input.parameterList {
// These identifiers aren't described using `identifierDescription(for:)` because no single
// node can disambiguate the argument label from the parameter name.
if let label = param.firstName {
diagnoseLowerCamelCaseViolations(
label, allowUnderscores: false, description: "argument label")
}
diagnoseLowerCamelCaseViolations(
param.firstName, allowUnderscores: false, description: "argument label")
if let paramName = param.secondName {
diagnoseLowerCamelCaseViolations(
paramName, allowUnderscores: false, description: "function parameter")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public final class AmbiguousTrailingClosureOverload: SyntaxLintRule {
for fn in functions {
let params = fn.signature.input.parameterList
guard let firstParam = params.firstAndOnly else { continue }
guard let type = firstParam.type, type.is(FunctionTypeSyntax.self) else { continue }
guard firstParam.type.is(FunctionTypeSyntax.self) else { continue }
if let mods = fn.modifiers, mods.has(modifier: "static") || mods.has(modifier: "class") {
staticOverloads[fn.identifier.text, default: []].append(fn)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ extension FunctionDeclSyntax {
/// Constructs a name for a function that includes parameter labels, i.e. `foo(_:bar:)`.
var fullDeclName: String {
let params = signature.input.parameterList.map { param in
"\(param.firstName?.text ?? "_"):"
"\(param.firstName.text):"
}
return "\(identifier.text)(\(params.joined()))"
}
Expand Down
18 changes: 17 additions & 1 deletion Sources/SwiftFormatRules/NoLeadingUnderscores.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,15 @@ public final class NoLeadingUnderscores: SyntaxLintRule {
return .visitChildren
}

public override func visit(_ node: FunctionParameterSyntax) -> SyntaxVisitorContinueKind {
public override func visit(_ node: ClosureParameterSyntax) -> SyntaxVisitorContinueKind {
// If both names are provided, we want to check `secondName`, which will be the parameter name
// (in that case, `firstName` is the label). If only one name is present, then it is recorded in
// `firstName`, and it is both the label and the parameter name.
diagnoseIfNameStartsWithUnderscore(node.secondName ?? node.firstName)
return .visitChildren
}

public override func visit(_ node: EnumCaseParameterSyntax) -> SyntaxVisitorContinueKind {
// If both names are provided, we want to check `secondName`, which will be the parameter name
// (in that case, `firstName` is the label). If only one name is present, then it is recorded in
// `firstName`, and it is both the label and the parameter name.
Expand All @@ -66,6 +74,14 @@ public final class NoLeadingUnderscores: SyntaxLintRule {
return .visitChildren
}

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

public override func visit(_ node: GenericParameterSyntax) -> SyntaxVisitorContinueKind {
diagnoseIfNameStartsWithUnderscore(node.name)
return .visitChildren
Expand Down
7 changes: 3 additions & 4 deletions Sources/SwiftFormatRules/UseSynthesizedInitializer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ public final class UseSynthesizedInitializer: SyntaxLintRule {
guard parameters.count == properties.count else { return false }
for (idx, parameter) in parameters.enumerated() {

guard let paramId = parameter.firstName, parameter.secondName == nil else { return false }
guard let paramType = parameter.type else { return false }
guard parameter.secondName == nil else { return false }

let property = properties[idx]
let propertyId = property.firstIdentifier
Expand All @@ -124,9 +123,9 @@ public final class UseSynthesizedInitializer: SyntaxLintRule {
return false
}

if propertyId.identifier.text != paramId.text
if propertyId.identifier.text != parameter.firstName.text
|| propertyType.description.trimmingCharacters(
in: .whitespaces) != paramType.description.trimmingCharacters(in: .whitespacesAndNewlines)
in: .whitespaces) != parameter.type.description.trimmingCharacters(in: .whitespacesAndNewlines)
{ return false }
}
return true
Expand Down
4 changes: 1 addition & 3 deletions Sources/SwiftFormatRules/ValidateDocumentationComments.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,7 @@ fileprivate func funcParametersIdentifiers(in paramList: FunctionParameterListSy
// If there is a label and an identifier, then the identifier (`secondName`) is the name that
// should be documented. Otherwise, the label and identifier are the same, occupying
// `firstName`.
guard let parameterIdentifier = parameter.secondName ?? parameter.firstName else {
continue
}
let parameterIdentifier = parameter.secondName ?? parameter.firstName
funcParameters.append(parameterIdentifier.text)
}
return funcParameters
Expand Down
2 changes: 1 addition & 1 deletion Sources/generate-pipeline/RuleCollector.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ final class RuleCollector {
guard let function = member.decl.as(FunctionDeclSyntax.self) else { continue }
guard function.identifier.text == "visit" else { continue }
let params = function.signature.input.parameterList
guard let firstType = params.firstAndOnly?.type?.as(SimpleTypeIdentifierSyntax.self) else {
guard let firstType = params.firstAndOnly?.type.as(SimpleTypeIdentifierSyntax.self) else {
continue
}
visitedNodes.append(firstType.name.text)
Expand Down

0 comments on commit 0d22a27

Please sign in to comment.