Skip to content

Commit 58ccbf3

Browse files
dylansturgallevato
authored andcommitted
Restrict doc-block to doc-line transform to first doc comment.
The transform is intentionally meant to only apply to comments that are documenting a declaration. The distinction is made by finding the comment "closest" to the decl, searching through the trivia backwards. Unfortunately, the search didn't handle the fact that there could be multiple doc comments in the leading trivia of a decl. Multiple comments usually occur at the beginning of the file, when there's a file level comment (either doc block or doc line), followed by decl documentation, then the first decl. It might make sense to convert doc-block comments in the file preamble to doc-line, but we've previously had issues converting general purpose block comments. This approach is safer because only comments that are documenting a decl (defined as closest to the decl) are converted.
1 parent fa522d0 commit 58ccbf3

File tree

3 files changed

+102
-2
lines changed

3 files changed

+102
-2
lines changed

Sources/SwiftFormatRules/UseTripleSlashForDocumentationComments.swift

+8-2
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,23 @@ public final class UseTripleSlashForDocumentationComments: SyntaxFormatRule {
7373
/// a docLineComment.
7474
private func convertDocBlockCommentToDocLineComment(_ decl: DeclSyntax) -> DeclSyntax {
7575
guard let commentText = decl.docComment else { return decl }
76-
guard let declLeadinTrivia = decl.leadingTrivia else { return decl }
76+
guard let declLeadingTrivia = decl.leadingTrivia else { return decl }
7777
let docComments = commentText.components(separatedBy: "\n")
7878
var pieces = [TriviaPiece]()
7979

8080
// Ensures the documentation comment is a docLineComment.
8181
var hasFoundDocComment = false
82-
for piece in declLeadinTrivia.reversed() {
82+
for piece in declLeadingTrivia.reversed() {
8383
if case .docBlockComment(_) = piece, !hasFoundDocComment {
8484
hasFoundDocComment = true
8585
diagnose(.avoidDocBlockComment, on: decl)
8686
pieces.append(contentsOf: separateDocBlockIntoPieces(docComments).reversed())
87+
} else if case .docLineComment(_) = piece, !hasFoundDocComment {
88+
// The comment was a doc-line comment all along. Leave it alone.
89+
// This intentionally only considers the comment closest to the decl. There may be other
90+
// comments, including block or doc-block comments, which are left as-is because they aren't
91+
// necessarily related to the decl and are unlikely part of the decl's documentation.
92+
return decl
8793
} else {
8894
pieces.append(piece)
8995
}

Tests/SwiftFormatRulesTests/UseTripleSlashForDocumentationCommentsTests.swift

+91
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,95 @@ final class UseTripleSlashForDocumentationCommentsTests: LintOrFormatRuleTestCas
5454
public var test = 1
5555
""")
5656
}
57+
58+
func testMultipleTypesOfDocComments() {
59+
XCTAssertFormatting(
60+
UseTripleSlashForDocumentationComments.self,
61+
input: """
62+
/**
63+
* This is my preamble. It could be important.
64+
* This comment stays as-is.
65+
*/
66+
67+
/// This decl has a comment.
68+
/// The comment is multiple lines long.
69+
public class AClazz {
70+
}
71+
""",
72+
expected: """
73+
/**
74+
* This is my preamble. It could be important.
75+
* This comment stays as-is.
76+
*/
77+
78+
/// This decl has a comment.
79+
/// The comment is multiple lines long.
80+
public class AClazz {
81+
}
82+
""")
83+
}
84+
85+
func testMultipleDocLineComments() {
86+
XCTAssertFormatting(
87+
UseTripleSlashForDocumentationComments.self,
88+
input: """
89+
/// This is my preamble. It could be important.
90+
/// This comment stays as-is.
91+
///
92+
93+
/// This decl has a comment.
94+
/// The comment is multiple lines long.
95+
public class AClazz {
96+
}
97+
""",
98+
expected: """
99+
/// This is my preamble. It could be important.
100+
/// This comment stays as-is.
101+
///
102+
103+
/// This decl has a comment.
104+
/// The comment is multiple lines long.
105+
public class AClazz {
106+
}
107+
""")
108+
}
109+
110+
func testManyDocComments() {
111+
XCTAssertFormatting(
112+
UseTripleSlashForDocumentationComments.self,
113+
input: """
114+
/**
115+
* This is my preamble. It could be important.
116+
* This comment stays as-is.
117+
*/
118+
119+
/// This is a doc-line comment!
120+
121+
/** This is a fairly short doc-block comment. */
122+
123+
/// Why are there so many comments?
124+
/// Who knows! But there are loads.
125+
126+
/** AClazz is a class with good name. */
127+
public class AClazz {
128+
}
129+
""",
130+
expected: """
131+
/**
132+
* This is my preamble. It could be important.
133+
* This comment stays as-is.
134+
*/
135+
136+
/// This is a doc-line comment!
137+
138+
/** This is a fairly short doc-block comment. */
139+
140+
/// Why are there so many comments?
141+
/// Who knows! But there are loads.
142+
143+
/// AClazz is a class with good name.
144+
public class AClazz {
145+
}
146+
""")
147+
}
57148
}

Tests/SwiftFormatRulesTests/XCTestManifests.swift

+3
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,9 @@ extension UseTripleSlashForDocumentationCommentsTests {
369369
// `swift test --generate-linuxmain`
370370
// to regenerate.
371371
static let __allTests__UseTripleSlashForDocumentationCommentsTests = [
372+
("testManyDocComments", testManyDocComments),
373+
("testMultipleDocLineComments", testMultipleDocLineComments),
374+
("testMultipleTypesOfDocComments", testMultipleTypesOfDocComments),
372375
("testRemoveDocBlockComments", testRemoveDocBlockComments),
373376
("testRemoveDocBlockCommentsWithoutStars", testRemoveDocBlockCommentsWithoutStars),
374377
]

0 commit comments

Comments
 (0)