diff --git a/CHANGELOG.md b/CHANGELOG.md index 650461984be..31abd8a3bf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,10 @@ not enabled in the configuration. [Marcelo Fabri](https://github.com/marcelofabri) +* Shebang (`#!`) in the beginning of a file is now ignored by all rules. + [Marcelo Fabri](https://github.com/marcelofabri) + [#1294](https://github.com/realm/SwiftLint/issues/1294) + ##### Bug Fixes * Fix false positive on `redundant_discardable_let` rule when using diff --git a/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift b/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift index 28acf82760b..f715f4fa650 100644 --- a/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift +++ b/Source/SwiftLintFramework/Extensions/File+SwiftLint.swift @@ -52,13 +52,22 @@ extension File { } let contents = self.contents.bridge() let pattern = "swiftlint:(enable|disable)(:previous|:this|:next)?\\ [^\\n]+" - return match(pattern: pattern, with: [.comment]).flatMap { range in + return skipShebangCommands() + match(pattern: pattern, with: [.comment]).flatMap { range in return Command(string: contents, range: range) }.flatMap { command in return command.expand() } } + private func skipShebangCommands() -> [Command] { + guard contents.hasPrefix("#!") else { + return [] + } + + return Command(action: .disable, ruleIdentifiers: masterRuleList.allValidIdentifiers(), + line: 0, modifier: .next).expand() + } + fileprivate func endOf(next command: Command?) -> Location { guard let nextCommand = command else { return Location(file: path, line: .max, character: .max) diff --git a/Tests/SwiftLintFrameworkTests/RulesTests.swift b/Tests/SwiftLintFrameworkTests/RulesTests.swift index 1464afb4897..c6ea7b78343 100644 --- a/Tests/SwiftLintFrameworkTests/RulesTests.swift +++ b/Tests/SwiftLintFrameworkTests/RulesTests.swift @@ -203,6 +203,11 @@ class RulesTests: XCTestCase { func testOperatorUsageWhitespace() { verifyRule(OperatorUsageWhitespaceRule.description) + + let description = OperatorUsageWhitespaceRule.description + .with(nonTriggeringExamples: ["#!/usr/bin/env swift\n"]) + .with(triggeringExamples: []).with(corrections: [:]) + verifyRule(description, skipCommentTests: true, skipStringTests: true, testMultiByteOffsets: false) } func testPrivateOverFilePrivate() {