Skip to content
Open
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
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@

### Enhancements

* None.
* Add `#examples` and `#examplesDictionary` macros that expand lists and
dictionaries of code strings into `Example`s, reducing boilerplate when
defining a rule's triggering/non-triggering examples and corrections. Adopt
them across the built-in rules.
[ZevEisenberg](https://github.com/ZevEisenberg)

### Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,27 @@ struct AnonymousArgumentInMultilineClosureRule: Rule {
```
""",
kind: .idiomatic,
nonTriggeringExamples: [
Example("closure { $0 }"),
Example("closure { print($0) }"),
Example("""
nonTriggeringExamples: #examples([
"closure { $0 }",
"closure { print($0) }",
"""
closure { arg in
print(arg)
}
"""),
Example("""
""",
"""
closure { arg in
nestedClosure { $0 + arg }
}
"""),
],
triggeringExamples: [
Example("""
""",
]),
triggeringExamples: #examples([
"""
closure {
print(↓$0)
}
"""),
]
""",
])
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,29 @@ struct BlockBasedKVORule: Rule {
name: "Block Based KVO",
description: "Prefer the new block based KVO API with keypaths when using Swift 3.2 or later",
kind: .idiomatic,
nonTriggeringExamples: [
Example(#"""
nonTriggeringExamples: #examples([
#"""
let observer = foo.observe(\.value, options: [.new]) { (foo, change) in
print(change.newValue)
}
"""#),
],
triggeringExamples: [
Example("""
"""#,
]),
triggeringExamples: #examples([
"""
class Foo: NSObject {
override ↓func observeValue(forKeyPath keyPath: String?, of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {}
}
"""),
Example("""
""",
"""
class Foo: NSObject {
override ↓func observeValue(forKeyPath keyPath: String?, of object: Any?,
change: Dictionary<NSKeyValueChangeKey, Any>?,
context: UnsafeMutableRawPointer?) {}
}
"""),
]
""",
])
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,110 +10,110 @@ struct ConvenienceTypeRule: Rule {
description: "Types used for hosting only static members should be implemented as a caseless enum " +
"to avoid instantiation",
kind: .idiomatic,
nonTriggeringExamples: [
Example("""
nonTriggeringExamples: #examples([
"""
enum Math { // enum
public static let pi = 3.14
}
"""),
Example("""
""",
"""
// class with inheritance
class MathViewController: UIViewController {
public static let pi = 3.14
}
"""),
Example("""
""",
"""
@objc class Math: NSObject { // class visible to Obj-C
public static let pi = 3.14
}
"""),
Example("""
""",
"""
struct Math { // type with non-static declarations
public static let pi = 3.14
public let randomNumber = 2
}
"""),
Example("class DummyClass {}"),
Example("""
""",
"class DummyClass {}",
"""
class Foo: NSObject { // class with Obj-C class property
class @objc let foo = 1
}
"""),
Example("""
""",
"""
class Foo: NSObject { // class with Obj-C static property
static @objc let foo = 1
}
"""),
Example("""
""",
"""
class Foo { // @objc class func can't exist on an enum
@objc class func foo() {}
}
"""),
Example("""
""",
"""
class Foo { // @objc static func can't exist on an enum
@objc static func foo() {}
}
"""),
Example("""
""",
"""
@objcMembers class Foo { // @objc static func can't exist on an enum
static func foo() {}
}
"""),
Example("""
""",
"""
final class Foo { // final class, but @objc class func can't exist on an enum
@objc class func foo() {}
}
"""),
Example("""
""",
"""
final class Foo { // final class, but @objc static func can't exist on an enum
@objc static func foo() {}
}
"""),
Example("""
""",
"""
@globalActor actor MyActor {
static let shared = MyActor()
}
"""),
],
triggeringExamples: [
Example("""
""",
]),
triggeringExamples: #examples([
"""
↓struct Math {
public static let pi = 3.14
}
"""),
Example("""
""",
"""
↓struct Math {
public static let pi = 3.14
@available(*, unavailable) init() {}
}
"""),
Example("""
""",
"""
final ↓class Foo { // final class can't be inherited
class let foo = 1
}
"""),
""",

// Intentional false positives. Non-final classes could be
// subclassed, but we figure it is probably rare enough that it is
// more important to catch these cases, and manually disable the
// rule if needed.

Example("""
"""
↓class Foo {
class let foo = 1
}
"""),
Example("""
""",
"""
↓class Foo {
final class let foo = 1
}
"""),
Example("""
""",
"""
↓class SomeClass {
static func foo() {}
}
"""),
]
""",
])
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ struct DiscouragedAssertRule: Rule {
name: "Discouraged Assert",
description: "Prefer `assertionFailure()` and/or `preconditionFailure()` over `assert(false)`",
kind: .idiomatic,
nonTriggeringExamples: [
Example(#"assert(true)"#),
Example(#"assert(true, "foobar")"#),
Example(#"assert(true, "foobar", file: "toto", line: 42)"#),
Example(#"assert(false || true)"#),
Example(#"XCTAssert(false)"#),
],
triggeringExamples: [
Example(#"↓assert(false)"#),
Example(#"↓assert(false, "foobar")"#),
Example(#"↓assert(false, "foobar", file: "toto", line: 42)"#),
Example(#"↓assert( false , "foobar")"#),
]
nonTriggeringExamples: #examples([
#"assert(true)"#,
#"assert(true, "foobar")"#,
#"assert(true, "foobar", file: "toto", line: 42)"#,
#"assert(false || true)"#,
#"XCTAssert(false)"#,
]),
triggeringExamples: #examples([
#"↓assert(false)"#,
#"↓assert(false, "foobar")"#,
#"↓assert(false, "foobar", file: "toto", line: 42)"#,
#"↓assert( false , "foobar")"#,
])
)
}

Expand Down
Loading
Loading