Skip to content

Commit c20f3db

Browse files
committed
Nesting parameter/returns/throws doc comments for closure parameters
Under parameter doc comment list items, allow function doc comment syntax to nest so you can document the meaning of closure parameters' signatures. rdar://problem/24794725
1 parent a9297ee commit c20f3db

File tree

7 files changed

+171
-63
lines changed

7 files changed

+171
-63
lines changed

bindings/xml/comment-xml-schema.rng

+22-3
Original file line numberDiff line numberDiff line change
@@ -650,9 +650,28 @@
650650
<!-- In general, template parameters with whitespace discussion
651651
should not be emitted, unless direction is explicitly specified.
652652
Schema might be more strict here. -->
653-
<element name="Discussion">
654-
<ref name="BlockContent" />
655-
</element>
653+
<choice>
654+
<element name="ClosureParameter">
655+
<optional>
656+
<ref name="Abstract" />
657+
</optional>
658+
<optional>
659+
<ref name="Parameters" />
660+
</optional>
661+
<optional>
662+
<ref name="ResultDiscussion" />
663+
</optional>
664+
<optional>
665+
<ref name="ThrowsDiscussion" />
666+
</optional>
667+
<optional>
668+
<ref name="Discussion" />
669+
</optional>
670+
</element>
671+
<element name="Discussion">
672+
<ref name="BlockContent" />
673+
</element>
674+
</choice>
656675
</element>
657676
</oneOrMore>
658677
</element>

include/swift/AST/Comment.h

+3-17
Original file line numberDiff line numberDiff line change
@@ -22,34 +22,20 @@ class DocComment;
2222
struct RawComment;
2323

2424
class DocComment {
25-
public:
26-
struct CommentParts {
27-
Optional<const swift::markup::Paragraph *>Brief;
28-
ArrayRef<const swift::markup::MarkupASTNode *> BodyNodes;
29-
ArrayRef<const swift::markup::ParamField *> ParamFields;
30-
Optional<const swift::markup::ReturnsField *> ReturnsField;
31-
Optional<const swift::markup::ThrowsField *> ThrowsField;
32-
33-
bool isEmpty() const {
34-
return !Brief.hasValue() && !ReturnsField.hasValue() && !ThrowsField.hasValue() && BodyNodes.empty() && ParamFields.empty();
35-
}
36-
};
37-
38-
private:
3925
const Decl *D;
4026
const swift::markup::Document *Doc = nullptr;
41-
const CommentParts Parts;
27+
const swift::markup::CommentParts Parts;
4228

4329
public:
4430
DocComment(const Decl *D, swift::markup::Document *Doc,
45-
CommentParts Parts)
31+
swift::markup::CommentParts Parts)
4632
: D(D), Doc(Doc), Parts(Parts) {}
4733

4834
const Decl *getDecl() const { return D; }
4935

5036
const swift::markup::Document *getDocument() const { return Doc; }
5137

