Skip to content

Commit d46e30f

Browse files
authored
Merge pull request #746 from shawnhyam/handle-block-comment-indentation
Handle indented block comments with ASCII art correctly.
2 parents ee3a4be + eec6403 commit d46e30f

File tree

3 files changed

+105
-70
lines changed

3 files changed

+105
-70
lines changed

Sources/SwiftFormat/Core/DocumentationCommentText.swift

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -67,24 +67,7 @@ public struct DocumentationCommentText {
6767
// comment. We have to copy it into an array since `Trivia` doesn't support bidirectional
6868
// indexing.
6969
let triviaArray = Array(trivia)
70-
let commentStartIndex: Array<TriviaPiece>.Index
71-
if
72-
let lastNonDocCommentIndex = triviaArray.lastIndex(where: {
73-
switch $0 {
74-
case .docBlockComment, .docLineComment,
75-
.newlines(1), .carriageReturns(1), .carriageReturnLineFeeds(1),
76-
.spaces, .tabs:
77-
return false
78-
default:
79-
return true
80-
}
81-
}),
82-
lastNonDocCommentIndex != trivia.endIndex
83-
{
84-
commentStartIndex = triviaArray.index(after: lastNonDocCommentIndex)
85-
} else {
86-
commentStartIndex = triviaArray.startIndex
87-
}
70+
let commentStartIndex = findCommentStartIndex(triviaArray)
8871

8972
// Determine the indentation level of the first line of the comment. This is used to adjust
9073
// block comments, whose text spans multiple lines.
@@ -216,3 +199,37 @@ private func asciiArtLength(of string: Substring, leadingSpaces: Int) -> Int {
216199
}
217200
return 0
218201
}
202+
203+
/// Returns the start index of the earliest comment in the Trivia if we work backwards and
204+
/// skip through comments, newlines, and whitespace. Then we advance a bit forward to be sure
205+
/// the returned index is actually a comment and not whitespace.
206+
private func findCommentStartIndex(_ triviaArray: Array<TriviaPiece>) -> Array<TriviaPiece>.Index {
207+
func firstCommentIndex(_ slice: ArraySlice<TriviaPiece>) -> Array<TriviaPiece>.Index {
208+
return slice.firstIndex(where: {
209+
switch $0 {
210+
case .docLineComment, .docBlockComment:
211+
return true
212+
default:
213+
return false
214+
}
215+
}) ?? slice.endIndex
216+
}
217+
218+
if
219+
let lastNonDocCommentIndex = triviaArray.lastIndex(where: {
220+
switch $0 {
221+
case .docBlockComment, .docLineComment,
222+
.newlines(1), .carriageReturns(1), .carriageReturnLineFeeds(1),
223+
.spaces, .tabs:
224+
return false
225+
default:
226+
return true
227+
}
228+
})
229+
{
230+
let nextIndex = triviaArray.index(after: lastNonDocCommentIndex)
231+
return firstCommentIndex(triviaArray[nextIndex...])
232+
} else {
233+
return firstCommentIndex(triviaArray[...])
234+
}
235+
}

