Skip to content

Commit 17bdbde

Browse files
atamez31allevato
authored andcommitted
Implementation of OneSpaceAfterKeywords (swiftlang#67)
1 parent 6050094 commit 17bdbde

File tree

2 files changed

+229
-0
lines changed

2 files changed

+229
-0
lines changed

tools/swift-format/Sources/Rules/OneSpaceAfterKeywords.swift

+190
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,195 @@ import SwiftSyntax
1111
///
1212
/// - SeeAlso: https://google.github.io/swift#horizontal-whitespace
1313
public final class OneSpaceAfterKeywords: SyntaxFormatRule {
14+
public override func visit(_ token: TokenSyntax) -> Syntax {
15+
guard let nextToken = token.nextToken else { return token }
16+
17+
// Keywords own their trailing spaces, so ensure it only has 1, if there's
18+
// another token on the same line.
19+
if token.tokenKind.isTypeKeyword,
20+
(nextToken.tokenKind.isTypeKeyword || isIdentifier(nextToken.tokenKind)),
21+
!nextToken.leadingTrivia.containsNewlines {
22+
let numSpaces = token.trailingTrivia.numberOfSpaces
23+
if numSpaces > 1 {
24+
diagnose(.removeSpacesAfterKeyword(numSpaces - 1, token.description), on: token)
25+
return token.withOneTrailingSpace()
26+
}
27+
}
28+
return token
29+
}
30+
}
31+
32+
/// Indicates if the token kind is an identifier
33+
func isIdentifier(_ tokKind: TokenKind) -> Bool {
34+
if case .identifier(_) = tokKind {
35+
return true
36+
}
37+
return false
38+
}
39+
extension Diagnostic.Message {
40+
static func removeSpacesAfterKeyword(_ count: Int, _ keyWord: String) -> Diagnostic.Message {
41+
let ending = count == 1 ? "" : "s"
42+
return Diagnostic.Message(.warning, "remove \(count) space\(ending) after '\(keyWord)'")
43+
}
44+
}
1445

46+
extension TokenKind {
47+
48+
// Indicates if the token kind is a keyword.
49+
var isTypeKeyword: Bool {
50+
switch self {
51+
case .associatedtypeKeyword:
52+
return true
53+
case .classKeyword:
54+
return true
55+
case .enumKeyword:
56+
return true
57+
case .extensionKeyword:
58+
return true
59+
case .funcKeyword:
60+
return true
61+
case .importKeyword:
62+
return true
63+
case .initKeyword:
64+
return true
65+
case .inoutKeyword:
66+
return true
67+
case .letKeyword:
68+
return true
69+
case .operatorKeyword:
70+
return true
71+
case .precedencegroupKeyword:
72+
return true
73+
case .protocolKeyword:
74+
return true
75+
case .structKeyword:
76+
return true
77+
case .subscriptKeyword:
78+
return true
79+
case .typealiasKeyword:
80+
return true
81+
case .varKeyword:
82+
return true
83+
case .fileprivateKeyword:
84+
return true
85+
case .internalKeyword:
86+
return true
87+
case .privateKeyword:
88+
return true
89+
case .publicKeyword:
90+
return true
91+
case .staticKeyword:
92+
return true
93+
case .deferKeyword:
94+
return true
95+
case .ifKeyword:
96+
return true
97+
case .guardKeyword:
98+
return true
99+
case .doKeyword:
100+
return true
101+
case .repeatKeyword:
102+
return true
103+
case .elseKeyword:
104+
return true
105+
case .forKeyword:
106+
return true
107+
case .inKeyword:
108+
return true
109+
case .whileKeyword:
110+
return true
111+
case .returnKeyword:
112+
return true
113+
case .breakKeyword:
114+
return true
115+
case .continueKeyword:
116+
return true
117+
case .fallthroughKeyword:
118+
return true
119+
case .switchKeyword:
120+
return true
121+
case .caseKeyword:
122+
return true
123+
case .defaultKeyword:
124+
return true
125+
case .whereKeyword:
126+
return true
127+
case .catchKeyword:
128+
return true
129+
case .asKeyword:
130+
return true
131+
case .anyKeyword:
132+
return true
133+
case .falseKeyword:
134+
return true
135+
case .isKeyword:
136+
return true
137+
case .nilKeyword:
138+
return true
139+
case .rethrowsKeyword:
140+
return true
141+
case .superKeyword:
142+
return true
143+
case .selfKeyword:
144+
return true
145+
case .capitalSelfKeyword:
146+
return true
147+
case .throwKeyword:
148+
return true
149+
case .trueKeyword:
150+
return true
151+
case .tryKeyword:
152+
return true
153+
case .throwsKeyword:
154+
return true
155+
case .__file__Keyword:
156+
return true
157+
case .__line__Keyword:
158+
return true
159+
case .__column__Keyword:
160+
return true
161+
case .__function__Keyword:
162+
return true
163+
case .__dso_handle__Keyword:
164+
return true
165+
case .wildcardKeyword:
166+
return true
167+
case .poundAvailableKeyword:
168+
return true
169+
case .poundEndifKeyword:
170+
return true
171+
case .poundElseKeyword:
172+
return true
173+
case .poundElseifKeyword:
174+
return true
175+
case .poundIfKeyword:
176+
return true
177+
case .poundSourceLocationKeyword:
178+
return true
179+
case .poundFileKeyword:
180+
return true
181+
case .poundLineKeyword:
182+
return true
183+
case .poundColumnKeyword:
184+
return true
185+
case .poundDsohandleKeyword:
186+
return true
187+
case .poundFunctionKeyword:
188+
return true
189+
case .poundSelectorKeyword:
190+
return true
191+
case .poundKeyPathKeyword:
192+
return true
193+
case .poundColorLiteralKeyword:
194+
return true
195+
case .poundFileLiteralKeyword:
196+
return true
197+
case .poundImageLiteralKeyword:
198+
return true
199+
case .contextualKeyword(_):
200+
return true
201+
default:
202+
return false
203+
}
204+
}
15205
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import SwiftSyntax
2+
import XCTest
3+
4+
@testable import Rules
5+
6+
public class OneSpaceAfterKeywordsTests: DiagnosingTestCase {
7+
public func testInvalidOneSpaceAfterKeywordsTests() {
8+
XCTAssertFormatting(
9+
OneSpaceAfterKeywords.self,
10+
input: """
11+
let v1 = "Test"
12+
var values: Values
13+
func isIdentifier(_ tokKind: TokenKind) -> Bool {
14+
guard let first = v1.first else { return false }
15+
if case .identifier(_) = tokKind {
16+
return true
17+
}
18+
return false
19+
}
20+
""",
21+
expected: """
22+
let v1 = "Test"
23+
var values: Values
24+
func isIdentifier(_ tokKind: TokenKind) -> Bool {
25+
guard let first = v1.first else { return false }
26+
if case .identifier(_) = tokKind {
27+
return true
28+
}
29+
return false
30+
}
31+
""")
32+
}
33+
34+
#if !os(macOS)
35+
static let allTests = [
36+
OneSpaceAfterKeywordsTests.testInvalidOneSpaceAfterKeywordsTests,
37+
]
38+
#endif
39+
}

0 commit comments

Comments
 (0)