mirror of
https://github.com/realm/SwiftLint.git
synced 2026-06-06 20:18:40 +00:00
Merge pull request #1285 from marcelofabri/unused_enumerated_index
unused_enumerated should check if only index is used
This commit is contained in:
@@ -41,6 +41,11 @@
|
||||
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||
[#1228](https://github.com/realm/SwiftLint/issues/1228)
|
||||
|
||||
* `unused_enumerated` rule now warns when only the index is being used.
|
||||
You should use `.indices` instead of `.enumerated()` in this case.
|
||||
[Marcelo Fabri](https://github.com/marcelofabri)
|
||||
[#1278](https://github.com/realm/SwiftLint/issues/1278)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* Fix a false positive on `large_tuple` rule when using closures.
|
||||
|
||||
@@ -17,19 +17,22 @@ public struct UnusedEnumeratedRule: ASTRule, ConfigurationProviderRule {
|
||||
public static let description = RuleDescription(
|
||||
identifier: "unused_enumerated",
|
||||
name: "Unused Enumerated",
|
||||
description: "When the index is not used, .enumerated() can be removed.",
|
||||
description: "When the index or the item is not used, `.enumerated()` can be removed.",
|
||||
nonTriggeringExamples: [
|
||||
"for (idx, foo) in bar.enumerated() { }\n",
|
||||
"for (_, foo) in bar.enumerated().something() { }\n",
|
||||
"for (_, foo) in bar.something() { }\n",
|
||||
"for foo in bar.enumerated() { }\n",
|
||||
"for foo in bar { }\n",
|
||||
"for (idx, _) in bar.enumerated() { }\n"
|
||||
"for (idx, _) in bar.enumerated().something() { }\n",
|
||||
"for (idx, _) in bar.something() { }\n",
|
||||
"for idx in bar.indices { }\n"
|
||||
],
|
||||
triggeringExamples: [
|
||||
"for (↓_, foo) in bar.enumerated() { }\n",
|
||||
"for (↓_, foo) in abc.bar.enumerated() { }\n",
|
||||
"for (↓_, foo) in abc.something().enumerated() { }\n"
|
||||
"for (↓_, foo) in abc.something().enumerated() { }\n",
|
||||
"for (idx, ↓_) in bar.enumerated() { }\n"
|
||||
]
|
||||
)
|
||||
|
||||
@@ -39,20 +42,39 @@ public struct UnusedEnumeratedRule: ASTRule, ConfigurationProviderRule {
|
||||
guard kind == .forEach,
|
||||
isEnumeratedCall(dictionary: dictionary),
|
||||
let byteRange = byteRangeForVariables(dictionary: dictionary),
|
||||
let firstToken = file.syntaxMap.tokens(inByteRange: byteRange).first,
|
||||
firstToken.length == 1,
|
||||
SyntaxKind(rawValue: firstToken.type) == .keyword,
|
||||
isUnderscore(file: file, token: firstToken) else {
|
||||
case let tokens = file.syntaxMap.tokens(inByteRange: byteRange),
|
||||
tokens.count > 1,
|
||||
let lastToken = tokens.last,
|
||||
case let firstTokenIsUnderscore = isTokenUnderscore(tokens[0], file: file),
|
||||
case let lastTokenIsUnderscore = isTokenUnderscore(lastToken, file: file),
|
||||
firstTokenIsUnderscore || lastTokenIsUnderscore else {
|
||||
return []
|
||||
}
|
||||
|
||||
let offset: Int
|
||||
let reason: String
|
||||
if firstTokenIsUnderscore {
|
||||
offset = tokens[0].offset
|
||||
reason = "When the index is not used, `.enumerated()` can be removed."
|
||||
} else {
|
||||
offset = lastToken.offset
|
||||
reason = "When the item is not used, `.indices` should be used instead of `.enumerated()`."
|
||||
}
|
||||
|
||||
return [
|
||||
StyleViolation(ruleDescription: type(of: self).description,
|
||||
severity: configuration.severity,
|
||||
location: Location(file: file, byteOffset: firstToken.offset))
|
||||
location: Location(file: file, byteOffset: offset),
|
||||
reason: reason)
|
||||
]
|
||||
}
|
||||
|
||||
private func isTokenUnderscore(_ token: SyntaxToken, file: File) -> Bool {
|
||||
return token.length == 1 &&
|
||||
SyntaxKind(rawValue: token.type) == .keyword &&
|
||||
isUnderscore(file: file, token: token)
|
||||
}
|
||||
|
||||
private func isEnumeratedCall(dictionary: [String: SourceKitRepresentable]) -> Bool {
|
||||
for subDict in dictionary.substructure {
|
||||
guard let kindString = subDict.kind,
|
||||
@@ -75,9 +97,8 @@ public struct UnusedEnumeratedRule: ASTRule, ConfigurationProviderRule {
|
||||
}
|
||||
|
||||
let expectedKind = "source.lang.swift.structure.elem.id"
|
||||
for subDict in elements {
|
||||
guard subDict.kind == expectedKind,
|
||||
let offset = subDict.offset,
|
||||
for subDict in elements where subDict.kind == expectedKind {
|
||||
guard let offset = subDict.offset,
|
||||
let length = subDict.length else {
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user