Skip to content

Commit

Permalink
Merge - upstream - master
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Metzing committed Feb 26, 2018
2 parents 1fb429d + 52274de commit 749cdba
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 18 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
* Adds `untyped-error-in-catch-rule` opt-in rule to warn against declaring errors without type check in catch statements.
[Daniel Metzing](https://github.com/dirtydanee)
[#2045](https://github.com/realm/SwiftLint/issues/2045)
* Add a new `excluded` config parameter to the `explicit_type_interface` rule
to exempt certain types of variables from the rule.
[Rounak Jain](https://github.com/rounak)
[#2028](https://github.com/realm/SwiftLint/issues/2028)

#### Bug Fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation
import SourceKittenFramework

public struct ExplicitTypeInterfaceRule: ASTRule, OptInRule, ConfigurationProviderRule {
public var configuration = SeverityConfiguration(.warning)
public var configuration = ExplicitTypeInterfaceConfiguration()

public init() {}

Expand All @@ -33,21 +33,18 @@ public struct ExplicitTypeInterfaceRule: ASTRule, OptInRule, ConfigurationProvid
]
)

private static let allowedKinds: Set<SwiftDeclarationKind> = [.varInstance, .varLocal,
.varStatic, .varClass]

public func validate(file: File, kind: SwiftDeclarationKind,
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {

guard ExplicitTypeInterfaceRule.allowedKinds.contains(kind),
guard configuration.allowedKinds.contains(kind),
!containsType(dictionary: dictionary),
let offset = dictionary.offset else {
return []
}

return [
StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
severity: configuration.severityConfiguration.severity,
location: Location(file: file, byteOffset: offset))
]
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//
// ExplicitTypeInterfaceConfiguration.swift
// SwiftLint
//
// Created by Rounak Jain on 2/18/18.
// Copyright © 2018 Realm. All rights reserved.
//

import Foundation
import SourceKittenFramework

private enum VariableKind: String {
case instance
case local
case `static`
case `class`
}

private extension SwiftDeclarationKind {
init(variableKind: VariableKind) {
switch variableKind {
case .instance:
self = .varInstance
case .local:
self = .varLocal
case .static:
self = .varStatic
case .class:
self = .varClass
}
}

var variableKind: VariableKind? {
switch self {
case .varInstance:
return .instance
case .varLocal:
return .local
case .varStatic:
return .static
case .varClass:
return .class
default:
return nil
}
}
}

public struct ExplicitTypeInterfaceConfiguration: RuleConfiguration, Equatable {

private static let variableKinds: Set<SwiftDeclarationKind> = [.varInstance,
.varLocal,
.varStatic,
.varClass]

public var severityConfiguration = SeverityConfiguration(.warning)

public var allowedKinds = ExplicitTypeInterfaceConfiguration.variableKinds

public var consoleDescription: String {
let excludedKinds = ExplicitTypeInterfaceConfiguration.variableKinds.subtracting(allowedKinds)
let simplifiedExcludedKinds = excludedKinds.flatMap { $0.variableKind?.rawValue }.sorted()
return severityConfiguration.consoleDescription + ", excluded: \(simplifiedExcludedKinds)"
}

public init() {}

public mutating func apply(configuration: Any) throws {
guard let configuration = configuration as? [String: Any] else {
throw ConfigurationError.unknownConfiguration
}
for (key, value) in configuration {
switch (key, value) {
case ("severity", let severityString as String):
try severityConfiguration.apply(configuration: severityString)
case ("excluded", let excludedStrings as [String]):
let excludedKinds = excludedStrings.flatMap(VariableKind.init(rawValue:))
allowedKinds.subtract(excludedKinds.map(SwiftDeclarationKind.init(variableKind:)))
default:
throw ConfigurationError.unknownConfiguration
}
}
}

public static func == (lhs: ExplicitTypeInterfaceConfiguration, rhs: ExplicitTypeInterfaceConfiguration) -> Bool {
return lhs.allowedKinds == rhs.allowedKinds && lhs.severityConfiguration == rhs.severityConfiguration
}

}
13 changes: 13 additions & 0 deletions SwiftLint.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
094385011D5D2894009168CF /* WeakDelegateRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 094384FF1D5D2382009168CF /* WeakDelegateRule.swift */; };
094385041D5D4F7C009168CF /* PrivateOutletRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 094385021D5D4F78009168CF /* PrivateOutletRule.swift */; };
181D9E172038343D001F6887 /* UntypedErrorInCatchRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 181D9E162038343D001F6887 /* UntypedErrorInCatchRule.swift */; };
125AAC78203AA82D0004BCE0 /* ExplicitTypeInterfaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125AAC77203AA82D0004BCE0 /* ExplicitTypeInterfaceConfiguration.swift */; };
125CE52F20425EFD001635E5 /* ExplicitTypeInterfaceConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 125CE52E20425EFD001635E5 /* ExplicitTypeInterfaceConfigurationTests.swift */; };
12E3D4DC2042729300B3E30E /* ExplicitTypeInterfaceRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12E3D4DB2042729300B3E30E /* ExplicitTypeInterfaceRuleTests.swift */; };
187290721FC37CA50016BEA2 /* YodaConditionRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1872906F1FC37A9B0016BEA2 /* YodaConditionRule.swift */; };
1E18574B1EADBA51004F89F7 /* NoExtensionAccessModifierRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E18574A1EADBA51004F89F7 /* NoExtensionAccessModifierRule.swift */; };
1E3C2D711EE36C6F00C8386D /* PrivateOverFilePrivateRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E3C2D701EE36C6F00C8386D /* PrivateOverFilePrivateRule.swift */; };
Expand Down Expand Up @@ -367,6 +370,10 @@
094384FF1D5D2382009168CF /* WeakDelegateRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakDelegateRule.swift; sourceTree = "<group>"; };
094385021D5D4F78009168CF /* PrivateOutletRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateOutletRule.swift; sourceTree = "<group>"; };
181D9E162038343D001F6887 /* UntypedErrorInCatchRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UntypedErrorInCatchRule.swift; sourceTree = "<group>"; };
125AAC77203AA82D0004BCE0 /* ExplicitTypeInterfaceConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExplicitTypeInterfaceConfiguration.swift; sourceTree = "<group>"; };
125CE52E20425EFD001635E5 /* ExplicitTypeInterfaceConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExplicitTypeInterfaceConfigurationTests.swift; sourceTree = "<group>"; };
12E3D4DB2042729300B3E30E /* ExplicitTypeInterfaceRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExplicitTypeInterfaceRuleTests.swift; sourceTree = "<group>"; };
>>>>>>> upstream-master
1872906F1FC37A9B0016BEA2 /* YodaConditionRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YodaConditionRule.swift; sourceTree = "<group>"; };
1E18574A1EADBA51004F89F7 /* NoExtensionAccessModifierRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoExtensionAccessModifierRule.swift; sourceTree = "<group>"; };
1E3C2D701EE36C6F00C8386D /* PrivateOverFilePrivateRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateOverFilePrivateRule.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -736,6 +743,7 @@
D43B04671E07228D004016AF /* ColonConfiguration.swift */,
67EB4DF81E4CC101004E9ACD /* CyclomaticComplexityConfiguration.swift */,
62A498551F306A7700D766E4 /* DiscouragedDirectInitConfiguration.swift */,
125AAC77203AA82D0004BCE0 /* ExplicitTypeInterfaceConfiguration.swift */,
D4C4A3511DEFBBB700E0E04C /* FileHeaderConfiguration.swift */,
29FFC3781F1574FD007E4825 /* FileLengthRuleConfiguration.swift */,
47ACC8971E7DC74E0088EEB2 /* ImplicitlyUnwrappedOptionalConfiguration.swift */,
Expand Down Expand Up @@ -928,6 +936,8 @@
67EB4DFB1E4CD7F5004E9ACD /* CyclomaticComplexityRuleTests.swift */,
62AF35D71F30B183009B11EE /* DiscouragedDirectInitRuleTests.swift */,
D48B51221F4F5E4B0068AB98 /* DocumentationTests.swift */,
125CE52E20425EFD001635E5 /* ExplicitTypeInterfaceConfigurationTests.swift */,
12E3D4DB2042729300B3E30E /* ExplicitTypeInterfaceRuleTests.swift */,
02FD8AEE1BFC18D60014BFFB /* ExtendedNSStringTests.swift */,
D4998DE81DF194F20006E05D /* FileHeaderRuleTests.swift */,
29FFC37B1F157BA8007E4825 /* FileLengthRuleTests.swift */,
Expand Down Expand Up @@ -1543,6 +1553,7 @@
E847F0A91BFBBABD00EA9363 /* EmptyCountRule.swift in Sources */,
D46252541DF63FB200BE2CA1 /* NumberSeparatorRule.swift in Sources */,
E315B83C1DFA4BC500621B44 /* DynamicInlineRule.swift in Sources */,
125AAC78203AA82D0004BCE0 /* ExplicitTypeInterfaceConfiguration.swift in Sources */,
1E18574B1EADBA51004F89F7 /* NoExtensionAccessModifierRule.swift in Sources */,
D42D2B381E09CC0D00CD7A2E /* FirstWhereRule.swift in Sources */,
D4B0226F1E0C75F9007E5297 /* VerticalParameterAlignmentRule.swift in Sources */,
Expand Down Expand Up @@ -1715,6 +1726,7 @@
29FFC37D1F157BDE007E4825 /* FileLengthRuleTests.swift in Sources */,
006204DE1E1E4E0A00FFFBE1 /* VerticalWhitespaceRuleTests.swift in Sources */,
02FD8AEF1BFC18D60014BFFB /* ExtendedNSStringTests.swift in Sources */,
12E3D4DC2042729300B3E30E /* ExplicitTypeInterfaceRuleTests.swift in Sources */,
D48B51231F4F5E4B0068AB98 /* DocumentationTests.swift in Sources */,
D4CA758F1E2DEEA500A40E8A /* NumberSeparatorRuleTests.swift in Sources */,
D4DB92251E628898005DE9C1 /* TodoRuleTests.swift in Sources */,
Expand All @@ -1732,6 +1744,7 @@
E86396C71BADAFE6002C9E88 /* ReporterTests.swift in Sources */,
D43B04661E071ED3004016AF /* ColonRuleTests.swift in Sources */,
3B12C9C71C3361CB000B423F /* RuleTests.swift in Sources */,
125CE52F20425EFD001635E5 /* ExplicitTypeInterfaceConfigurationTests.swift in Sources */,
67EB4DFC1E4CD7F5004E9ACD /* CyclomaticComplexityRuleTests.swift in Sources */,
3B30C4A11C3785B300E04027 /* YamlParserTests.swift in Sources */,
3B20CD0A1EB699380069EF2E /* GenericTypeNameRuleTests.swift in Sources */,
Expand Down
22 changes: 21 additions & 1 deletion Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,25 @@ extension DocumentationTests {
]
}

