Skip to content

Commit

Permalink
Fix false positives in array_init rule with prefix operators
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelofabri authored and sjavora committed Mar 9, 2019
1 parent 91e3964 commit fc76d89
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
[Marcelo Fabri](https://github.com/marcelofabri)
[#2159](https://github.com/realm/SwiftLint/issues/2159)

* Fix false positives on `array_init` rule when using prefix operators.
[Marcelo Fabri](https://github.com/marcelofabri)
[#1877](https://github.com/realm/SwiftLint/issues/1877)

## 0.30.0: A New Washer and Dryer Set

#### Breaking
Expand Down
15 changes: 15 additions & 0 deletions Rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,16 @@ foo.something { RouteMapper.map($0) }

```

```swift
foo.map { !$0 }

```

```swift
foo.map { /* a comment */ !$0 }

```

</details>
<details>
<summary>Triggering Examples</summary>
Expand Down Expand Up @@ -328,6 +338,11 @@ foo.something { RouteMapper.map($0) }

```

```swift
↓foo.map { /* a comment */ $0 }

```

</details>


Expand Down
44 changes: 38 additions & 6 deletions Source/SwiftLintFramework/Rules/Lint/ArrayInitRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ public struct ArrayInitRule: ASTRule, ConfigurationProviderRule, OptInRule, Auto
"foo.map { ((), $0) }\n",
"foo.map { $0! }\n",
"foo.map { $0! /* force unwrap */ }\n",
"foo.something { RouteMapper.map($0) }\n"
"foo.something { RouteMapper.map($0) }\n",
"foo.map { !$0 }\n",
"foo.map { /* a comment */ !$0 }\n"
],
triggeringExamples: [
"↓foo.map({ $0 })\n",
Expand All @@ -37,7 +39,8 @@ public struct ArrayInitRule: ASTRule, ConfigurationProviderRule, OptInRule, Auto
"↓foo.map { elem -> String in\n" +
" elem\n" +
"}\n",
"↓foo.map { $0 /* a comment */ }\n"
"↓foo.map { $0 /* a comment */ }\n",
"↓foo.map { /* a comment */ $0 }\n"
]
)

Expand Down Expand Up @@ -68,7 +71,8 @@ public struct ArrayInitRule: ASTRule, ConfigurationProviderRule, OptInRule, Auto
isParameterStyleViolation(file: file, dictionary: dictionary, tokens: tokens),
let lastToken = tokens.last,
case let bodyEndPosition = bodyOffset + bodyLength,
!containsTrailingContent(lastToken: lastToken, bodyEndPosition: bodyEndPosition, file: file) else {
!containsTrailingContent(lastToken: lastToken, bodyEndPosition: bodyEndPosition, file: file),
!containsLeadingContent(tokens: tokens, bodyStartPosition: bodyOffset, file: file) else {
return []
}

Expand Down Expand Up @@ -98,10 +102,38 @@ public struct ArrayInitRule: ASTRule, ConfigurationProviderRule, OptInRule, Auto
file: File) -> Bool {
let lastTokenEnd = lastToken.offset + lastToken.length
let remainingLength = bodyEndPosition - lastTokenEnd
let nsstring = file.contents.bridge()
let remainingRange = NSRange(location: lastTokenEnd, length: remainingLength)
let remainingTokens = file.syntaxMap.tokens(inByteRange: remainingRange)
let ranges = NSMutableIndexSet(indexesIn: remainingRange)
return containsContent(inByteRange: remainingRange, file: file)
}

private func containsLeadingContent(tokens: [SyntaxToken],
bodyStartPosition: Int,
file: File) -> Bool {
let inTokenPosition = tokens.firstIndex(where: { token in
SyntaxKind(rawValue: token.type) == .keyword && file.contents(for: token) == "in"
})

let firstToken: SyntaxToken
let start: Int
if let position = inTokenPosition {
let index = tokens.index(after: position)
firstToken = tokens[index]
let inToken = tokens[position]
start = inToken.offset + inToken.length
} else {
firstToken = tokens[0]
start = bodyStartPosition
}

let length = firstToken.offset - start
let remainingRange = NSRange(location: start, length: length)
return containsContent(inByteRange: remainingRange, file: file)
}

private func containsContent(inByteRange byteRange: NSRange, file: File) -> Bool {
let nsstring = file.contents.bridge()
let remainingTokens = file.syntaxMap.tokens(inByteRange: byteRange)
let ranges = NSMutableIndexSet(indexesIn: byteRange)

for token in remainingTokens {
ranges.remove(in: NSRange(location: token.offset, length: token.length))
Expand Down

0 comments on commit fc76d89

Please sign in to comment.