Files
SwiftLint/Source/SwiftLintFramework/Rules/Performance/EmptyStringRule.swift
T
JP Simard 48fde2321f Rewrite contains_over_first_not_nil & last_where with SwiftSyntax (#4366)
Replace `MemberAccessExprSyntax.functionCallBase` with
`ExprSyntax.asFunctionCall` so we can use it in more places.

Move `TokenKind.isEqualityComparison` into `SwiftSyntax+SwiftLint.swift`
2022-10-13 15:59:30 +00:00

52 lines
1.8 KiB
Swift

import SwiftSyntax
public struct EmptyStringRule: ConfigurationProviderRule, OptInRule, SwiftSyntaxRule {
public var configuration = SeverityConfiguration(.warning)
public init() {}
public static let description = RuleDescription(
identifier: "empty_string",
name: "Empty String",
description: "Prefer checking `isEmpty` over comparing `string` to an empty string literal.",
kind: .performance,
nonTriggeringExamples: [
Example("myString.isEmpty"),
Example("!myString.isEmpty"),
Example("\"\"\"\nfoo==\n\"\"\"")
],
triggeringExamples: [
Example(#"myString↓ == """#),
Example(#"myString↓ != """#),
Example(#"myString↓=="""#),
Example(##"myString↓ == #""#"##),
Example(###"myString↓ == ##""##"###)
]
)
public func makeVisitor(file: SwiftLintFile) -> ViolationsSyntaxVisitor? {
Visitor(viewMode: .sourceAccurate)
}
}
private extension EmptyStringRule {
final class Visitor: SyntaxVisitor, ViolationsSyntaxVisitor {
private(set) var violationPositions: [AbsolutePosition] = []
override func visitPost(_ node: StringLiteralExprSyntax) {
guard
// Empty string literal: `""`, `#""#`, etc.
node.segments.count == 1 && node.segments.first?.contentLength == .zero,
let previousToken = node.previousToken,
// On the rhs of an `==` or `!=` operator
previousToken.tokenKind.isEqualityComparison,
let violationPosition = previousToken.previousToken?.endPositionBeforeTrailingTrivia
else {
return
}
violationPositions.append(violationPosition)
}
}
}