extension ExplicitTypeInterfaceConfigurationTests {
static var allTests: [(String, (ExplicitTypeInterfaceConfigurationTests) -> () throws -> Void)] = [
("testDefaultConfiguration", testDefaultConfiguration),
("testApplyingCustomConfiguration", testApplyingCustomConfiguration),
("testInvalidKeyInCustomConfiguration", testInvalidKeyInCustomConfiguration),
("testInvalidTypeOfCustomConfiguration", testInvalidTypeOfCustomConfiguration),
("testInvalidTypeOfValueInCustomConfiguration", testInvalidTypeOfValueInCustomConfiguration),
("testConsoleDescription", testConsoleDescription)
]
}

extension ExplicitTypeInterfaceRuleTests {
static var allTests: [(String, (ExplicitTypeInterfaceRuleTests) -> () throws -> Void)] = [
("testExplicitTypeInterface", testExplicitTypeInterface),
("testExcludeLocalVars", testExcludeLocalVars),
("testExcludeClassVars", testExcludeClassVars)
]
}

extension ExtendedNSStringTests {
static var allTests: [(String, (ExtendedNSStringTests) -> () throws -> Void)] = [
("testLineAndCharacterForByteOffset_forContentsContainingMultibyteCharacters", testLineAndCharacterForByteOffset_forContentsContainingMultibyteCharacters)
Expand Down Expand Up @@ -403,7 +422,6 @@ extension RulesTests {
("testExplicitEnumRawValue", testExplicitEnumRawValue),
("testExplicitInit", testExplicitInit),
("testExplicitTopLevelACL", testExplicitTopLevelACL),
("testExplicitTypeInterface", testExplicitTypeInterface),
("testExtensionAccessModifier", testExtensionAccessModifier),
("testFallthrough", testFallthrough),
("testFatalErrorMessage", testFatalErrorMessage),
Expand Down Expand Up @@ -564,6 +582,8 @@ XCTMain([
testCase(CyclomaticComplexityRuleTests.allTests),
testCase(DiscouragedDirectInitRuleTests.allTests),
testCase(DocumentationTests.allTests),
testCase(ExplicitTypeInterfaceConfigurationTests.allTests),
testCase(ExplicitTypeInterfaceRuleTests.allTests),
testCase(ExtendedNSStringTests.allTests),
testCase(FileHeaderRuleTests.allTests),
testCase(FileLengthRuleTests.allTests),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// ExplicitTypeInterfaceConfigurationTests.swift
// SwiftLint
//
// Created by Rounak Jain on 2/24/18.
// Copyright © 2018 Realm. All rights reserved.
//

@testable import SwiftLintFramework
import XCTest

class ExplicitTypeInterfaceConfigurationTests: XCTestCase {

func testDefaultConfiguration() {
let config = ExplicitTypeInterfaceConfiguration()
XCTAssertEqual(config.severityConfiguration.severity, .warning)
XCTAssertEqual(config.allowedKinds, Set([.varInstance, .varClass, .varStatic, .varLocal]))
}

func testApplyingCustomConfiguration() throws {
var config = ExplicitTypeInterfaceConfiguration()
try config.apply(configuration: ["severity": "error",
"excluded": ["local"]])
XCTAssertEqual(config.severityConfiguration.severity, .error)
XCTAssertEqual(config.allowedKinds, Set([.varInstance, .varClass, .varStatic]))
}

func testInvalidKeyInCustomConfiguration() {
var config = ExplicitTypeInterfaceConfiguration()
checkError(ConfigurationError.unknownConfiguration) {
try config.apply(configuration: ["invalidKey": "error"])
}
}

func testInvalidTypeOfCustomConfiguration() {
var config = ExplicitTypeInterfaceConfiguration()
checkError(ConfigurationError.unknownConfiguration) {
try config.apply(configuration: "invalidKey")
}
}

func testInvalidTypeOfValueInCustomConfiguration() {
var config = ExplicitTypeInterfaceConfiguration()
checkError(ConfigurationError.unknownConfiguration) {
try config.apply(configuration: ["severity": 1])
}
}

func testConsoleDescription() throws {
var config = ExplicitTypeInterfaceConfiguration()
try config.apply(configuration: ["excluded": ["class", "instance"]])
XCTAssertEqual(config.consoleDescription, "warning, excluded: [\"class\", \"instance\"]")
}
}
47 changes: 47 additions & 0 deletions Tests/SwiftLintFrameworkTests/ExplicitTypeInterfaceRuleTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// ExplicitTypeInterfaceRuleTests.swift
// SwiftLint
//
// Created by Rounak Jain on 2/24/18.
// Copyright © 2018 Realm. All rights reserved.
//

import SwiftLintFramework
import XCTest

class ExplicitTypeInterfaceRuleTests: XCTestCase {

func testExplicitTypeInterface() {
verifyRule(ExplicitTypeInterfaceRule.description)
}

func testExcludeLocalVars() {
let nonTriggeringExamples = ExplicitTypeInterfaceRule.description.nonTriggeringExamples + [
"func foo() {\nlet intVal = 1\n}"
]
let triggeringExamples = ExplicitTypeInterfaceRule.description.triggeringExamples
let description = ExplicitTypeInterfaceRule.description
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)

verifyRule(description, ruleConfiguration: ["excluded": ["local"]])
}

func testExcludeClassVars() {
let nonTriggeringExamples = ExplicitTypeInterfaceRule.description.nonTriggeringExamples + [
"class Foo {\n static var myStaticVar = 0\n}\n",
"class Foo {\n static let myStaticLet = 0\n}\n"
]
let triggeringExamples = [
"class Foo {\n ↓var myVar = 0\n\n}\n",
"class Foo {\n ↓let mylet = 0\n\n}\n",
"class Foo {\n ↓class var myClassVar = 0\n}\n"
]
let description = ExplicitTypeInterfaceRule.description
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)

verifyRule(description, ruleConfiguration: ["excluded": ["static"]])
}

}
2 changes: 1 addition & 1 deletion Tests/SwiftLintFrameworkTests/ReporterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class ReporterTests: XCTestCase {
} else if let array = (result as? [Any])?.bridge() {
return array
}
fatalError("Unexpected value in JSON: \(result)")
queuedFatalError("Unexpected value in JSON: \(result)")
}
XCTAssertEqual(try jsonValue(result), try jsonValue(expectedOutput))
}
Expand Down
4 changes: 0 additions & 4 deletions Tests/SwiftLintFrameworkTests/RulesTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,6 @@ class RulesTests: XCTestCase {
verifyRule(ExplicitTopLevelACLRule.description)
}

func testExplicitTypeInterface() {
verifyRule(ExplicitTypeInterfaceRule.description)
}

func testExtensionAccessModifier() {
verifyRule(ExtensionAccessModifierRule.description)
}
Expand Down
Loading

0 comments on commit 749cdba

Please sign in to comment.