Skip to content

Commit

Permalink
Adds opt-in prefixed_toplevel_constant rule
Browse files Browse the repository at this point in the history
Implements #1907.
  • Loading branch information
ornithocoder committed Jan 5, 2018
1 parent 34d2fb3 commit 1295c5d
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -35,6 +35,11 @@
[Ornithologist Coder](https://github.com/ornithocoder)
[#1987](https://github.com/realm/SwiftLint/issues/1987)

* Adds `prefixed_toplevel_constant` opt-in rule which encourages top-level
constants to be prefixed by `k`.
[Ornithologist Coder](https://github.com/ornithocoder)
[#1907](https://github.com/realm/SwiftLint/issues/1907)

##### Bug Fixes

* Fix false positives in `control_statement` rule when methods with keyword
Expand Down
80 changes: 80 additions & 0 deletions Rules.md
Expand Up @@ -75,6 +75,7 @@
* [Overridden methods call super](#overridden-methods-call-super)
* [Override in Extension](#override-in-extension)
* [Pattern Matching Keywords](#pattern-matching-keywords)
* [Prefixed Top-Level Constant](#prefixed-top-level-constant)
* [Private Actions](#private-actions)
* [Private Outlets](#private-outlets)
* [Private over fileprivate](#private-over-fileprivate)
Expand Down Expand Up @@ -8960,6 +8961,85 @@ switch foo {



## Prefixed Top-Level Constant

Identifier | Enabled by default | Supports autocorrection | Kind
--- | --- | --- | ---
`prefixed_toplevel_constant` | Disabled | No | style

Top-level constants should be prefixed by `k`.

### Examples

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

```swift
private let kFoo = 20.0
```

```swift
public let kFoo = false
```

```swift
internal let kFoo = "Foo"
```

```swift
let kFoo = true
```

```swift
struct Foo {
let bar = 20.0
}
```

```swift
private var foo = 20.0
```

```swift
public var foo = false
```

```swift
internal var foo = "Foo"
```

```swift
var foo = true
```

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

```swift
private let Foo = 20.0
```

```swift
public let Foo = false
```

```swift
internal let Foo = "Foo"
```

```swift
let Foo = true
```

```swift
let foo = 2, bar = true
```

</details>



## Private Actions

Identifier | Enabled by default | Supports autocorrection | Kind
Expand Down
1 change: 1 addition & 0 deletions Source/SwiftLintFramework/Models/MasterRuleList.swift
Expand Up @@ -83,6 +83,7 @@ public let masterRuleList = RuleList(rules: [
OverriddenSuperCallRule.self,
OverrideInExtensionRule.self,
PatternMatchingKeywordsRule.self,
PrefixedTopLevelConstantRule.self,
PrivateActionRule.self,
PrivateOutletRule.self,
PrivateOverFilePrivateRule.self,
Expand Down
62 changes: 62 additions & 0 deletions Source/SwiftLintFramework/Rules/PrefixedTopLevelConstantRule.swift
@@ -0,0 +1,62 @@
//
// PrefixedConstantRule.swift
// SwiftLint
//
// Created by Ornithologist Coder on 1/5/18.
// Copyright © 2018 Realm. All rights reserved.
//

import Foundation
import SourceKittenFramework

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

public init() {}

public static let description = RuleDescription(
identifier: "prefixed_toplevel_constant",
name: "Prefixed Top-Level Constant",
description: "Top-level constants should be prefixed by `k`.",
kind: .style,
nonTriggeringExamples: [
"private let kFoo = 20.0",
"public let kFoo = false",
"internal let kFoo = \"Foo\"",
"let kFoo = true",
"struct Foo {\n" +
" let bar = 20.0\n" +
"}",
"private var foo = 20.0",
"public var foo = false",
"internal var foo = \"Foo\"",
"var foo = true"
],
triggeringExamples: [
"private let ↓Foo = 20.0",
"public let ↓Foo = false",
"internal let ↓Foo = \"Foo\"",
"let ↓Foo = true",
"let ↓foo = 2, ↓bar = true"
]
)

public func validate(file: File,
kind: SwiftDeclarationKind,
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
guard
kind == .varGlobal,
let offset = dictionary.offset,
let nameOffset = dictionary.nameOffset,
let name = dictionary.name,
let content = file.contents.bridge().substringWithByteRange(start: offset, length: nameOffset - offset),
content.hasPrefix("let") && !name.hasPrefix("k")
else {
return []
}

return [StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
location: Location(file: file, byteOffset: nameOffset))]
}
}
4 changes: 4 additions & 0 deletions SwiftLint.xcodeproj/project.pbxproj
Expand Up @@ -83,6 +83,7 @@
629C60D91F43906700B4AF92 /* SingleTestClassRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 629C60D81F43906700B4AF92 /* SingleTestClassRule.swift */; };
62A498561F306A7700D766E4 /* DiscouragedDirectInitConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A498551F306A7700D766E4 /* DiscouragedDirectInitConfiguration.swift */; };
62A6E7931F3317E3003A0479 /* JoinedDefaultRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A6E7911F3317E3003A0479 /* JoinedDefaultRule.swift */; };
62DADC481FFF0423002B6319 /* PrefixedTopLevelConstantRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62DADC471FFF0423002B6319 /* PrefixedTopLevelConstantRule.swift */; };
62DEA1661FB21A9E00BCCCC6 /* PrivateActionRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62DEA1651FB21A9E00BCCCC6 /* PrivateActionRule.swift */; };
67932E2D1E54AF4B00CB0629 /* CyclomaticComplexityConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67932E2C1E54AF4B00CB0629 /* CyclomaticComplexityConfigurationTests.swift */; };
67EB4DFA1E4CC111004E9ACD /* CyclomaticComplexityConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67EB4DF81E4CC101004E9ACD /* CyclomaticComplexityConfiguration.swift */; };
Expand Down Expand Up @@ -430,6 +431,7 @@
62A498551F306A7700D766E4 /* DiscouragedDirectInitConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscouragedDirectInitConfiguration.swift; sourceTree = "<group>"; };
62A6E7911F3317E3003A0479 /* JoinedDefaultRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoinedDefaultRule.swift; sourceTree = "<group>"; };
62AF35D71F30B183009B11EE /* DiscouragedDirectInitRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscouragedDirectInitRuleTests.swift; sourceTree = "<group>"; };
62DADC471FFF0423002B6319 /* PrefixedTopLevelConstantRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefixedTopLevelConstantRule.swift; sourceTree = "<group>"; };
62DEA1651FB21A9E00BCCCC6 /* PrivateActionRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateActionRule.swift; sourceTree = "<group>"; };
62E54FED1F93AD57005B367B /* QuickDiscouragedFocusedTestRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickDiscouragedFocusedTestRule.swift; sourceTree = "<group>"; };
65454F451B14D73800319A6C /* ControlStatementRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControlStatementRule.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1092,6 +1094,7 @@
78F032441D7C877800BE709A /* OverriddenSuperCallRule.swift */,
D40FE89C1F867BFF006433E2 /* OverrideInExtensionRule.swift */,
D403A4A21F4DB5510020CA02 /* PatternMatchingKeywordsRule.swift */,
62DADC471FFF0423002B6319 /* PrefixedTopLevelConstantRule.swift */,
62DEA1651FB21A9E00BCCCC6 /* PrivateActionRule.swift */,
094385021D5D4F78009168CF /* PrivateOutletRule.swift */,
1E3C2D701EE36C6F00C8386D /* PrivateOverFilePrivateRule.swift */,
Expand Down Expand Up @@ -1557,6 +1560,7 @@
57ED827B1CF656E3002B3513 /* JUnitReporter.swift in Sources */,
D43B04691E072291004016AF /* ColonConfiguration.swift in Sources */,
E82367E01ED3BD1E0040A88E /* Configuration+Cache.swift in Sources */,
62DADC481FFF0423002B6319 /* PrefixedTopLevelConstantRule.swift in Sources */,
D4130D991E16CC1300242361 /* TypeNameRuleExamples.swift in Sources */,
24E17F721B14BB3F008195BE /* File+Cache.swift in Sources */,
47ACC8981E7DC74E0088EEB2 /* ImplicitlyUnwrappedOptionalConfiguration.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions Tests/LinuxMain.swift
Expand Up @@ -438,6 +438,7 @@ extension RulesTests {
("testOperatorUsageWhitespace", testOperatorUsageWhitespace),
("testOverrideInExtension", testOverrideInExtension),
("testPatternMatchingKeywords", testPatternMatchingKeywords),
("testPrefixedTopLevelConstant", testPrefixedTopLevelConstant),
("testPrivateAction", testPrivateAction),
("testPrivateOutlet", testPrivateOutlet),
("testPrivateUnitTest", testPrivateUnitTest),
Expand Down
4 changes: 4 additions & 0 deletions Tests/SwiftLintFrameworkTests/RulesTests.swift
Expand Up @@ -259,6 +259,10 @@ class RulesTests: XCTestCase {
verifyRule(PatternMatchingKeywordsRule.description)
}

func testPrefixedTopLevelConstant() {
verifyRule(PrefixedTopLevelConstantRule.description)
}

func testPrivateAction() {
verifyRule(PrivateActionRule.description)
}
Expand Down

0 comments on commit 1295c5d

Please sign in to comment.