Tests/SwiftFormatTests/Core/DocumentationCommentTextTests.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,25 @@ final class DocumentationCommentTextTests: XCTestCase {
5454
"""
5555
)
5656
}
57-
57+
58+
func testIndentedDocBlockCommentWithASCIIArt() throws {
59+
let decl: DeclSyntax = """
60+
/**
61+
* A simple doc comment.
62+
*/
63+
func f() {}
64+
"""
65+
let commentText = try XCTUnwrap(DocumentationCommentText(extractedFrom: decl.leadingTrivia))
66+
XCTAssertEqual(commentText.introducer, .block)
67+
XCTAssertEqual(
68+
commentText.text,
69+
"""
70+
A simple doc comment.
71+
72+
"""
73+
)
74+
}
75+
5876
func testDocBlockCommentWithoutASCIIArt() throws {
5977
let decl: DeclSyntax = """
6078
/**

Tests/SwiftFormatTests/Rules/BeginDocumentationCommentWithOneLineSummaryTests.swift

Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,33 @@ final class BeginDocumentationCommentWithOneLineSummaryTests: LintOrFormatRuleTe
1414
assertLint(
1515
BeginDocumentationCommentWithOneLineSummary.self,
1616
"""
17-
/// Returns a bottle of Dr Pepper from the vending machine.
18-
public func drPepper(from vendingMachine: VendingMachine) -> Soda {}
17+
/// Returns a bottle of Dr Pepper from the vending machine.
18+
public func drPepper(from vendingMachine: VendingMachine) -> Soda {}
1919
20-
/// Contains a comment as description that needs a sentence
21-
/// of two lines of code.
22-
public var twoLinesForOneSentence = "test"
20+
/// Contains a comment as description that needs a sentence
21+
/// of two lines of code.
22+
public var twoLinesForOneSentence = "test"
2323
24-
/// The background color of the view.
25-
var backgroundColor: UIColor
24+
/// The background color of the view.
25+
var backgroundColor: UIColor
2626
27-
/// Returns the sum of the numbers.
28-
///
29-
/// - Parameter numbers: The numbers to sum.
30-
/// - Returns: The sum of the numbers.
31-
func sum(_ numbers: [Int]) -> Int {
32-
// ...
33-
}
27+
/// Returns the sum of the numbers.
28+
///
29+
/// - Parameter numbers: The numbers to sum.
30+
/// - Returns: The sum of the numbers.
31+
func sum(_ numbers: [Int]) -> Int {
32+
// ...
33+
}
3434
35-
/// This docline should not succeed.
36-
/// There are two sentences without a blank line between them.
37-
1️⃣struct Test {}
35+
/// This docline should not succeed.
36+
/// There are two sentences without a blank line between them.
37+
1️⃣struct Test {}
3838
39-
/// This docline should not succeed. There are two sentences.
40-
2️⃣public enum Token { case comma, semicolon, identifier }
39+
/// This docline should not succeed. There are two sentences.
40+
2️⃣public enum Token { case comma, semicolon, identifier }
4141
42-
/// Should fail because it doesn't have a period
43-
3️⃣public class testNoPeriod {}
42+
/// Should fail because it doesn't have a period
43+
3️⃣public class testNoPeriod {}
4444
""",
4545
findings: [
4646
FindingSpec("1️⃣", message: #"add a blank comment line after this sentence: "This docline should not succeed.""#),
@@ -54,36 +54,36 @@ final class BeginDocumentationCommentWithOneLineSummaryTests: LintOrFormatRuleTe
5454
assertLint(
5555
BeginDocumentationCommentWithOneLineSummary.self,
5656
"""
57-
/**
58-
* Returns the numeric value.
59-
*
60-
* - Parameters:
61-
* - digit: The Unicode scalar whose numeric value should be returned.
62-
* - radix: The radix, between 2 and 36, used to compute the numeric value.
63-
* - Returns: The numeric value of the scalar.*/
64-
func numericValue(of digit: UnicodeScalar, radix: Int = 10) -> Int {}
65-
66-
/**
67-
* This block comment contains a sentence summary
68-
* of two lines of code.
69-
*/
70-
public var twoLinesForOneSentence = "test"
71-
72-
/**
73-
* This block comment should not succeed, struct.
74-
* There are two sentences without a blank line between them.
75-
*/
76-
1️⃣struct TestStruct {}
77-
78-
/**
79-
This block comment should not succeed, class.
80-
Add a blank comment after the first line.
81-
*/
82-
2️⃣public class TestClass {}
83-
/** This block comment should not succeed, enum. There are two sentences. */
84-
3️⃣public enum testEnum {}
85-
/** Should fail because it doesn't have a period */
86-
4️⃣public class testNoPeriod {}
57+
/**
58+
* Returns the numeric value.
59+
*
60+
* - Parameters:
61+
* - digit: The Unicode scalar whose numeric value should be returned.
62+
* - radix: The radix, between 2 and 36, used to compute the numeric value.
63+
* - Returns: The numeric value of the scalar.*/
64+
func numericValue(of digit: UnicodeScalar, radix: Int = 10) -> Int {}
65+
66+
/**
67+
* This block comment contains a sentence summary
68+
* of two lines of code.
69+
*/
70+
public var twoLinesForOneSentence = "test"
71+
72+
/**
73+
* This block comment should not succeed, struct.
74+
* There are two sentences without a blank line between them.
75+
*/
76+
1️⃣struct TestStruct {}
77+
78+
/**
79+
This block comment should not succeed, class.
80+
Add a blank comment after the first line.
81+
*/
82+
2️⃣public class TestClass {}
83+
/** This block comment should not succeed, enum. There are two sentences. */
84+
3️⃣public enum testEnum {}
85+
/** Should fail because it doesn't have a period */
86+
4️⃣public class testNoPeriod {}
8787
""",
8888
findings: [
8989
FindingSpec("1️⃣", message: #"add a blank comment line after this sentence: "This block comment should not succeed, struct.""#),

0 commit comments

Comments
 (0)