Add IBInspectableInExtensionRule (#3174)

This commit is contained in:
Keith Smiley 2020-08-04 14:15:40 -07:00 committed by GitHub
parent 9e5557fbc5
commit cf94d5d8ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 73 additions and 0 deletions

View File

@ -19,6 +19,9 @@
found issues.
[krin-san](https://github.com/krin-san)
[#3177](https://github.com/realm/SwiftLint/pull/3177)
* Add opt-in `ibinspectable_in_extension` rule to lint against `@IBInspectable`
properties in `extensions`
[Keith Smiley](https://github.com/keith)
* Add `computed_accessors_order` rule to validate the order of `get` and `set`
accessors in computed properties and subscripts.

View File

@ -69,6 +69,7 @@ public let masterRuleList = RuleList(rules: [
FunctionDefaultParameterAtEndRule.self,
FunctionParameterCountRule.self,
GenericTypeNameRule.self,
IBInspectableInExtensionRule.self,
IdenticalOperandsRule.self,
IdentifierNameRule.self,
ImplicitGetterRule.self,

View File

@ -0,0 +1,52 @@
import SourceKittenFramework
public struct IBInspectableInExtensionRule: ConfigurationProviderRule, OptInRule, AutomaticTestableRule {
public var configuration = SeverityConfiguration(.warning)
public init() {}
public static let description = RuleDescription(
identifier: "ibinspectable_in_extension",
name: "IBInspectable in Extension",
description: "Extensions shouldn't add @IBInspectable properties.",
kind: .lint,
nonTriggeringExamples: [
Example("""
class Foo {
@IBInspectable private var x: Int
}
""")
],
triggeringExamples: [
Example("""
extension Foo {
@IBInspectable private var x: Int
}
""")
]
)
public func validate(file: SwiftLintFile) -> [StyleViolation] {
let collector = NamespaceCollector(dictionary: file.structureDictionary)
let elements = collector.findAllElements(of: [.extension])
return elements
.flatMap { element in
return element.dictionary.substructure.compactMap { element -> ByteCount? in
guard element.declarationKind == .varInstance,
element.enclosedSwiftAttributes.contains(.ibinspectable),
let offset = element.offset
else {
return nil
}
return offset
}
}
.map {
StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
location: Location(file: file, byteOffset: $0))
}
}
}

View File

@ -247,6 +247,7 @@
C25EBBE521078DCE00E27603 /* Glob.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25EBBE321078DC700E27603 /* Glob.swift */; };
C26330382073DAC500D7B4FD /* LowerACLThanParentRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C26330352073DAA200D7B4FD /* LowerACLThanParentRule.swift */; };
C28B2B3D2106DF730009A0FE /* PrefixedConstantRuleConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28B2B3B2106DF210009A0FE /* PrefixedConstantRuleConfiguration.swift */; };
C2A8D076243C0D0300642BC9 /* IBInspectableInExtensionRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A8D075243C0D0300642BC9 /* IBInspectableInExtensionRule.swift */; };
C2B3C1612106F78C00088928 /* ConfigurationAliasesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B3C15F2106F78100088928 /* ConfigurationAliasesTests.swift */; };
C328A2F71E6759AE00A9E4D7 /* ExplicitTypeInterfaceRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C328A2F51E67595500A9E4D7 /* ExplicitTypeInterfaceRule.swift */; };
C3D23F1D21E3A33700E9BD1B /* UnusedControlFlowLabelRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4D7320C21E15ED4001C07D9 /* UnusedControlFlowLabelRule.swift */; };
@ -765,6 +766,7 @@
C25EBBE321078DC700E27603 /* Glob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Glob.swift; sourceTree = "<group>"; };
C26330352073DAA200D7B4FD /* LowerACLThanParentRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LowerACLThanParentRule.swift; sourceTree = "<group>"; };
C28B2B3B2106DF210009A0FE /* PrefixedConstantRuleConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefixedConstantRuleConfiguration.swift; sourceTree = "<group>"; };
C2A8D075243C0D0300642BC9 /* IBInspectableInExtensionRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBInspectableInExtensionRule.swift; sourceTree = "<group>"; };
C2B3C15F2106F78100088928 /* ConfigurationAliasesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationAliasesTests.swift; sourceTree = "<group>"; };
C328A2F51E67595500A9E4D7 /* ExplicitTypeInterfaceRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExplicitTypeInterfaceRule.swift; sourceTree = "<group>"; };
C3DE5DAA1E7DF99B00761483 /* FatalErrorMessageRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FatalErrorMessageRule.swift; sourceTree = "<group>"; };
@ -1198,6 +1200,7 @@
62A3E95B209E078000547A86 /* EmptyXCTestMethodRule.swift */,
626B01B420A1735900D2C42F /* EmptyXCTestMethodRuleExamples.swift */,
7723A4DE23442D7100F38590 /* RawValueForCamelCasedCodableEnumRule.swift */,
C2A8D075243C0D0300642BC9 /* IBInspectableInExtensionRule.swift */,
D4E92D1E2137B4C9002EDD48 /* IdenticalOperandsRule.swift */,
D4441A27213279950020896F /* InertDeferRule.swift */,
C26330352073DAA200D7B4FD /* LowerACLThanParentRule.swift */,
@ -2208,6 +2211,7 @@
C3D23F1D21E3A33700E9BD1B /* UnusedControlFlowLabelRule.swift in Sources */,
55CE0585231899100023BA72 /* ContainsOverRangeNilComparisonRule.swift in Sources */,
6C1D763221A4E69600DEF783 /* Request+DisableSourceKit.swift in Sources */,
C2A8D076243C0D0300642BC9 /* IBInspectableInExtensionRule.swift in Sources */,
47ACC8981E7DC74E0088EEB2 /* ImplicitlyUnwrappedOptionalConfiguration.swift in Sources */,
787CDE39208E7D41005F3D2F /* SwitchCaseAlignmentConfiguration.swift in Sources */,
D450D1DD21F199F700E60010 /* TrailingClosureConfiguration.swift in Sources */,

View File

@ -664,6 +664,12 @@ extension GlobTests {
]
}
extension IBInspectableInExtensionRuleTests {
static var allTests: [(String, (IBInspectableInExtensionRuleTests) -> () throws -> Void)] = [
("testWithDefaultConfiguration", testWithDefaultConfiguration)
]
}
extension IdenticalOperandsRuleTests {
static var allTests: [(String, (IdenticalOperandsRuleTests) -> () throws -> Void)] = [
("testWithDefaultConfiguration", testWithDefaultConfiguration)
@ -1761,6 +1767,7 @@ XCTMain([
testCase(FunctionParameterCountRuleTests.allTests),
testCase(GenericTypeNameRuleTests.allTests),
testCase(GlobTests.allTests),
testCase(IBInspectableInExtensionRuleTests.allTests),
testCase(IdenticalOperandsRuleTests.allTests),
testCase(IdentifierNameRuleTests.allTests),
testCase(ImplicitGetterRuleTests.allTests),

View File

@ -264,6 +264,12 @@ class FunctionDefaultParameterAtEndRuleTests: XCTestCase {
}
}
class IBInspectableInExtensionRuleTests: XCTestCase {
func testWithDefaultConfiguration() {
verifyRule(IBInspectableInExtensionRule.description)
}
}
class IdenticalOperandsRuleTests: XCTestCase {
func testWithDefaultConfiguration() {
verifyRule(IdenticalOperandsRule.description)