Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip correcting files with parser diagnostics #3349

Merged
merged 3 commits into from
Sep 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
performance in multithreaded operations.
[JP Simard](https://github.com/jpsim)

* Skip correcting file if the swift parser reports a warning or an
error.
[JP Simard](https://github.com/jpsim)
[#3343](https://github.com/realm/SwiftLint/issues/3343)

#### Bug Fixes

* None.
Expand Down
19 changes: 19 additions & 0 deletions Source/SwiftLintFramework/Extensions/SwiftLintFile+Cache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ private var syntaxKindsByLinesCache = Cache({ file in file.syntaxKindsByLine() }
private var syntaxTokensByLinesCache = Cache({ file in file.syntaxTokensByLine() })

internal typealias AssertHandler = () -> Void
// Re-enable once all parser diagnostics in tests have been addressed.
// https://github.com/realm/SwiftLint/issues/3348
internal var parserDiagnosticsDisabledForTests = false

private var assertHandlers = [FileCacheKey: AssertHandler]()
private var assertHandlerCache = Cache({ file in assertHandlers[file.cacheKey] })
Expand Down Expand Up @@ -125,6 +128,22 @@ extension SwiftLintFile {
}
}

internal var parserDiagnostics: [[String: SourceKitRepresentable]]? {
if parserDiagnosticsDisabledForTests {
return nil
}

guard let response = responseCache.get(self) else {
if let handler = assertHandler {
handler()
return nil
}
queuedFatalError("Never call this for file that sourcekitd fails.")
}

return response["key.diagnostics"] as? [[String: SourceKitRepresentable]]
}

internal var structure: Structure {
guard let structure = structureCache.get(self) else {
if let handler = assertHandler {
Expand Down
8 changes: 8 additions & 0 deletions Source/SwiftLintFramework/Models/Linter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,14 @@ public struct CollectedLinter {
return []
}

if let parserDiagnostics = file.parserDiagnostics {
queuedPrintError(
"Skipping correcting file because it produced Swift parser diagnostics: \(file.path ?? "<nopath>")"
)
queuedPrintError(toJSON(["diagnostics": parserDiagnostics]))
return []
}

var corrections = [Correction]()
for rule in rules.compactMap({ $0 as? CorrectableRule }) {
let newCorrections = rule.correct(file: file, using: storage, compilerArguments: compilerArguments)
Expand Down
2 changes: 1 addition & 1 deletion Source/SwiftLintFramework/Models/MasterRuleList.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Generated using Sourcery 0.17.0 — https://github.com/krzysztofzablocki/Sourcery
// Generated using Sourcery 0.18.0 — https://github.com/krzysztofzablocki/Sourcery
// DO NOT EDIT

/// The rule list containing all available rules built into SwiftLint.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,17 @@ public struct TrailingSemicolonRule: SubstitutionCorrectableRule, ConfigurationP
name: "Trailing Semicolon",
description: "Lines should not have trailing semicolons.",
kind: .idiomatic,
nonTriggeringExamples: [ Example("let a = 0\n") ],
nonTriggeringExamples: [
Example("let a = 0\n"),
Example("let a = 0; let b = 0")
],
triggeringExamples: [
Example("let a = 0↓;\n"),
Example("let a = 0↓;\nlet b = 1\n"),
Example("let a = 0↓;;\n"),
Example("let a = 0↓; ;;\n"),
Example("let a = 0↓; ; ;\n")
Example("let a = 0↓;\nlet b = 1\n")
],
corrections: [
Example("let a = 0↓;\n"): Example("let a = 0\n"),
Example("let a = 0↓;\nlet b = 1\n"): Example("let a = 0\nlet b = 1\n"),
Example("let a = 0↓;;\n"): Example("let a = 0\n"),
Example("let a = 0↓; ;;\n"): Example("let a = 0\n"),
Example("let a = 0↓; ; ;\n"): Example("let a = 0\n")
Example("let a = 0↓;\nlet b = 1\n"): Example("let a = 0\nlet b = 1\n")
]
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ public struct AnyObjectProtocolRule: SubstitutionCorrectableASTRule, OptInRule,
Example("protocol SomeClassOnlyProtocol: AnyObject {}\n"),
Example("protocol SomeClassOnlyProtocol: ↓class, SomeInheritedProtocol {}\n"):
Example("protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}\n"),
Example("protocol SomeClassOnlyProtocol: SomeInheritedProtocol, ↓class {}\n"):
Example("protocol SomeClassOnlyProtocol: SomeInheritedProtocol, AnyObject {}\n"),
Example("@objc protocol SomeClassOnlyProtocol: ↓class, SomeInheritedProtocol {}\n"):
Example("@objc protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {}\n")
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,10 @@ public struct UnusedClosureParameterRule: SubstitutionCorrectableASTRule, Config
Example("[1, 2].map { _ in\n return numberWithSuffix\n}\n"),
Example("[1, 2].map { ↓number in\n return 3 // number\n}\n"):
Example("[1, 2].map { _ in\n return 3 // number\n}\n"),
Example("[1, 2].map { ↓number in\n return 3 \"number\"\n}\n"):
Example("[1, 2].map { _ in\n return 3 \"number\"\n}\n"),
Example("[1, 2].something { number, ↓idx in\n return number\n}\n"):
Example("[1, 2].something { number, _ in\n return number\n}\n"),
Example("genericsFunc(closure: { (↓int: Int) -> Void in // do something\n}\n"):
Example("genericsFunc(closure: { (_: Int) -> Void in // do something\n}\n"),
Example("genericsFunc(closure: { (↓int: Int) -> Void in // do something\n})\n"):
Example("genericsFunc(closure: { (_: Int) -> Void in // do something\n})\n"),
Example("genericsFunc { (↓a, ↓b: Type) -> Void in\n}\n"):
Example("genericsFunc { (_, _: Type) -> Void in\n}\n"),
Example("genericsFunc { (↓a: Type, ↓b: Type) -> Void in\n}\n"):
Expand All @@ -91,8 +89,20 @@ public struct UnusedClosureParameterRule: SubstitutionCorrectableASTRule, Config
Example("genericsFunc { (a: Type, _) -> Void in\nreturn a\n}\n"),
Example("hoge(arg: num) { ↓num in\n}\n"):
Example("hoge(arg: num) { _ in\n}\n"),
Example("func foo () {\n bar { ↓number in\n return 3\n}\n"):
Example("func foo () {\n bar { _ in\n return 3\n}\n"),
Example("""
func foo () {
bar { ↓number in
return 3
}
}
"""):
Example("""
func foo () {
bar { _ in
return 3
}
}
"""),
Example("class C {\n #if true\n func f() {\n [1, 2].map { ↓number in\n return 3\n }\n }\n #endif\n}"):
Example("class C {\n #if true\n func f() {\n [1, 2].map { _ in\n return 3\n }\n }\n #endif\n}")
]
Expand Down
8 changes: 4 additions & 4 deletions Source/SwiftLintFramework/Rules/Lint/YodaConditionRule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ public struct YodaConditionRule: ASTRule, OptInRule, ConfigurationProviderRule,
Example("guard foo != \"str str\" else { return }"),
Example("while foo < 10 { }\n"),
Example("while foo > 1 { }\n"),
Example("while foo + 1 == 2"),
Example("if optionalValue?.property ?? 0 == 2"),
Example("if foo == nil")
Example("while foo + 1 == 2 {}"),
Example("if optionalValue?.property ?? 0 == 2 {}"),
Example("if foo == nil {}")
],
triggeringExamples: [
Example("↓if 42 == foo {}\n"),
Expand All @@ -55,7 +55,7 @@ public struct YodaConditionRule: ASTRule, OptInRule, ConfigurationProviderRule,
Example("↓guard \"str str\" != foo else { return }"),
Example("↓while 10 > foo { }"),
Example("↓while 1 < foo { }"),
Example("↓if nil == foo")
Example("↓if nil == foo {}")
])

public func validate(file: SwiftLintFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private func trailingClosure(_ violationSymbol: String = "",
line: UInt = #line) -> Example {
return Example("""
foo.bar \(violationSymbol){ toto in
\(repeatElement("\tlet a = 0\n", count: codeLinesCount).joined())\
\((0..<codeLinesCount).map { "\tlet a\($0) = 0\n" }.joined())\
\(repeatElement("\t// toto\n", count: commentLinesCount).joined())\
\(repeatElement("\t\n", count: emptyLinesCount).joined())\
}
Expand All @@ -54,7 +54,7 @@ private func argumentClosure(_ violationSymbol: String = "",
line: UInt = #line) -> Example {
return Example("""
foo.bar(\(violationSymbol){ toto in
\(repeatElement("\tlet a = 0\n", count: codeLinesCount).joined())\
\((0..<codeLinesCount).map { "\tlet a\($0) = 0\n" }.joined())\
})
""", file: file, line: line)
}
Expand All @@ -65,7 +65,7 @@ private func labeledArgumentClosure(_ violationSymbol: String = "",
line: UInt = #line) -> Example {
return Example("""
foo.bar(label: \(violationSymbol){ toto in
\(repeatElement("\tlet a = 0\n", count: codeLinesCount).joined())\
\((0..<codeLinesCount).map { "\tlet a\($0) = 0\n" }.joined())\
})
""", file: file, line: line)
}
Expand All @@ -76,9 +76,9 @@ private func multiLabeledArgumentClosures(_ violationSymbol: String = "",
line: UInt = #line) -> Example {
return Example("""
foo.bar(label: \(violationSymbol){ toto in
\(repeatElement("\tlet a = 0\n", count: codeLinesCount).joined())\
\((0..<codeLinesCount).map { "\tlet a\($0) = 0\n" }.joined())\
}, anotherLabel: \(violationSymbol){ toto in
\(repeatElement("\tlet a = 0\n", count: codeLinesCount).joined())\
\((0..<codeLinesCount).map { "\tlet a\($0) = 0\n" }.joined())\
})
""", file: file, line: line)
}
Expand All @@ -89,9 +89,9 @@ private func labeledAndTrailingClosures(_ violationSymbol: String = "",
line: UInt = #line) -> Example {
return Example("""
foo.bar(label: \(violationSymbol){ toto in
\(repeatElement("\tlet a = 0\n", count: codeLinesCount).joined())\
\((0..<codeLinesCount).map { "\tlet a\($0) = 0\n" }.joined())\
}) \(violationSymbol){ toto in
\(repeatElement("\tlet a = 0\n", count: codeLinesCount).joined())\
\((0..<codeLinesCount).map { "\tlet a\($0) = 0\n" }.joined())\
}
""", file: file, line: line)
}
Expand All @@ -103,7 +103,7 @@ private func lazyInitialization(_ violationSymbol: String = "",
return Example("""
let foo: Bar = \(violationSymbol){ toto in
\tlet bar = Bar()
\(repeatElement("\tlet a = 0\n", count: codeLinesCount).joined())\
\((0..<codeLinesCount).map { "\tlet a\($0) = 0\n" }.joined())\
\treturn bar
}()
""", file: file, line: line)
Expand Down
30 changes: 15 additions & 15 deletions Source/SwiftLintFramework/Rules/Style/AttributesRuleExamples.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ internal struct AttributesRuleExamples {
Example("@IBAction func buttonPressed(button: UIButton)"),
Example("@objc\n @IBAction func buttonPressed(button: UIButton)"),
Example("@available(iOS 9.0, *)\n func animate(view: UIStackView)"),
Example("@available(iOS 9.0, *, message=\"A message\")\n func animate(view: UIStackView)"),
Example("@nonobjc\n final class X"),
Example("@available(iOS 9.0, *)\n class UIStackView"),
Example("@NSApplicationMain\n class AppDelegate: NSObject, NSApplicationDelegate"),
Example("@UIApplicationMain\n class AppDelegate: NSObject, UIApplicationDelegate"),
Example("@IBDesignable\n class MyCustomView: UIView"),
Example("@available(*, deprecated, message: \"A message\")\n func animate(view: UIStackView)"),
Example("@nonobjc\n final class X {}"),
Example("@available(iOS 9.0, *)\n class UIStackView {}"),
Example("@NSApplicationMain\n class AppDelegate: NSObject, NSApplicationDelegate {}"),
Example("@UIApplicationMain\n class AppDelegate: NSObject, UIApplicationDelegate {}"),
Example("@IBDesignable\n class MyCustomView: UIView {}"),
Example("@testable import SourceKittenFramework"),
Example("@objc(foo_x)\n var x: String"),
Example("@available(iOS 9.0, *)\n@objc(abc_stackView)\n let stackView: UIStackView"),
Example("@objc(abc_addSomeObject:)\n @NSManaged func addSomeObject(book: SomeObject)"),
Example("@objc(ABCThing)\n @available(iOS 9.0, *)\n class Thing"),
Example("@objc(ABCThing)\n @available(iOS 9.0, *)\n class Thing {}"),
Example("class Foo: NSObject {\n override var description: String { return \"\" }\n}"),
Example("class Foo: NSObject {\n\n override func setUp() {}\n}"),
Example("@objc\nclass ⽺ {}\n"),
Expand Down Expand Up @@ -76,20 +76,20 @@ internal struct AttributesRuleExamples {
Example("@IBAction\n ↓func buttonPressed(button: UIButton)"),
Example("@IBAction\n @objc\n ↓func buttonPressed(button: UIButton)"),
Example("@available(iOS 9.0, *) ↓func animate(view: UIStackView)"),
Example("@nonobjc final ↓class X"),
Example("@available(iOS 9.0, *) ↓class UIStackView"),
Example("@available(iOS 9.0, *)\n @objc ↓class UIStackView"),
Example("@available(iOS 9.0, *) @objc\n ↓class UIStackView"),
Example("@available(iOS 9.0, *)\n\n ↓class UIStackView"),
Example("@UIApplicationMain ↓class AppDelegate: NSObject, UIApplicationDelegate"),
Example("@IBDesignable ↓class MyCustomView: UIView"),
Example("@nonobjc final ↓class X {}"),
Example("@available(iOS 9.0, *) ↓class UIStackView {}"),
Example("@available(iOS 9.0, *)\n @objc ↓class UIStackView {}"),
Example("@available(iOS 9.0, *) @objc\n ↓class UIStackView {}"),
Example("@available(iOS 9.0, *)\n\n ↓class UIStackView {}"),
Example("@UIApplicationMain ↓class AppDelegate: NSObject, UIApplicationDelegate {}"),
Example("@IBDesignable ↓class MyCustomView: UIView {}"),
Example("@testable\n↓import SourceKittenFramework"),
Example("@testable\n\n\n↓import SourceKittenFramework"),
Example("@objc(foo_x) ↓var x: String"),
Example("@available(iOS 9.0, *) @objc(abc_stackView)\n ↓let stackView: UIStackView"),
Example("@objc(abc_addSomeObject:) @NSManaged\n ↓func addSomeObject(book: SomeObject)"),
Example("@objc(abc_addSomeObject:)\n @NSManaged\n ↓func addSomeObject(book: SomeObject)"),
Example("@available(iOS 9.0, *)\n @objc(ABCThing) ↓class Thing"),
Example("@available(iOS 9.0, *)\n @objc(ABCThing) ↓class Thing {}"),
Example("@GKInspectable\n ↓var maxSpeed: Float"),
Example("@discardableResult ↓func a() -> Int"),
Example("@objc\n @discardableResult ↓func a() -> Int"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct ComputedAccessorsOrderRuleExamples {
Example("""
protocol Foo {
var foo: Int { get set }
}
"""),
Example("""
protocol Foo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct ImplicitGetterRuleExamples {
Example("""
protocol Foo {
var foo: Int { get set }
}
"""),
Example("""
class Foo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ public struct VerticalWhitespaceClosingBracesRule: ConfigurationProviderRule {
public init() {}

private static let nonTriggeringExamples: [Example] = [
Example("[1, 2].map { $0 }.filter {"),
Example("[1, 2].map { $0 }.filter { num in"),
Example("[1, 2].map { $0 }.filter { true }"),
Example("[1, 2].map { $0 }.filter { num in true }"),
Example("""
/*
class X {
Expand All @@ -27,14 +27,81 @@ public struct VerticalWhitespaceClosingBracesRule: ConfigurationProviderRule {
]

private static let violatingToValidExamples: [Example: Example] = [
Example(" print(\"x is 5\")\n↓\n}"): Example(" print(\"x is 5\")\n}"),
Example(" print(\"x is 5\")\n↓\n\n}"): Example(" print(\"x is 5\")\n}"),
Example(" print(\"x is 5\")\n↓ \n}"): Example(" print(\"x is 5\")\n}"),
Example(" )\n}\n↓\n }\n}"): Example(" )\n}\n }\n}"),
Example("[\n1,\n2,\n3\n↓\n]"): Example("[\n1,\n2,\n3\n]"),
Example("foo(\nx: 5,\ny:6\n↓\n)"): Example("foo(\nx: 5,\ny:6\n)"),
Example("class Name {\n run(5) { x in print(x) }\n↓\n}"):
Example("class Name {\n run(5) { x in print(x) }\n}")
Example("""
do {
print("x is 5")
}
"""):
Example("""
do {
print("x is 5")
}
"""),
Example("""
do {
print("x is 5")

}
"""):
Example("""
do {
print("x is 5")
}
"""),
Example("""
do {
print("x is 5")
↓\n \n}
"""):
Example("""
do {
print("x is 5")
}
"""),
Example("""
[
1,
2,
3
]
"""):
Example("""
[
1,
2,
3
]
"""),
Example("""
foo(
x: 5,
y:6
)
"""):
Example("""
foo(
x: 5,
y:6
)
"""),
Example("""
func foo() {
run(5) { x in
print(x)
}
}
"""): Example("""
func foo() {
run(5) { x in
print(x)
}
}
""")
]

private let pattern = "((?:\\n[ \\t]*)+)(\\n[ \\t]*[)}\\]])"
Expand Down
Loading