52-
CommentParts getParts() const {
38+
swift::markup::CommentParts getParts() const {
5339
return Parts;
5440
}
5541

include/swift/Markup/AST.h

+48
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,35 @@ namespace swift {
2222
namespace markup {
2323

2424
class MarkupContext;
25+
class MarkupASTNode;
26+
class Paragraph;
27+
class ParamField;
28+
class ReturnsField;
29+
class ThrowsField;
30+
31+
/// The basic structure of a doc comment attached to a Swift
32+
/// declaration.
33+
struct CommentParts {
34+
Optional<const Paragraph *> Brief;
35+
ArrayRef<const MarkupASTNode *> BodyNodes;
36+
ArrayRef<ParamField *> ParamFields;
37+
Optional<const ReturnsField *> ReturnsField;
38+
Optional<const ThrowsField *> ThrowsField;
39+
40+
bool isEmpty() const {
41+
return !Brief.hasValue() &&
42+
!ReturnsField.hasValue() &&
43+
!ThrowsField.hasValue() &&
44+
BodyNodes.empty() &&
45+
ParamFields.empty();
46+
}
47+
48+
bool hasFunctionDocumentation() const {
49+
return !ParamFields.empty() ||
50+
ReturnsField.hasValue() ||
51+
ThrowsField.hasValue();
52+
}
53+
};
2554

2655
#define MARKUP_AST_NODE(Id, Parent) class Id;
2756
#define ABSTRACT_MARKUP_AST_NODE(Id, Parent) class Id;
@@ -585,6 +614,10 @@ class ParamField final : public PrivateExtension,
585614

586615
StringRef Name;
587616

617+
// Parameter fields can contain a substructure describing a
618+
// function or closure parameter.
619+
llvm::Optional<CommentParts> Parts;
620+
588621
ParamField(StringRef Name, ArrayRef<MarkupASTNode *> Children);
589622

590623
public:
@@ -596,6 +629,21 @@ class ParamField final : public PrivateExtension,
596629
return Name;
597630
}
598631

632+
llvm::Optional<CommentParts> getParts() const {
633+
return Parts;
634+
}
635+
636+
void setParts(CommentParts P) {
637+
Parts = P;
638+
}
639+
640+
bool isClosureParameter() const {
641+
if (!Parts.hasValue())
642+
return false;
643+
644+
return Parts.getValue().hasFunctionDocumentation();
645+
}
646+
599647
ArrayRef<MarkupASTNode *> getChildren() {
600648
return {getTrailingObjects<MarkupASTNode *>(), NumChildren};
601649
}

lib/AST/DocComment.cpp

+11-6
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ Optional<swift::markup::ParamField *> extractParamOutlineItem(
7070

7171
bool extractParameterOutline(
7272
swift::markup::MarkupContext &MC, swift::markup::List *L,
73-
SmallVectorImpl<const swift::markup::ParamField *> &ParamFields) {
73+
SmallVectorImpl<swift::markup::ParamField *> &ParamFields) {
7474
SmallVector<swift::markup::MarkupASTNode *, 8> NormalItems;
7575
auto Children = L->getChildren();
7676
if (Children.empty())
@@ -145,7 +145,7 @@ bool extractParameterOutline(
145145

146146
bool extractSeparatedParams(
147147
swift::markup::MarkupContext &MC, swift::markup::List *L,
148-
SmallVectorImpl<const swift::markup::ParamField *> &ParamFields) {
148+
SmallVectorImpl<swift::markup::ParamField *> &ParamFields) {
149149
SmallVector<swift::markup::MarkupASTNode *, 8> NormalItems;
150150
auto Children = L->getChildren();
151151

@@ -209,7 +209,7 @@ bool extractSeparatedParams(
209209

210210
bool extractSimpleField(
211211
swift::markup::MarkupContext &MC, swift::markup::List *L,
212-
DocComment::CommentParts &Parts,
212+
swift::markup::CommentParts &Parts,
213213
SmallVectorImpl<const swift::markup::MarkupASTNode *> &BodyNodes) {
214214
auto Children = L->getChildren();
215215
SmallVector<swift::markup::MarkupASTNode *, 8> NormalItems;
@@ -274,11 +274,11 @@ bool extractSimpleField(
274274
return NormalItems.size() == 0;
275275
}
276276

277-
static DocComment::CommentParts
277+
static swift::markup::CommentParts
278278
extractCommentParts(swift::markup::MarkupContext &MC,
279279
swift::markup::MarkupASTNode *Node) {
280280

281-
DocComment::CommentParts Parts;
281+
swift::markup::CommentParts Parts;
282282
auto Children = Node->getChildren();
283283
if (Children.empty())
284284
return Parts;
@@ -289,7 +289,7 @@ extractCommentParts(swift::markup::MarkupContext &MC,
289289
Parts.Brief = FirstParagraph;
290290

291291
SmallVector<const swift::markup::MarkupASTNode *, 4> BodyNodes;
292-
SmallVector<const swift::markup::ParamField *, 8> ParamFields;
292+
SmallVector<swift::markup::ParamField *, 8> ParamFields;
293293

294294
// Look for special top-level lists
295295
size_t StartOffset = FirstParagraph == nullptr ? 0 : 1;
@@ -317,6 +317,11 @@ extractCommentParts(swift::markup::MarkupContext &MC,
317317
Parts.BodyNodes = MC.allocateCopy(llvm::makeArrayRef(BodyNodes));
318318
Parts.ParamFields = MC.allocateCopy(llvm::makeArrayRef(ParamFields));
319319

320+
for (auto Param : Parts.ParamFields) {
321+
auto ParamParts = extractCommentParts(MC, Param);
322+
Param->setParts(ParamParts);
323+
}
324+
320325
return Parts;
321326
}
322327

lib/IDE/CommentConversion.cpp

+49-36
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,24 @@ struct CommentToXMLConverter {
211211
}
212212

213213
void printParamField(const ParamField *PF) {
214-
OS << "<Parameter><Name>";
214+
OS << "<Parameter>";
215+
OS << "<Name>";
215216
OS << PF->getName();
216-
OS << "</Name><Direction isExplicit=\"0\">in</Direction><Discussion>";
217-
for (auto Child : PF->getChildren())
218-
printASTNode(Child);
219-
220-
OS << "</Discussion></Parameter>";
217+
OS << "</Name>";
218+
OS << "<Direction isExplicit=\"0\">in</Direction>";
219+
220+
if (PF->isClosureParameter()) {
221+
OS << "<ClosureParameter>";
222+
visitCommentParts(PF->getParts().getValue());
223+
OS << "</ClosureParameter>";
224+
} else {
225+
OS << "<Discussion>";
226+
for (auto Child : PF->getChildren()) {
227+
printASTNode(Child);
228+
}
229+
OS << "</Discussion>";
230+
}
231+
OS << "</Parameter>";
221232
}
222233

223234
void printResultDiscussion(const ReturnsField *RF) {
@@ -235,9 +246,40 @@ struct CommentToXMLConverter {
235246
}
236247

237248
void visitDocComment(const DocComment *DC);
249+
void visitCommentParts(const swift::markup::CommentParts &Parts);
238250
};
239251
} // unnamed namespace
240252

253+
void CommentToXMLConverter::visitCommentParts(const swift::markup::CommentParts &Parts) {
254+
if (Parts.Brief.hasValue()) {
255+
OS << "<Abstract>";
256+
printASTNode(Parts.Brief.getValue());
257+
OS << "</Abstract>";
258+
}
259+
260+
if (!Parts.ParamFields.empty()) {
261+
OS << "<Parameters>";
262+
for (const auto *PF : Parts.ParamFields)
263+
printParamField(PF);
264+
265+
OS << "</Parameters>";
266+
}
267+
268+
if (Parts.ReturnsField.hasValue())
269+
printResultDiscussion(Parts.ReturnsField.getValue());
270+
271+
if (Parts.ThrowsField.hasValue())
272+
printThrowsDiscussion(Parts.ThrowsField.getValue());
273+
274+
if (!Parts.BodyNodes.empty()) {
275+
OS << "<Discussion>";
276+
for (const auto *N : Parts.BodyNodes)
277+
printASTNode(N);
278+
279+
OS << "</Discussion>";
280+
}
281+
}
282+
241283
void CommentToXMLConverter::visitDocComment(const DocComment *DC) {
242284
const Decl *D = DC->getDecl();
243285

@@ -313,36 +355,7 @@ void CommentToXMLConverter::visitDocComment(const DocComment *DC) {
313355
OS << "</Declaration>";
314356
}
315357

316-
auto Brief = DC->getBrief();
317-
if (Brief.hasValue()) {
318-
OS << "<Abstract>";
319-
printASTNode(Brief.getValue());
320-
OS << "</Abstract>";
321-
}
322-
323-
if (!DC->getParamFields().empty()) {
324-
OS << "<Parameters>";
325-
for (const auto *PF : DC->getParamFields())
326-
printParamField(PF);
327-
328-
OS << "</Parameters>";
329-
}
330-
331-
auto RF = DC->getReturnsField();
332-
if (RF.hasValue())
333-
printResultDiscussion(RF.getValue());
334-
335-
auto TF = DC->getThrowsField();
336-
if (TF.hasValue())
337-
printThrowsDiscussion(TF.getValue());
338-
339-
if (!DC->getBodyNodes().empty()) {
340-
OS << "<Discussion>";
341-
for (const auto *N : DC->getBodyNodes())
342-
printASTNode(N);
343-
344-
OS << "</Discussion>";
345-
}
358+
visitCommentParts(DC->getParts());
346359

347360
OS << RootEndTag;
348361
}

lib/Markup/AST.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ Strong *Strong::create(MarkupContext &MC,
205205

206206
ParamField::ParamField(StringRef Name, ArrayRef<MarkupASTNode *> Children)
207207
: PrivateExtension(ASTNodeKind::ParamField), NumChildren(Children.size()),
208-
Name(Name) {
208+
Name(Name),
209+
Parts(None) {
209210
std::uninitialized_copy(Children.begin(), Children.end(),
210211
getTrailingObjects<MarkupASTNode *>());
211212
}

test/Inputs/comment_to_something_conversion.swift

+36
Original file line numberDiff line numberDiff line change
@@ -422,3 +422,39 @@ public func codeListingWithDefaultLanguage() {}
422422
/// ```
423423
public func codeListingWithOtherLanguage() {}
424424
// CHECK: DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>codeListingWithOtherLanguage()</Name><USR>s:F14swift_ide_test28codeListingWithOtherLanguageFT_T_</USR><Declaration>public func codeListingWithOtherLanguage()</Declaration><Abstract><Para>Brief.</Para></Abstract><Discussion><CodeListing language="c++"><zCodeLineNumbered><![CDATA[Something::Something::create();]]></zCodeLineNumbered><zCodeLineNumbered></zCodeLineNumbered></CodeListing></Discussion></Function>]
425+
426+
/// Partially applies a binary operator.
427+
///
428+
/// - Parameter a: The left-hand side to partially apply.
429+
/// - Parameter combine: A binary operator.
430+
/// - Parameter lhs: The left-hand side of the operator
431+
/// - Parameter rhs: The right-hand side of the operator
432+
/// - Returns: A result.
433+
/// - Throws: Nothing.
434+
public func closureParameterExplodedExploded<T>(a: T, combine: (lhs: T, rhs: T) -> T) {}
435+
// CHECK: DocCommentAsXML=[<Function file="{{.*}} line="{{.*}}" column="{{.*}}"><Name>closureParameterExplodedExploded(a:combine:)</Name><USR>s:F14swift_ide_test32closureParameterExplodedExplodedurFT1ax7combineFT3lhsx3rhsx_x_T_</USR><Declaration>public func closureParameterExplodedExploded&lt;T&gt;(a: T, combine: (lhs: T, rhs: T) -&gt; T)</Declaration><Abstract><Para>Partially applies a binary operator.</Para></Abstract><Parameters><Parameter><Name>a</Name><Direction isExplicit="0">in</Direction><Discussion><Para>The left-hand side to partially apply.</Para></Discussion></Parameter><Parameter><Name>combine</Name><Direction isExplicit="0">in</Direction><ClosureParameter><Abstract><Para>A binary operator.</Para></Abstract><Parameters><Parameter><Name>lhs</Name><Direction isExplicit="0">in</Direction><Discussion><Para>The left-hand side of the operator</Para></Discussion></Parameter><Parameter><Name>rhs</Name><Direction isExplicit="0">in</Direction><Discussion><Para>The right-hand side of the operator</Para></Discussion></Parameter></Parameters><ResultDiscussion><Para>A result.</Para></ResultDiscussion><ThrowsDiscussion><Para>Nothing.</Para></ThrowsDiscussion></ClosureParameter></Parameter></Parameters></Function>] CommentXMLValid
436+
437+
/// Partially applies a binary operator.
438+
///
439+
/// - Parameters:
440+
/// - a: The left-hand side to partially apply.
441+
/// - combine: A binary operator.
442+
/// - Parameter lhs: The left-hand side of the operator
443+
/// - Parameter rhs: The right-hand side of the operator
444+
/// - Returns: A result.
445+
/// - Throws: Nothing.
446+
public func closureParameterOutlineExploded<T>(a: T, combine: (lhs: T, rhs: T) -> T) {}
447+
// CHECK: DocCommentAsXML=[<Function file="{{.*}} line="{{.*}}" column="{{.*}}"><Name>closureParameterOutlineExploded(a:combine:)</Name><USR>s:F14swift_ide_test31closureParameterOutlineExplodedurFT1ax7combineFT3lhsx3rhsx_x_T_</USR><Declaration>public func closureParameterOutlineExploded&lt;T&gt;(a: T, combine: (lhs: T, rhs: T) -&gt; T)</Declaration><Abstract><Para>Partially applies a binary operator.</Para></Abstract><Parameters><Parameter><Name>a</Name><Direction isExplicit="0">in</Direction><Discussion><Para>The left-hand side to partially apply.</Para></Discussion></Parameter><Parameter><Name>combine</Name><Direction isExplicit="0">in</Direction><ClosureParameter><Abstract><Para>A binary operator.</Para></Abstract><Parameters><Parameter><Name>lhs</Name><Direction isExplicit="0">in</Direction><Discussion><Para>The left-hand side of the operator</Para></Discussion></Parameter><Parameter><Name>rhs</Name><Direction isExplicit="0">in</Direction><Discussion><Para>The right-hand side of the operator</Para></Discussion></Parameter></Parameters><ResultDiscussion><Para>A result.</Para></ResultDiscussion><ThrowsDiscussion><Para>Nothing.</Para></ThrowsDiscussion></ClosureParameter></Parameter></Parameters></Function>] CommentXMLValid
448+
449+
/// Partially applies a binary operator.
450+
///
451+
/// - Parameters:
452+
/// - a: The left-hand side to partially apply.
453+
/// - combine: A binary operator.
454+
/// - Parameters:
455+
/// - lhs: The left-hand side of the operator
456+
/// - rhs: The right-hand side of the operator
457+
/// - Returns: A result.
458+
/// - Throws: Nothing.
459+
public func closureParameterOutlineOutline<T>(a: T, combine: (lhs: T, rhs: T) -> T) {}
460+
// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>closureParameterOutlineOutline(a:combine:)</Name><USR>s:F14swift_ide_test30closureParameterOutlineOutlineurFT1ax7combineFT3lhsx3rhsx_x_T_</USR><Declaration>public func closureParameterOutlineOutline&lt;T&gt;(a: T, combine: (lhs: T, rhs: T) -&gt; T)</Declaration><Abstract><Para>Partially applies a binary operator.</Para></Abstract><Parameters><Parameter><Name>a</Name><Direction isExplicit="0">in</Direction><Discussion><Para>The left-hand side to partially apply.</Para></Discussion></Parameter><Parameter><Name>combine</Name><Direction isExplicit="0">in</Direction><ClosureParameter><Abstract><Para>A binary operator.</Para></Abstract><Parameters><Parameter><Name>lhs</Name><Direction isExplicit="0">in</Direction><Discussion><Para>The left-hand side of the operator</Para></Discussion></Parameter><Parameter><Name>rhs</Name><Direction isExplicit="0">in</Direction><Discussion><Para>The right-hand side of the operator</Para></Discussion></Parameter></Parameters><ResultDiscussion><Para>A result.</Para></ResultDiscussion><ThrowsDiscussion><Para>Nothing.</Para></ThrowsDiscussion></ClosureParameter></Parameter></Parameters></Function>]

0 commit comments

Comments
 (0)