Skip to content

Commit 67e8257

Browse files
authored
Merge pull request swiftlang#146 from google/no-space-after-line-comment-sigil
Make CommentWhitespace a lint-only rule.
2 parents c08d37d + cf9b211 commit 67e8257

File tree

3 files changed

+165
-262
lines changed

3 files changed

+165
-262
lines changed

Diff for: Sources/SwiftFormatRules/CommentWhitespace.swift

+17-80
Original file line numberDiff line numberDiff line change
@@ -10,109 +10,46 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
import Foundation
1413
import SwiftFormatCore
1514
import SwiftSyntax
1615

17-
/// At least two spaces before, and exactly one space after the `//` that begins a line comment.
16+
/// There are at least two spaces before the `//` that begins a line comment.
1817
///
19-
/// Lint: If an invalid number of spaces appear before or after a comment, a lint error is
20-
/// raised.
21-
///
22-
/// Format: All comments will have at least 2 spaces before, and a single space after, the `//`.
18+
/// Lint: If an invalid number of spaces appear before a comment, a lint error is raised.
2319
///
2420
/// - SeeAlso: https://google.github.io/swift#horizontal-whitespace
25-
public final class CommentWhitespace: SyntaxFormatRule {
26-
public override func visit (_ token: TokenSyntax) -> Syntax {
27-
var pieces = [TriviaPiece]()
28-
var validToken = token
29-
var needsWhitespaceFix = false
21+
public final class CommentWhitespace: SyntaxLintRule {
3022

31-
guard let nextToken = token.nextToken else {
32-
// In the case there is a line comment at the end of the file, it ensures
33-
// that the line comment has a single space after the `//`.
34-
pieces = checksSpacesAfterLineComment(isInvalid: &needsWhitespaceFix, token: token)
35-
return needsWhitespaceFix ? token.withLeadingTrivia(Trivia.init(pieces: pieces)) : token
36-
}
23+
public override func visit(_ token: TokenSyntax) {
24+
guard let nextToken = token.nextToken else { return }
3725

38-
// Ensures the line comment has at least 2 spaces before the `//`.
39-
if hasInlineLineComment(trivia: nextToken.leadingTrivia) {
40-
let numSpaces = token.trailingTrivia.numberOfSpaces
41-
if numSpaces < 2 {
42-
needsWhitespaceFix = true
43-
let addSpaces = 2 - numSpaces
44-
diagnose(.addSpacesBeforeLineComment(count: addSpaces), on:token)
45-
validToken = token.withTrailingTrivia(token.trailingTrivia.appending(.spaces(addSpaces)))
26+
// Ensures the line comment has at least two spaces before the `//`.
27+
if triviaIsEndOfLineComment(nextToken.leadingTrivia) {
28+
let numberOfSpaces = token.trailingTrivia.numberOfSpaces
29+
if numberOfSpaces < 2 {
30+
let spacesToAdd = 2 - numberOfSpaces
31+
diagnose(.addSpacesBeforeLineComment(count: spacesToAdd), on: token)
4632
}
4733
}
48-
49-
pieces = checksSpacesAfterLineComment(isInvalid: &needsWhitespaceFix, token: token)
50-
return needsWhitespaceFix ? validToken.withLeadingTrivia(Trivia.init(pieces: pieces)) : token
5134
}
5235

53-
/// Returns a boolean indicating if the given trivia contains
54-
/// a line comment inline with code.
55-
private func hasInlineLineComment (trivia: Trivia) -> Bool {
56-
// Comments are inline unless the trivia begins with a
57-
// with a newline.
36+
/// Returns a value indicating whether the given trivia represents an end of line comment.
37+
private func triviaIsEndOfLineComment(_ trivia: Trivia) -> Bool {
38+
// Comments are end-of-line unless the trivia begins with a newline.
5839
if let firstPiece = trivia.reversed().last {
59-
if case .newlines(_) = firstPiece {
60-
return false
61-
}
40+
if case .newlines(_) = firstPiece { return false }
6241
}
6342
for piece in trivia {
64-
if case .lineComment(_) = piece {
65-
return true
66-
}
43+
if case .lineComment(_) = piece { return true }
6744
}
6845
return false
6946
}
70-
71-
/// Ensures the line comment has exactly one space after the `//`.
72-
private func checksSpacesAfterLineComment(isInvalid: inout Bool, token: TokenSyntax) -> [TriviaPiece] {
73-
var pieces = [TriviaPiece]()
74-
75-
for piece in token.leadingTrivia {
76-
// Checks if the line comment has exactly one space after the `//`,
77-
// if it doesn't it removes or add an space, depending on what the
78-
// comment needs in order to follow the right format.
79-
if case .lineComment(let text) = piece,
80-
let formatText = formatLineComment(textLineComment: text, token: token) {
81-
isInvalid = true
82-
pieces.append(TriviaPiece.lineComment(formatText))
83-
}
84-
else {
85-
pieces.append(piece)
86-
}
87-
}
88-
return pieces
89-
}
90-
91-
/// Given a string with the text of a line comment, it ensures there
92-
/// is exactly one space after the `//`. If the string doesn't follow
93-
/// this rule a new string is returned with the right format.
94-
private func formatLineComment (textLineComment: String, token: TokenSyntax) -> String? {
95-
let text = textLineComment.dropFirst(2)
96-
if text.first != " " {
97-
diagnose(.addSpaceAfterLineComment, on: token)
98-
return "// " + text.trimmingCharacters(in: .whitespaces)
99-
}
100-
else if text.dropFirst(1).first == " " {
101-
diagnose(.removeSpacesAfterLineComment, on: token)
102-
return "// " + text.trimmingCharacters(in: .whitespaces)
103-
}
104-
return nil
105-
}
10647
}
10748

10849
extension Diagnostic.Message {
50+
10951
static func addSpacesBeforeLineComment(count: Int) -> Diagnostic.Message {
11052
let ending = count == 1 ? "" : "s"
11153
return Diagnostic.Message(.warning, "add \(count) space\(ending) before the //")
11254
}
113-
114-
static let addSpaceAfterLineComment =
115-
Diagnostic.Message(.warning, "add one space after `//`")
116-
static let removeSpacesAfterLineComment =
117-
Diagnostic.Message(.warning, "remove excess of spaces after the `//`")
11855
}

0 commit comments

Comments
 (0)