Skip to content

Commit

Permalink
Add discouraged_direct_init opt-in rule
Browse files Browse the repository at this point in the history
Rule requested by @Noobish1 on issue #1306.
  • Loading branch information
ornithocoder committed Aug 1, 2017
1 parent cca1060 commit 13c7e6e
Show file tree
Hide file tree
Showing 7 changed files with 288 additions and 7 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@
[Marcelo Fabri](https://github.com/marcelofabri)
[#1719](https://github.com/realm/SwiftLint/issues/1719)

* Add `discouraged_direct_init` opt-in rule that discourages direct
initialization of certain types.
[Ornithologist Coder](https://github.com/ornithocoder)
[#1306](https://github.com/realm/SwiftLint/issues/1306)

##### Bug Fixes

* Fix false positive on `redundant_discardable_let` rule when using
Expand Down
86 changes: 86 additions & 0 deletions Rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* [Custom Rules](#custom-rules)
* [Cyclomatic Complexity](#cyclomatic-complexity)
* [Discarded Notification Center Observer](#discarded-notification-center-observer)
* [Discouraged Direct Initialization](#discouraged-direct-initialization)
* [Dynamic Inline](#dynamic-inline)
* [Empty Count](#empty-count)
* [Empty Enum Arguments](#empty-enum-arguments)
Expand Down Expand Up @@ -1627,6 +1628,91 @@ func foo() -> Any {



## Discouraged Direct Initialization

Identifier | Enabled by default | Supports autocorrection | Kind
--- | --- | --- | ---
`discouraged_direct_init` | Disabled | No | lint

Discouraged direct initialization of types that can be harmful.

### Examples

<details>
<summary>Non Triggering Examples</summary>

```swift
let foo = UIDevice.current
```

```swift
let foo = Bundle.main
```

```swift
let foo = Bundle(path: "bar")
```

```swift
let foo = Bundle(identifier: "bar")
```

```swift
let foo = Bundle.init(path: "bar")
```

```swift
let foo = Bundle.init(identifier: "bar")
```

</details>
<details>
<summary>Triggering Examples</summary>

```swift
UIDevice()
```

```swift
Bundle()
```

```swift
let foo = UIDevice()
```

```swift
let foo = Bundle()
```

```swift
let foo = bar(bundle: Bundle(), device: UIDevice())
```

```swift
UIDevice.init()
```

```swift
Bundle.init()
```

```swift
let foo = UIDevice.init()
```

```swift
let foo = Bundle.init()
```

```swift
let foo = bar(bundle: Bundle.init(), device: UIDevice.init())
```

</details>



## Dynamic Inline

Identifier | Enabled by default | Supports autocorrection | Kind
Expand Down
1 change: 1 addition & 0 deletions Source/SwiftLintFramework/Models/MasterRuleList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public let masterRuleList = RuleList(rules: [
CustomRules.self,
CyclomaticComplexityRule.self,
DiscardedNotificationCenterObserverRule.self,
DiscouragedDirectInitRule.self,
DynamicInlineRule.self,
EmptyCountRule.self,
EmptyEnumArgumentsRule.self,
Expand Down
61 changes: 61 additions & 0 deletions Source/SwiftLintFramework/Rules/DiscouragedDirectInitRule.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// DiscourageInitRule.swift
// SwiftLint
//
// Created by Ornithologist Coder on 8/1/17.
// Copyright © 2017 Realm. All rights reserved.
//

import Foundation
import SourceKittenFramework

public struct DiscouragedDirectInitRule: ASTRule, OptInRule, ConfigurationProviderRule {
public var configuration = DiscouragedDirectInitConfiguration()

public init() {}

public static let description = RuleDescription(
identifier: "discouraged_direct_init",
name: "Discouraged Direct Initialization",
description: "Discouraged direct initialization of types that can be harmful.",
kind: .lint,
nonTriggeringExamples: [
"let foo = UIDevice.current",
"let foo = Bundle.main",
"let foo = Bundle(path: \"bar\")",
"let foo = Bundle(identifier: \"bar\")",
"let foo = Bundle.init(path: \"bar\")",
"let foo = Bundle.init(identifier: \"bar\")"
],
triggeringExamples: [
"↓UIDevice()",
"↓Bundle()",
"let foo = ↓UIDevice()",
"let foo = ↓Bundle()",
"let foo = bar(bundle: ↓Bundle(), device: ↓UIDevice())",
"↓UIDevice.init()",
"↓Bundle.init()",
"let foo = ↓UIDevice.init()",
"let foo = ↓Bundle.init()",
"let foo = bar(bundle: ↓Bundle.init(), device: ↓UIDevice.init())"
]
)

public func validate(file: File,
kind: SwiftExpressionKind,
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
guard
kind == .call,
let offset = dictionary.nameOffset,
let name = dictionary.name,
dictionary.bodyLength == 0,
configuration.discouragedInits.contains(name)
else {
return []
}

return [StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
location: Location(file: file, byteOffset: offset))]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// DiscouragedInitConfiguration.swift
// SwiftLint
//
// Created by Ornithologist Coder on 8/1/17.
// Copyright © 2017 Realm. All rights reserved.
//

import Foundation
import SourceKittenFramework

private func toExplicitInitMethod(typeName: String) -> String {
return "\(typeName).init"
}

public struct DiscouragedDirectInitConfiguration: RuleConfiguration, Equatable {
public var severityConfiguration = SeverityConfiguration(.warning)

public var consoleDescription: String {
return severityConfiguration.consoleDescription + ", included: \(discouragedInits)"
}

public var severity: ViolationSeverity {
return severityConfiguration.severity
}

private(set) public var discouragedInits: Set<String>

private let defaultDiscouragedInits = [
"Bundle",
"UIDevice"
]

init() {
discouragedInits = Set(defaultDiscouragedInits + defaultDiscouragedInits.map(toExplicitInitMethod))
}

// MARK: - RuleConfiguration

public mutating func apply(configuration: Any) throws {
guard let configuration = configuration as? [String: Any] else {
throw ConfigurationError.unknownConfiguration
}

if let severityString = configuration["severity"] as? String {
try severityConfiguration.apply(configuration: severityString)
}

if let included = [String].array(of: configuration["included"]) {
discouragedInits = Set(included + included.map(toExplicitInitMethod))
}
}

// MARK: - Equatable

public static func == (lhs: DiscouragedDirectInitConfiguration, rhs: DiscouragedDirectInitConfiguration) -> Bool {
return lhs.discouragedInits == rhs.discouragedInits && lhs.severityConfiguration == rhs.severityConfiguration
}
}
26 changes: 19 additions & 7 deletions SwiftLint.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@
4DCB8E7F1CBE494E0070FCF0 /* RegexHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DCB8E7D1CBE43640070FCF0 /* RegexHelpers.swift */; };
57ED827B1CF656E3002B3513 /* JUnitReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57ED82791CF65183002B3513 /* JUnitReporter.swift */; };
621061BF1ED57E640082D51E /* MultilineParametersRuleExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621061BE1ED57E640082D51E /* MultilineParametersRuleExamples.swift */; };
62329C2B1F30B2310035737E /* DiscouragedDirectInitRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62AF35D71F30B183009B11EE /* DiscouragedDirectInitRuleTests.swift */; };
6250D32A1ED4DFEB00735129 /* MultilineParametersRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6238AE411ED4D734006C3601 /* MultilineParametersRule.swift */; };
62622F6B1F2F2E3500D5D099 /* DiscouragedDirectInitRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62622F6A1F2F2E3500D5D099 /* DiscouragedDirectInitRule.swift */; };
62A498561F306A7700D766E4 /* DiscouragedDirectInitConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A498551F306A7700D766E4 /* DiscouragedDirectInitConfiguration.swift */; };
67932E2D1E54AF4B00CB0629 /* CyclomaticComplexityConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67932E2C1E54AF4B00CB0629 /* CyclomaticComplexityConfigurationTests.swift */; };
67EB4DFA1E4CC111004E9ACD /* CyclomaticComplexityConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB4DF81E4CC101004E9ACD /* CyclomaticComplexityConfiguration.swift */; };
67EB4DFC1E4CD7F5004E9ACD /* CyclomaticComplexityRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB4DFB1E4CD7F5004E9ACD /* CyclomaticComplexityRuleTests.swift */; };
Expand Down Expand Up @@ -365,6 +368,9 @@
57ED82791CF65183002B3513 /* JUnitReporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JUnitReporter.swift; sourceTree = "<group>"; };
621061BE1ED57E640082D51E /* MultilineParametersRuleExamples.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilineParametersRuleExamples.swift; sourceTree = "<group>"; };
6238AE411ED4D734006C3601 /* MultilineParametersRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultilineParametersRule.swift; sourceTree = "<group>"; };
62622F6A1F2F2E3500D5D099 /* DiscouragedDirectInitRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscouragedDirectInitRule.swift; sourceTree = "<group>"; };
62A498551F306A7700D766E4 /* DiscouragedDirectInitConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscouragedDirectInitConfiguration.swift; sourceTree = "<group>"; };
62AF35D71F30B183009B11EE /* DiscouragedDirectInitRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscouragedDirectInitRuleTests.swift; sourceTree = "<group>"; };
65454F451B14D73800319A6C /* ControlStatementRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControlStatementRule.swift; sourceTree = "<group>"; };
67932E2C1E54AF4B00CB0629 /* CyclomaticComplexityConfigurationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CyclomaticComplexityConfigurationTests.swift; sourceTree = "<group>"; };
67EB4DF81E4CC101004E9ACD /* CyclomaticComplexityConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CyclomaticComplexityConfiguration.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -629,6 +635,7 @@
D4C4A34A1DEA4FD700E0E04C /* AttributesConfiguration.swift */,
D43B04671E07228D004016AF /* ColonConfiguration.swift */,
67EB4DF81E4CC101004E9ACD /* CyclomaticComplexityConfiguration.swift */,
62A498551F306A7700D766E4 /* DiscouragedDirectInitConfiguration.swift */,
D4C4A3511DEFBBB700E0E04C /* FileHeaderConfiguration.swift */,
29FFC3781F1574FD007E4825 /* FileLengthRuleConfiguration.swift */,
47ACC8971E7DC74E0088EEB2 /* ImplicitlyUnwrappedOptionalConfiguration.swift */,
Expand All @@ -647,8 +654,8 @@
725094881D0855760039B353 /* StatementPositionConfiguration.swift */,
D40F83871DE9179200524C62 /* TrailingCommaConfiguration.swift */,
BF48D2D61CBCCA5F0080BDAE /* TrailingWhitespaceConfiguration.swift */,
006204DA1E1E48F900FFFBE1 /* VerticalWhitespaceConfiguration.swift */,
CE8178EB1EAC02CD0063186E /* UnusedOptionalBindingConfiguration.swift */,
006204DA1E1E48F900FFFBE1 /* VerticalWhitespaceConfiguration.swift */,
);
path = RuleConfigurations;
sourceTree = "<group>";
Expand Down Expand Up @@ -807,16 +814,14 @@
D0D1217B19E87B05005E4BAA /* SwiftLintFrameworkTests */ = {
isa = PBXGroup;
children = (
D0D1212219E878CC005E4BAA /* Configuration */,
3B12C9BE1C3209AC000B423F /* Resources */,
D0D1217C19E87B05005E4BAA /* Supporting Files */,
D4998DE61DF191380006E05D /* AttributesRuleTests.swift */,
D43B04651E071ED3004016AF /* ColonRuleTests.swift */,
E81ADD731ED6052F000CD451 /* CommandTests.swift */,
E809EDA21B8A73FB00399043 /* ConfigurationTests.swift */,
3BB47D861C51DE6E00AE6A10 /* CustomRulesTests.swift */,
67932E2C1E54AF4B00CB0629 /* CyclomaticComplexityConfigurationTests.swift */,
67EB4DFB1E4CD7F5004E9ACD /* CyclomaticComplexityRuleTests.swift */,
62AF35D71F30B183009B11EE /* DiscouragedDirectInitRuleTests.swift */,
02FD8AEE1BFC18D60014BFFB /* ExtendedNSStringTests.swift */,
D4998DE81DF194F20006E05D /* FileHeaderRuleTests.swift */,
29FFC37B1F157BA8007E4825 /* FileLengthRuleTests.swift */,
Expand All @@ -834,6 +839,7 @@
E81ADD711ED5ED9D000CD451 /* RegionTests.swift */,
E86396C61BADAFE6002C9E88 /* ReporterTests.swift */,
3BCC04D31C502BAB006073C3 /* RuleConfigurationTests.swift */,
D45255C71F0932F8003C9B56 /* RuleDescription+Examples.swift */,
E8BB8F9B1B17DE3B00199606 /* RulesTests.swift */,
3B12C9C61C3361CB000B423F /* RuleTests.swift */,
6C7045431C6ADA450003F15A /* SourceKitCrashTests.swift */,
Expand All @@ -845,7 +851,9 @@
006204DD1E1E4E0A00FFFBE1 /* VerticalWhitespaceRuleTests.swift */,
3B12C9C21C320A53000B423F /* Yaml+SwiftLintTests.swift */,
3B30C4A01C3785B300E04027 /* YamlParserTests.swift */,
D45255C71F0932F8003C9B56 /* RuleDescription+Examples.swift */,
D0D1212219E878CC005E4BAA /* Configuration */,
3B12C9BE1C3209AC000B423F /* Resources */,
D0D1217C19E87B05005E4BAA /* Supporting Files */,
);
name = SwiftLintFrameworkTests;
path = Tests/SwiftLintFrameworkTests;
Expand Down Expand Up @@ -899,8 +907,8 @@
children = (
D47A510F1DB2DD4800A4CC21 /* AttributesRule.swift */,
D48AE2CB1DFB58C5001C6A4A /* AttributesRulesExamples.swift */,
D4B0228D1E0CC608007E5297 /* ClassDelegateProtocolRule.swift */,
D4FD4C841F2A260A00DD8AA8 /* BlockBasedKVORule.swift */,
D4B0228D1E0CC608007E5297 /* ClassDelegateProtocolRule.swift */,
1F11B3CE1C252F23002E8FA8 /* ClosingBraceRule.swift */,
D43B046A1E075905004016AF /* ClosureEndIndentationRule.swift */,
D47079A81DFDBED000027086 /* ClosureParameterPositionRule.swift */,
Expand All @@ -913,6 +921,7 @@
3B1DF0111C5148140011BCED /* CustomRules.swift */,
2E02005E1C54BF680024D09D /* CyclomaticComplexityRule.swift */,
D4DABFD21E29B4A5009617B6 /* DiscardedNotificationCenterObserverRule.swift */,
62622F6A1F2F2E3500D5D099 /* DiscouragedDirectInitRule.swift */,
E315B83B1DFA4BC500621B44 /* DynamicInlineRule.swift */,
E847F0A81BFBBABD00EA9363 /* EmptyCountRule.swift */,
D4470D581EB6B4D1008A1B2E /* EmptyEnumArgumentsRule.swift */,
Expand Down Expand Up @@ -962,8 +971,8 @@
E5A167C81B25A0B000CF2D03 /* OperatorFunctionWhitespaceRule.swift */,
D4FBADCF1E00DA0400669C73 /* OperatorUsageWhitespaceRule.swift */,
78F032441D7C877800BE709A /* OverriddenSuperCallRule.swift */,
1E3C2D701EE36C6F00C8386D /* PrivateOverFilePrivateRule.swift */,
094385021D5D4F78009168CF /* PrivateOutletRule.swift */,
1E3C2D701EE36C6F00C8386D /* PrivateOverFilePrivateRule.swift */,
B2902A0B1D66815600BFCCF7 /* PrivateUnitTestRule.swift */,
009E09271DFEE4C200B588A7 /* ProhibitedSuperRule.swift */,
D47F31141EC918B600E3E1CA /* ProtocolPropertyAccessorsOrderRule.swift */,
Expand Down Expand Up @@ -1442,6 +1451,7 @@
E80746F61ECB722F00548D31 /* CacheDescriptionProvider.swift in Sources */,
094385041D5D4F7C009168CF /* PrivateOutletRule.swift in Sources */,
E88DEA6B1B0983FE00A66CB0 /* StyleViolation.swift in Sources */,
62622F6B1F2F2E3500D5D099 /* DiscouragedDirectInitRule.swift in Sources */,
3BB47D831C514E8100AE6A10 /* RegexConfiguration.swift in Sources */,
D401D9261ED85EF0005DA5D4 /* RuleKind.swift in Sources */,
D4C889711E385B7B00BAE88D /* RedundantDiscardableLetRule.swift in Sources */,
Expand All @@ -1451,6 +1461,7 @@
29FFC37A1F15764D007E4825 /* FileLengthRuleConfiguration.swift in Sources */,
3B5B9FE11C444DA20009AD27 /* Array+SwiftLint.swift in Sources */,
D43B04641E0620AB004016AF /* UnusedEnumeratedRule.swift in Sources */,
62A498561F306A7700D766E4 /* DiscouragedDirectInitConfiguration.swift in Sources */,
C946FECB1EAE67EE007DD778 /* LetVarWhitespaceRule.swift in Sources */,
E881985D1BEA97EB00333A11 /* TrailingWhitespaceRule.swift in Sources */,
E832F10B1B17E2F5003F265F /* NSFileManager+SwiftLint.swift in Sources */,
Expand Down Expand Up @@ -1499,6 +1510,7 @@
E812249A1B04F85B001783D2 /* TestHelpers.swift in Sources */,
3B20CD0C1EB699C20069EF2E /* TypeNameRuleTests.swift in Sources */,
3B3A9A331EA3DFD90075B121 /* IdentifierNameRuleTests.swift in Sources */,
62329C2B1F30B2310035737E /* DiscouragedDirectInitRuleTests.swift in Sources */,
E86396C71BADAFE6002C9E88 /* ReporterTests.swift in Sources */,
D43B04661E071ED3004016AF /* ColonRuleTests.swift in Sources */,
3B12C9C71C3361CB000B423F /* RuleTests.swift in Sources */,
Expand Down
Loading

0 comments on commit 13c7e6e

Please sign in to comment.