Skip to content

Commit

Permalink
Add private_only to prefixed_toplevel_constant (realm#2315)
Browse files Browse the repository at this point in the history
* Add private_only to prefixed_toplevel_constant

This allows users to opt in to only validate top level constants have
the given prefix if the constant is private or fileprivate.
  • Loading branch information
keith authored and Daniel.Metzing committed Aug 14, 2018
1 parent df77761 commit ef4b5cd
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
[Cihat Gündüz](https://github.com/Dschee)
[#2307](https://github.com/realm/SwiftLint/issues/2307)

* Add `private_only` configuration to `prefixed_toplevel_constant` rule
[Keith Smiley](https://github.com/keith)
[#2315](https://github.com/realm/SwiftLint/pull/2315)

#### Bug Fixes

* Fix an issue with `control_statement` where commas in clauses prevented the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Foundation
import SourceKittenFramework

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

private let topLevelPrefix = "k"

Expand Down Expand Up @@ -54,6 +54,11 @@ public struct PrefixedTopLevelConstantRule: ASTRule, OptInRule, ConfigurationPro
public func validate(file: File,
kind: SwiftDeclarationKind,
dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
if configuration.onlyPrivateMembers,
let acl = dictionary.accessibility.flatMap(AccessControlLevel.init(identifier:)), !acl.isPrivate {
return []
}

guard
kind == .varGlobal,
dictionary.setterAccessibility == nil,
Expand All @@ -66,7 +71,7 @@ public struct PrefixedTopLevelConstantRule: ASTRule, OptInRule, ConfigurationPro

return [
StyleViolation(ruleDescription: type(of: self).description,
severity: configuration.severity,
severity: configuration.severityConfiguration.severity,
location: Location(file: file, byteOffset: nameOffset))
]
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Foundation

public struct PrefixedConstantRuleConfiguration: RuleConfiguration, Equatable {
var severityConfiguration = SeverityConfiguration(.warning)
var onlyPrivateMembers = false

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

public init(onlyPrivateMembers: Bool) {
self.onlyPrivateMembers = onlyPrivateMembers
}

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

onlyPrivateMembers = (configuration["only_private"] as? Bool == true)

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

public func == (lhs: PrefixedConstantRuleConfiguration,
rhs: PrefixedConstantRuleConfiguration) -> Bool {
return lhs.onlyPrivateMembers == rhs.onlyPrivateMembers &&
lhs.severityConfiguration == rhs.severityConfiguration
}
20 changes: 14 additions & 6 deletions SwiftLint.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,9 @@
B89F3BCF1FD5EE1400931E59 /* RequiredEnumCaseRuleConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B89F3BC71FD5ED7D00931E59 /* RequiredEnumCaseRuleConfiguration.swift */; };
BB00B4E91F5216090079869F /* MultipleClosuresWithTrailingClosureRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB00B4E71F5216070079869F /* MultipleClosuresWithTrailingClosureRule.swift */; };
BFF028AE1CBCF8A500B38A9D /* TrailingWhitespaceConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF48D2D61CBCCA5F0080BDAE /* TrailingWhitespaceConfiguration.swift */; };
C25EBBDF2107884200E27603 /* PrefixedTopLevelConstantRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25EBBDD210787B200E27603 /* PrefixedTopLevelConstantRuleTests.swift */; };
C26330382073DAC500D7B4FD /* LowerACLThanParentRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C26330352073DAA200D7B4FD /* LowerACLThanParentRule.swift */; };
C28B2B3D2106DF730009A0FE /* PrefixedConstantRuleConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28B2B3B2106DF210009A0FE /* PrefixedConstantRuleConfiguration.swift */; };
C328A2F71E6759AE00A9E4D7 /* ExplicitTypeInterfaceRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C328A2F51E67595500A9E4D7 /* ExplicitTypeInterfaceRule.swift */; };
C3DE5DAC1E7DF9CA00761483 /* FatalErrorMessageRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DE5DAA1E7DF99B00761483 /* FatalErrorMessageRule.swift */; };
C946FECB1EAE67EE007DD778 /* LetVarWhitespaceRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = C946FEC91EAE5E20007DD778 /* LetVarWhitespaceRule.swift */; };
Expand Down Expand Up @@ -556,7 +558,9 @@
B89F3BCB1FD5EDA900931E59 /* RequiredEnumCaseRuleTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequiredEnumCaseRuleTestCase.swift; sourceTree = "<group>"; };
BB00B4E71F5216070079869F /* MultipleClosuresWithTrailingClosureRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultipleClosuresWithTrailingClosureRule.swift; sourceTree = "<group>"; };
BF48D2D61CBCCA5F0080BDAE /* TrailingWhitespaceConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrailingWhitespaceConfiguration.swift; sourceTree = "<group>"; };
C25EBBDD210787B200E27603 /* PrefixedTopLevelConstantRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefixedTopLevelConstantRuleTests.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>"; };
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>"; };
C946FEC91EAE5E20007DD778 /* LetVarWhitespaceRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LetVarWhitespaceRule.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -831,6 +835,7 @@
D4DA1DFD1E1A10DB0037413D /* NumberSeparatorConfiguration.swift */,
A1A6F3F11EE319ED00A9F9E2 /* ObjectLiteralConfiguration.swift */,
78F032471D7D614300BE709A /* OverridenSuperCallConfiguration.swift */,
C28B2B3B2106DF210009A0FE /* PrefixedConstantRuleConfiguration.swift */,
DAD3BE491D6ECD9500660239 /* PrivateOutletRuleConfiguration.swift */,
D4246D6C1F30D8620097E658 /* PrivateOverFilePrivateRuleConfiguration.swift */,
B2902A0D1D6681F700BFCCF7 /* PrivateUnitTestConfiguration.swift */,
Expand Down Expand Up @@ -1010,6 +1015,7 @@
D43B04651E071ED3004016AF /* ColonRuleTests.swift */,
E81ADD731ED6052F000CD451 /* CommandTests.swift */,
820F451D21073D7200AA056A /* ConditionalReturnsOnNewlineRuleTests.swift */,
D0D1212219E878CC005E4BAA /* Configuration */,
E809EDA21B8A73FB00399043 /* ConfigurationTests.swift */,
F480DC7E1F26090000099465 /* ConfigurationTests+Nested.swift */,
F480DC821F2609D700099465 /* ConfigurationTests+ProjectMock.swift */,
Expand All @@ -1036,20 +1042,23 @@
3B63D46E1E1F09DF0057BE35 /* LineLengthRuleTests.swift */,
D4C27BFF1E12DFF500DF713E /* LinterCacheTests.swift */,
1EB7C8521F0C45C2004BAD22 /* ModifierOrderTests.swift */,
D4CA758E1E2DEEA500A40E8A /* NumberSeparatorRuleTests.swift */,
B25DCD0F1F7EF6DC0028A199 /* MultilineArgumentsRuleTests.swift */,
D4CA758E1E2DEEA500A40E8A /* NumberSeparatorRuleTests.swift */,
825F19D01EEFF19700969EF1 /* ObjectLiteralRuleTests.swift */,
D4246D6E1F30DB260097E658 /* PrivateOverFilePrivateRuleTests.swift */,
C25EBBDD210787B200E27603 /* PrefixedTopLevelConstantRuleTests.swift */,
D4F5851820E99B5A0085C6D8 /* PrivateOutletRuleTests.swift */,
D4246D6E1F30DB260097E658 /* PrivateOverFilePrivateRuleTests.swift */,
E81ADD711ED5ED9D000CD451 /* RegionTests.swift */,
E86396C61BADAFE6002C9E88 /* ReporterTests.swift */,
B89F3BCB1FD5EDA900931E59 /* RequiredEnumCaseRuleTestCase.swift */,
3B12C9BE1C3209AC000B423F /* Resources */,
3BCC04D31C502BAB006073C3 /* RuleConfigurationTests.swift */,
D45255C71F0932F8003C9B56 /* RuleDescription+Examples.swift */,
E8BB8F9B1B17DE3B00199606 /* RulesTests.swift */,
3B12C9C61C3361CB000B423F /* RuleTests.swift */,
6C7045431C6ADA450003F15A /* SourceKitCrashTests.swift */,
D4F5851620E99B260085C6D8 /* StatementPositionRuleTests.swift */,
D0D1217C19E87B05005E4BAA /* Supporting Files */,
787CDE3A208F9C34005F3D2F /* SwitchCaseAlignmentRuleTests.swift */,
E81224991B04F85B001783D2 /* TestHelpers.swift */,
D4DB92241E628898005DE9C1 /* TodoRuleTests.swift */,
Expand All @@ -1059,11 +1068,8 @@
D4470D5A1EB76F44008A1B2E /* UnusedOptionalBindingRuleTests.swift */,
006204DD1E1E4E0A00FFFBE1 /* VerticalWhitespaceRuleTests.swift */,
F480DC801F2609AB00099465 /* XCTestCase+BundlePath.swift */,
3B12C9C21C320A53000B423F /* YamlSwiftLintTests.swift */,
3B30C4A01C3785B300E04027 /* YamlParserTests.swift */,
D0D1212219E878CC005E4BAA /* Configuration */,
3B12C9BE1C3209AC000B423F /* Resources */,
D0D1217C19E87B05005E4BAA /* Supporting Files */,
3B12C9C21C320A53000B423F /* YamlSwiftLintTests.swift */,
);
name = SwiftLintFrameworkTests;
path = Tests/SwiftLintFrameworkTests;
Expand Down Expand Up @@ -1764,6 +1770,7 @@
629C60D91F43906700B4AF92 /* SingleTestClassRule.swift in Sources */,
621061BF1ED57E640082D51E /* MultilineParametersRuleExamples.swift in Sources */,
D48AE2CC1DFB58C5001C6A4A /* AttributesRuleExamples.swift in Sources */,
C28B2B3D2106DF730009A0FE /* PrefixedConstantRuleConfiguration.swift in Sources */,
62A7127520F1178F00E604A6 /* AnyObjectProtocolRule.swift in Sources */,
E88DEA6F1B09843F00A66CB0 /* Location.swift in Sources */,
D43B046B1E075905004016AF /* ClosureEndIndentationRule.swift in Sources */,
Expand Down Expand Up @@ -1916,6 +1923,7 @@
D4F5851720E99B260085C6D8 /* StatementPositionRuleTests.swift in Sources */,
1EB7C8531F0C45C2004BAD22 /* ModifierOrderTests.swift in Sources */,
67932E2D1E54AF4B00CB0629 /* CyclomaticComplexityConfigurationTests.swift in Sources */,
C25EBBDF2107884200E27603 /* PrefixedTopLevelConstantRuleTests.swift in Sources */,
D4470D5B1EB76F44008A1B2E /* UnusedOptionalBindingRuleTests.swift in Sources */,
787CDE3B208F9C34005F3D2F /* SwitchCaseAlignmentRuleTests.swift in Sources */,
F480DC811F2609AB00099465 /* XCTestCase+BundlePath.swift in Sources */,
Expand Down
3 changes: 2 additions & 1 deletion Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,8 @@ extension PatternMatchingKeywordsRuleTests {

extension PrefixedTopLevelConstantRuleTests {
static var allTests: [(String, (PrefixedTopLevelConstantRuleTests) -> () throws -> Void)] = [
("testWithDefaultConfiguration", testWithDefaultConfiguration)
("testDefaultConfiguration", testDefaultConfiguration),
("testPrivateOnly", testPrivateOnly)
]
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,12 +390,6 @@ class PatternMatchingKeywordsRuleTests: XCTestCase {
}
}

class PrefixedTopLevelConstantRuleTests: XCTestCase {
func testWithDefaultConfiguration() {
verifyRule(PrefixedTopLevelConstantRule.description)
}
}

class PrivateActionRuleTests: XCTestCase {
func testWithDefaultConfiguration() {
verifyRule(PrivateActionRule.description)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@testable import SwiftLintFramework
import XCTest

final class PrefixedTopLevelConstantRuleTests: XCTestCase {
func testDefaultConfiguration() {
verifyRule(PrefixedTopLevelConstantRule.description)
}

func testPrivateOnly() {
let triggeringExamples = [
"private let ↓Foo = 20.0",
"fileprivate let ↓foo = 20.0"
]
let nonTriggeringExamples = [
"let Foo = 20.0",
"internal let Foo = \"Foo\"",
"public let Foo = 20.0"
]

let description = PrefixedTopLevelConstantRule.description
.with(triggeringExamples: triggeringExamples)
.with(nonTriggeringExamples: nonTriggeringExamples)

verifyRule(description, ruleConfiguration: ["only_private": true])
}
}

0 comments on commit ef4b5cd

Please sign in to comment.