This option allows for more fine-grained placement of the location
marker for code violating a custom rule, e.g.:
```swift
print("Hello world.")
^~~~~
```
for this `.swiftlint.yml`:
```yaml
custom_rules:
world_preceded_by_hello:
name: "World Preceded by Hello"
included: ".+\\.swift"
message: "The word World predeced by the word hello should be capitalised."
severity: warning
regex: "(?i:hello)\\s+(world)"
match_kinds: [string]
capture_group: 1
```
* Added 'file_name_no_space' rule
* Removed unused var, and added to changelog
* Remove custom suffix from 'file-name-no-space' rule
* Fixed LinuxMain
* Switched to use a CharacterSet over Regex
* [UnusedImportRule] Handle comments after the import statement
* fixup! [UnusedImportRule] Handle comments after the import statement
* Use \s+ to capture whitespace in regex
Co-Authored-By: Dave Lee <davelee.com@gmail.com>
* Fix testDetectSwiftVersion() with Swift 5.1.3
* fixup! Fix testDetectSwiftVersion() with Swift 5.1.3
* Handle @_exported imports
* Work around SR-11099
* Unescape newline
* Fixed false positive in opening_brace rule on anonymous closure
* added one more triggering rule, fixed docs
* fixed anonymous closure match
* fixed anonymous closure match, more accurate
* Add expiring todos rule
* Fix default dateFormat
* Fix date regex to handle 2-4 at beginning/end of string
* Clean up/improve clarity
* Add tests for ExpiringTodoRule
* Add output from make sourcery
* Add output from make sourcery
* Update documentation
* Enable updating of all configuration properties
* Add back Foundation import
* Add changelog entry
* Add 2 spaces after changelog entry
* Add return for legacy swift compatibility
* Add unwrapping to switch statement
* Use disable:next
* Add default values to severity config init; Add public delimiter init
* Add tests for various custom configurations
* Remove unused funcs
* Add extra tests to LinuxMain file
* Update File type -> SwiftLintFile
* Move Changelog entry
* Shorten changelog entry line length
* Fix changelog
* Improve compilation time
Before this change, `trailingClosure` took 8.6s to type check.
After this change, it takes 31ms.
* Speed up type checking `isDecimal(number:)`
Before: 377ms
After: 2ms
* Speed up type checking testViolationMessageForExpressibleByIntegerLiteral()
Before: 285ms
After: 175ms
* Fix OSSCheck
More than just rules are in `Source/SwiftLintFramework/Rules/`
* Shim XCTUnwrap for Swift 5.0
When the request is asked which tokens are have in an intersection, the previous solution was searching for first Index (linearly) and then filtered everything that was coming after that index using `intersect function`
The updated solution will search for the first token index using`binary search`
# Speedup
While this is only one function was updated, the next options were considered:
- [**lin+filter**] old solution
- [**lin+prefix**] old solution with `prefix:wihle` instead of filtering
- [**bin+filter**] binary search with filter
- [**bin+prefix**] binary search with `prefix:wihle` instead of filtering
The speedup highly depends on the file sizes. The bigger/longer files the bigger win is
# Benchmark
## Kickstarter
|lin+filter|lin+prefix|bin+filter|bin+prefix|speedup|
|-|-|-|-|-|
|0.494|0.243|0.390|\***0.117\***| ~4x |
## Swift
|lin+filter|lin+prefix|bin+filter|bin+prefix|speedup|
|-|-|-|-|-|
|1.739|0.740|1.273|\***0.103**\*| ~16x |
## WordPress
|lin+filter|lin+prefix|bin+filter|bin+prefix|speedup|
|-|-|-|-|-|
|1.270|0.526|0.918|0.148| ~8x |
# Testing code
This code was tested with these parts of code (in Release build)
```
fileprivate var counter = 0
fileprivate var times: [String: Double] = [:]
fileprivate let timesQueue = DispatchQueue.init(label: "benchmarks")
fileprivate func timeLog<T>(_ name: String, block: () -> T) -> T {
let start = DispatchTime.now()
let result = block()
let end = DispatchTime.now()
timesQueue.async {
let oldValue = times[name, default:0.0]
let diff = TimeInterval(end.uptimeNanoseconds - start.uptimeNanoseconds) / 1_000_000_000
let newValue = oldValue + diff
times[name] = newValue
counter += 1
if counter % 1000 * times.count == 0 {
print("!!!!: \(times)")
}
}
return result
}
internal func tokens(inByteRange byteRange: NSRange) -> [SyntaxToken] {
let new = timeLog("new") { tokensFast(inByteRange: byteRange) }
let new2 = timeLog("old") { tokensOld(inByteRange: byteRange) }
return arc4random() % 2 == 1 ? new : new2
}
```
* Use binary search when searching for lines indexes
* Update Changelog
* Remove unused old method of searching line by offset
* Update line by offset call with already implemented function
* Add Mark rule for triple slash Mark comments
* Move changelog entry to appropriate section
* Re-add Package.resolved
* Fix trailing comma
* Rebuild Rules.md using Xcode 10.3
* Combine two regexes into one
* Require Swift 5.0 to build
* Update CI
* Stop testing with Swift 4.x & Xcode 10.0/10.1
* Use official Swift docker image instead of norionomura's
* Use Xcode 10.3 as latest stable version
* Update READMEs
* Fixup xcodeproj
* Fixup CI Swift container image tag
* Fixup changelog
As was discussed #2737, I utilized the `indexsource` request to look up the operators and fetch the cursorInfo per operator. In the implementation I refrained from using `usr` to look up the operator because SourceKit [doesn't support](5add168042/tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp (L1799)) fetching cursorInfo by `usr` when it comes from C (but it can still be fetched by offset).
I also made [an alternative implementation](https://github.com/realm/SwiftLint/compare/master...biboran:fix-unused-imports-for-operators-alternative) which uses the `indexsource` request instead of the `editor.open`. It seems to work with the unit tests but I am not 100% sure it doesn't introduce a regression since there is no oss-check for analyzer rules.
I also updated [the example](https://github.com/biboran/synthax-bug-example) to better reflect the original issue in case you want to test the changes manually