Compare commits
1 Commits
main
...
marcelo/tu
Author | SHA1 | Date |
---|---|---|
![]() |
3a0973a7d3 |
|
@ -30,6 +30,12 @@
|
|||
`return <expression>` in a function that returns `Void`.
|
||||
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||
|
||||
* Add back `tuple_pattern` rule to warn against assigning variables
|
||||
through a tuple pattern when the left side of the assignment
|
||||
contains labels.
|
||||
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||
[#3466](https://github.com/realm/SwiftLint/issues/3466)
|
||||
|
||||
* Don't skip autocorrect on files that have parser warnings. Only files with
|
||||
errors reported by the Swift parser will be skipped.
|
||||
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||
|
|
|
@ -183,6 +183,7 @@ public let primaryRuleList = RuleList(rules: [
|
|||
TrailingNewlineRule.self,
|
||||
TrailingSemicolonRule.self,
|
||||
TrailingWhitespaceRule.self,
|
||||
TuplePatternRule.self,
|
||||
TypeBodyLengthRule.self,
|
||||
TypeContentsOrderRule.self,
|
||||
TypeNameRule.self,
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
import SourceKittenFramework
|
||||
import SwiftSyntax
|
||||
|
||||
public struct TuplePatternRule: ConfigurationProviderRule, AutomaticTestableRule {
|
||||
public var configuration = SeverityConfiguration(.warning)
|
||||
|
||||
public init() {}
|
||||
|
||||
public static let description = RuleDescription(
|
||||
identifier: "tuple_pattern",
|
||||
name: "Tuple Pattern",
|
||||
description: "Assigning variables through a tuple pattern is only permitted if the left-hand side of the " +
|
||||
"assignment is unlabeled.",
|
||||
kind: .idiomatic,
|
||||
minSwiftVersion: .fiveDotOne,
|
||||
nonTriggeringExamples: [
|
||||
Example("let (a, b) = (y: 4, x: 5.0)"),
|
||||
Example("let (a, b) = (4, 5.0)"),
|
||||
Example("let (a, b) = (a: 4, b: 5.0)"),
|
||||
Example("let (a, b) = tuple")
|
||||
],
|
||||
triggeringExamples: [
|
||||
Example("let ↓(x: a, y: b) = (y: 4, x: 5.0)"),
|
||||
Example("let ↓(x: Int, y: Double) = (y: 4, x: 5.0)"),
|
||||
Example("let ↓(x: Int, y: Double) = (y: 4, x: 5.0)")
|
||||
]
|
||||
)
|
||||
|
||||
public func validate(file: SwiftLintFile) -> [StyleViolation] {
|
||||
guard let syntaxTree = file.syntaxTree else {
|
||||
return []
|
||||
}
|
||||
|
||||
let visitor = TuplePatternVisitor()
|
||||
visitor.walk(syntaxTree)
|
||||
return visitor.violations(for: self, in: file)
|
||||
}
|
||||
}
|
||||
|
||||
private class TuplePatternVisitor: SyntaxVisitor {
|
||||
private var positions = [AbsolutePosition]()
|
||||
|
||||
override func visitPost(_ node: PatternBindingSyntax) {
|
||||
guard let tuplePattern = node.pattern.as(TuplePatternSyntax.self),
|
||||
case let leftSideLabels = tuplePattern.labels,
|
||||
!leftSideLabels.compactMap({ $0 }).isEmpty,
|
||||
let rightSideLabels = node.initializer?.tupleElementList?.labels,
|
||||
leftSideLabels != rightSideLabels else {
|
||||
return
|
||||
}
|
||||
|
||||
positions.append(node.positionAfterSkippingLeadingTrivia)
|
||||
}
|
||||
|
||||
func violations(for rule: TuplePatternRule, in file: SwiftLintFile) -> [StyleViolation] {
|
||||
return positions.map { position in
|
||||
StyleViolation(ruleDescription: type(of: rule).description,
|
||||
severity: rule.configuration.severity,
|
||||
location: Location(file: file, byteOffset: ByteCount(position.utf8Offset)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension TuplePatternSyntax {
|
||||
var labels: [String?] {
|
||||
return elements.map { element in
|
||||
element.labelName?.withoutTrivia().text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension InitializerClauseSyntax {
|
||||
var tupleElementList: TupleExprElementListSyntax? {
|
||||
if let expr = value.as(TupleExprSyntax.self) {
|
||||
return expr.elementList
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private extension TupleExprElementListSyntax {
|
||||
var labels: [String?] {
|
||||
return map { element in
|
||||
element.label?.withoutTrivia().text
|
||||
}
|
||||
}
|
||||
}
|
|
@ -785,6 +785,12 @@ class TrailingSemicolonRuleTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
class TuplePatternRuleTests: XCTestCase {
|
||||
func testWithDefaultConfiguration() {
|
||||
verifyRule(TuplePatternRule.description)
|
||||
}
|
||||
}
|
||||
|
||||
class TypeBodyLengthRuleTests: XCTestCase {
|
||||
func testWithDefaultConfiguration() {
|
||||
verifyRule(TypeBodyLengthRule.description)
|
||||
|
|
Loading…
Reference in New Issue