Skip to content

Commit 8abff1c

Browse files
LaurenWhiteallevato
authored andcommitted
Implement NoLeadingUnderscores rule and tests. (swiftlang#54)
1 parent bbd6fe5 commit 8abff1c

File tree

2 files changed

+200
-0
lines changed

2 files changed

+200
-0
lines changed

Sources/Rules/NoLeadingUnderscores.swift

+100
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,105 @@ import SwiftSyntax
1111
///
1212
/// - SeeAlso: https://google.github.io/swift#naming-conventions-are-not-access-control
1313
public final class NoLeadingUnderscores: SyntaxLintRule {
14+
15+
public override func visit(_ node: AssociatedtypeDeclSyntax) {
16+
diagnoseUnderscoreViolation(name: node.identifier)
17+
}
18+
19+
public override func visit(_ node: ClassDeclSyntax) {
20+
diagnoseUnderscoreViolation(name: node.identifier)
21+
super.visit(node) // Visit children despite override
22+
}
23+
24+
public override func visit(_ node: EnumDeclSyntax) {
25+
diagnoseUnderscoreViolation(name: node.identifier)
26+
super.visit(node)
27+
}
28+
29+
public override func visit(_ node: EnumCaseDeclSyntax) {
30+
for element in node.elements {
31+
diagnoseUnderscoreViolation(name: element.identifier)
32+
}
33+
}
34+
35+
public override func visit(_ node: FunctionDeclSyntax) {
36+
diagnoseUnderscoreViolation(name: node.identifier)
37+
// Check parameter names of function
38+
let parameters = node.signature.input.parameterList
39+
for parameter in parameters {
40+
if let typeIdentifier = parameter.firstName {
41+
diagnoseUnderscoreViolation(name: typeIdentifier)
42+
}
43+
if let varIdentifier = parameter.secondName {
44+
diagnoseUnderscoreViolation(name: varIdentifier)
45+
}
46+
}
47+
// Check generic parameter names
48+
if let genParameters = node.genericParameterClause?.genericParameterList {
49+
for genParameter in genParameters {
50+
diagnoseUnderscoreViolation(name: genParameter.name)
51+
}
52+
}
53+
super.visit(node)
54+
}
55+
56+
public override func visit(_ node: PrecedenceGroupDeclSyntax) {
57+
diagnoseUnderscoreViolation(name: node.identifier)
58+
}
59+
60+
public override func visit(_ node: ProtocolDeclSyntax) {
61+
diagnoseUnderscoreViolation(name: node.identifier)
62+
super.visit(node)
63+
}
64+
65+
public override func visit(_ node: StructDeclSyntax) {
66+
diagnoseUnderscoreViolation(name: node.identifier)
67+
// Check generic parameter names
68+
if let genParameters = node.genericParameterClause?.genericParameterList {
69+
for genParameter in genParameters {
70+
diagnoseUnderscoreViolation(name: genParameter.name)
71+
}
72+
}
73+
super.visit(node)
74+
}
75+
76+
public override func visit(_ node: TypealiasDeclSyntax) {
77+
diagnoseUnderscoreViolation(name: node.identifier)
78+
}
79+
80+
public override func visit(_ node: InitializerDeclSyntax) {
81+
// Check parameter names of initializer
82+
let parameters = node.parameters.parameterList
83+
for parameter in parameters {
84+
if let typeIdentifier = parameter.firstName {
85+
diagnoseUnderscoreViolation(name: typeIdentifier)
86+
}
87+
if let varIdentifier = parameter.secondName {
88+
diagnoseUnderscoreViolation(name: varIdentifier)
89+
}
90+
}
91+
super.visit(node)
92+
}
93+
94+
public override func visit(_ node: VariableDeclSyntax) {
95+
for binding in node.bindings {
96+
if let pat = binding.pattern as? IdentifierPatternSyntax {
97+
diagnoseUnderscoreViolation(name: pat.identifier)
98+
}
99+
}
100+
super.visit(node)
101+
}
102+
103+
func diagnoseUnderscoreViolation(name: TokenSyntax) {
104+
let leadingChar = name.text.first
105+
if leadingChar == "_" {
106+
diagnose(.doNotLeadWithUnderscore(identifier: name.text), on: name)
107+
}
108+
}
109+
}
14110

111+
extension Diagnostic.Message {
112+
static func doNotLeadWithUnderscore(identifier: String) -> Diagnostic.Message {
113+
return .init(.warning, "Identifier \(identifier) should not lead with '_'")
114+
}
15115
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import Foundation
2+
import SwiftSyntax
3+
import XCTest
4+
5+
@testable import Rules
6+
7+
public class NoLeadingUnderscoresTests: DiagnosingTestCase {
8+
public func testInvalidIdentifierNames() {
9+
let input =
10+
"""
11+
let _foo = foo
12+
var good_name = 20
13+
var _badName, okayName, _wor_sEName = 20
14+
struct _baz {
15+
var x: Int {
16+
get {
17+
var a = 10
18+
var _b = 20
19+
}
20+
set {
21+
var _c = 10
22+
var d = 20
23+
}
24+
}
25+
26+
init(foox z: Int, bar _y: Int) {}
27+
func _bazFunc(arg1: String, _arg2: Int) {}
28+
func quuxFunc(fooo _x: Int) {}
29+
}
30+
31+
protocol _SomeProtocol {
32+
func _food()
33+
}
34+
35+
struct Bag<_Element> {}
36+
func generic<_Arg>(x: _Arg) {}
37+
38+
enum Numbers {
39+
case one
40+
case _two
41+
case three
42+
}
43+
44+
func f() {
45+
var _x: Int = 10
46+
var y: Int = 20
47+
}
48+
"""
49+
performLint(NoLeadingUnderscores.self, input: input)
50+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_foo"))
51+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "good_name"))
52+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_badName"))
53+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "okayName"))
54+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_wor_sEName"))
55+
56+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_baz"))
57+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "x"))
58+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "a"))
59+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_b"))
60+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_c"))
61+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "d"))
62+
63+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "init"))
64+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "foox"))
65+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "z"))
66+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "bar"))
67+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_y"))
68+
69+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_bazFunc"))
70+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "arg1"))
71+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_arg2"))
72+
73+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "quuxFunc"))
74+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "fooo"))
75+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_x"))
76+
77+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_SomeProtocol"))
78+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_food"))
79+
80+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_Element"))
81+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "generic"))
82+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_Arg"))
83+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "x"))
84+
85+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "Numbers"))
86+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "one"))
87+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_two"))
88+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "three"))
89+
90+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "f"))
91+
XCTAssertDiagnosed(.doNotLeadWithUnderscore(identifier: "_x"))
92+
XCTAssertNotDiagnosed(.doNotLeadWithUnderscore(identifier: "y"))
93+
}
94+
95+
#if !os(macOS)
96+
static let allTests = [
97+
NoLeadingUnderscores.testInvalidIdentifierNames,
98+
]
99+
#endif
100+
}

0 commit comments

Comments
 (0)