|
10 | 10 | //
|
11 | 11 | //===----------------------------------------------------------------------===//
|
12 | 12 |
|
13 |
| -import Foundation |
14 | 13 | import SwiftFormatCore
|
15 | 14 | import SwiftSyntax
|
16 | 15 |
|
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. |
18 | 17 | ///
|
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. |
23 | 19 | ///
|
24 | 20 | /// - 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 { |
30 | 22 |
|
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 } |
37 | 25 |
|
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) |
46 | 32 | }
|
47 | 33 | }
|
48 |
| - |
49 |
| - pieces = checksSpacesAfterLineComment(isInvalid: &needsWhitespaceFix, token: token) |
50 |
| - return needsWhitespaceFix ? validToken.withLeadingTrivia(Trivia.init(pieces: pieces)) : token |
51 | 34 | }
|
52 | 35 |
|
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. |
58 | 39 | if let firstPiece = trivia.reversed().last {
|
59 |
| - if case .newlines(_) = firstPiece { |
60 |
| - return false |
61 |
| - } |
| 40 | + if case .newlines(_) = firstPiece { return false } |
62 | 41 | }
|
63 | 42 | for piece in trivia {
|
64 |
| - if case .lineComment(_) = piece { |
65 |
| - return true |
66 |
| - } |
| 43 | + if case .lineComment(_) = piece { return true } |
67 | 44 | }
|
68 | 45 | return false
|
69 | 46 | }
|
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 |
| - } |
106 | 47 | }
|
107 | 48 |
|
108 | 49 | extension Diagnostic.Message {
|
| 50 | + |
109 | 51 | static func addSpacesBeforeLineComment(count: Int) -> Diagnostic.Message {
|
110 | 52 | let ending = count == 1 ? "" : "s"
|
111 | 53 | return Diagnostic.Message(.warning, "add \(count) space\(ending) before the //")
|
112 | 54 | }
|
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 `//`") |
118 | 55 | }
|
0 commit comments