|
| 1 | +import SwiftLintCore |
1 | 2 | import SwiftSyntax |
2 | 3 |
|
3 | 4 | @SwiftSyntaxRule(foldExpressions:true) |
4 | | -structEmptyCountRule:OptInRule{ |
| 5 | +structEmptyCountRule:SwiftSyntaxCorrectableRule,OptInRule{ |
5 | 6 | varconfiguration=EmptyCountConfiguration() |
6 | 7 |
|
7 | 8 | staticletdescription=RuleDescription( |
@@ -31,31 +32,95 @@ struct EmptyCountRule: OptInRule { |
31 | 32 | Example("[Int]().↓count == 0b00"), |
32 | 33 | Example("[Int]().↓count == 0o00"), |
33 | 34 | Example("↓count == 0") |
| 35 | +], |
| 36 | + corrections:[ |
| 37 | +Example("[].↓count == 0"): |
| 38 | +Example("[].isEmpty"), |
| 39 | +Example("0 == [].↓count"): |
| 40 | +Example("[].isEmpty"), |
| 41 | +Example("[Int]().↓count == 0"): |
| 42 | +Example("[Int]().isEmpty"), |
| 43 | +Example("0 == [Int]().↓count"): |
| 44 | +Example("[Int]().isEmpty"), |
| 45 | +Example("[Int]().↓count==0"): |
| 46 | +Example("[Int]().isEmpty"), |
| 47 | +Example("[Int]().↓count > 0"): |
| 48 | +Example("![Int]().isEmpty"), |
| 49 | +Example("[Int]().↓count != 0"): |
| 50 | +Example("![Int]().isEmpty"), |
| 51 | +Example("[Int]().↓count == 0x0"): |
| 52 | +Example("[Int]().isEmpty"), |
| 53 | +Example("[Int]().↓count == 0x00_00"): |
| 54 | +Example("[Int]().isEmpty"), |
| 55 | +Example("[Int]().↓count == 0b00"): |
| 56 | +Example("[Int]().isEmpty"), |
| 57 | +Example("[Int]().↓count == 0o00"): |
| 58 | +Example("[Int]().isEmpty"), |
| 59 | +Example("↓count == 0"): |
| 60 | +Example("isEmpty"), |
| 61 | +Example("↓count == 0 && [Int]().↓count == 0o00"): |
| 62 | +Example("isEmpty && [Int]().isEmpty"), |
| 63 | +Example("[Int]().count != 3 && [Int]().↓count != 0 || ↓count == 0 && [Int]().count > 2"): |
| 64 | +Example("[Int]().count != 3 && ![Int]().isEmpty || isEmpty && [Int]().count > 2") |
34 | 65 | ] |
35 | 66 | ) |
| 67 | + |
| 68 | +func makeRewriter(file:SwiftLintFile)->(someViolationsSyntaxRewriter)?{ |
| 69 | +Rewriter( |
| 70 | + configuration: configuration, |
| 71 | + locationConverter: file.locationConverter, |
| 72 | + disabledRegions:disabledRegions(file: file) |
| 73 | +) |
| 74 | +} |
36 | 75 | } |
37 | 76 |
|
38 | 77 | privateextensionEmptyCountRule{ |
39 | 78 | finalclassVisitor:ViolationsSyntaxVisitor<ConfigurationType>{ |
40 | | -privateletoperators:Set=["==","!=",">",">=","<","<="] |
41 | | - |
42 | 79 | overridefunc visitPost(_ node:InfixOperatorExprSyntax){ |
43 | | -guardlet operatorNode= node.operator.as(BinaryOperatorExprSyntax.self), |
44 | | -let binaryOperator= operatorNode.operator.binaryOperator, |
45 | | - operators.contains(binaryOperator)else{ |
| 80 | +guardlet binaryOperator= node.binaryOperator, binaryOperator.isComparisonelse{ |
46 | 81 | return |
47 | 82 | } |
48 | 83 |
|
49 | | -iflet intExpr= node.rightOperand.as(IntegerLiteralExprSyntax.self), intExpr.isZero, |
50 | | -let position= node.leftOperand.countCallPosition(onlyAfterDot: configuration.onlyAfterDot){ |
| 84 | +iflet(_, position)= node.countNodeAndPosition(onlyAfterDot: configuration.onlyAfterDot){ |
51 | 85 | violations.append(position) |
52 | | -return |
53 | 86 | } |
| 87 | +} |
| 88 | +} |
54 | 89 |
|
55 | | -iflet intExpr= node.leftOperand.as(IntegerLiteralExprSyntax.self), intExpr.isZero, |
56 | | -let position= node.rightOperand.countCallPosition(onlyAfterDot: configuration.onlyAfterDot){ |
57 | | - violations.append(position) |
| 90 | +finalclassRewriter:ViolationsSyntaxRewriter{ |
| 91 | +privateletconfiguration:EmptyCountConfiguration |
| 92 | + |
| 93 | +init(configuration:EmptyCountConfiguration, |
| 94 | + locationConverter:SourceLocationConverter, |
| 95 | + disabledRegions:[SourceRange]){ |
| 96 | +self.configuration= configuration |
| 97 | + super.init(locationConverter: locationConverter, disabledRegions: disabledRegions) |
| 98 | +} |
| 99 | + |
| 100 | +overridefunc visit(_ node:InfixOperatorExprSyntax)->ExprSyntax{ |
| 101 | +guardlet binaryOperator= node.binaryOperator, binaryOperator.isComparisonelse{ |
| 102 | +return super.visit(node) |
| 103 | +} |
| 104 | + |
| 105 | +iflet(count, position)= node.countNodeAndPosition(onlyAfterDot: configuration.onlyAfterDot){ |
| 106 | +letnewNode= |
| 107 | +iflet count= count.as(MemberAccessExprSyntax.self){ |
| 108 | + count.with(\.declName.baseName,"isEmpty").trimmed.as(ExprSyntax.self) |
| 109 | +}else{ |
| 110 | + count.as(DeclReferenceExprSyntax.self)?.with(\.baseName,"isEmpty").trimmed.as(ExprSyntax.self) |
| 111 | +} |
| 112 | +guardlet newNodeelse{return super.visit(node)} |
| 113 | + correctionPositions.append(position) |
58 | 114 | return |
| 115 | +if["!=","<",">"].contains(binaryOperator){ |
| 116 | + newNode.negated |
| 117 | +.withTrivia(from: node) |
| 118 | +}else{ |
| 119 | + newNode |
| 120 | +.withTrivia(from: node) |
| 121 | +} |
| 122 | +}else{ |
| 123 | +return super.visit(node) |
59 | 124 | } |
60 | 125 | } |
61 | 126 | } |
@@ -89,3 +154,42 @@ private extension TokenSyntax { |
89 | 154 | } |
90 | 155 | } |
91 | 156 | } |
| 157 | + |
| 158 | +privateextensionExprSyntaxProtocol{ |
| 159 | +varnegated:ExprSyntax{ |
| 160 | +ExprSyntax(PrefixOperatorExprSyntax(operator:.prefixOperator("!"), expression:self)) |
| 161 | +} |
| 162 | +} |
| 163 | + |
| 164 | +privateextensionSyntaxProtocol{ |
| 165 | +func withTrivia(from node:someSyntaxProtocol)->Self{ |
| 166 | +self |
| 167 | +.with(\.leadingTrivia, node.leadingTrivia) |
| 168 | +.with(\.trailingTrivia, node.trailingTrivia) |
| 169 | +} |
| 170 | +} |
| 171 | + |
| 172 | +privateextensionInfixOperatorExprSyntax{ |
| 173 | +func countNodeAndPosition(onlyAfterDot:Bool)->(ExprSyntax,AbsolutePosition)?{ |
| 174 | +iflet intExpr= rightOperand.as(IntegerLiteralExprSyntax.self), intExpr.isZero, |
| 175 | +let position= leftOperand.countCallPosition(onlyAfterDot: onlyAfterDot){ |
| 176 | +return(leftOperand, position) |
| 177 | +}elseiflet intExpr= leftOperand.as(IntegerLiteralExprSyntax.self), intExpr.isZero, |
| 178 | +let position= rightOperand.countCallPosition(onlyAfterDot: onlyAfterDot){ |
| 179 | +return(rightOperand, position) |
| 180 | +}else{ |
| 181 | +returnnil |
| 182 | +} |
| 183 | +} |
| 184 | + |
| 185 | +varbinaryOperator:String?{ |
| 186 | +self.operator.as(BinaryOperatorExprSyntax.self)?.operator.binaryOperator |
| 187 | +} |
| 188 | +} |
| 189 | + |
| 190 | +privateextensionString{ |
| 191 | +privatestaticletoperators:Set=["==","!=",">",">=","<","<="] |
| 192 | +varisComparison:Bool{ |
| 193 | +String.operators.contains(self) |
| 194 | +} |
| 195 | +} |