Skip to content

Commit 136c8d4

Browse files
authored
Merge pull request #3301 from bitjammer/cascading-documentation-comments
Cascade doc comments from protocol requirements to extensions
2 parents 7be7cc5 + d3cc09f commit 136c8d4

File tree

2 files changed

+116
-2
lines changed

2 files changed

+116
-2
lines changed

lib/AST/DocComment.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,47 @@ getAnyBaseClassDocComment(swift::markup::MarkupContext &MC,
392392
return None;
393393
}
394394

395+
static Optional<DocComment *>
396+
getProtocolRequirementDocComment(swift::markup::MarkupContext &MC,
397+
const ProtocolDecl *ProtoExt,
398+
const Decl *D) {
399+
400+
auto getSingleRequirementWithNonemptyDoc = [](const ProtocolDecl *P,
401+
const ValueDecl *VD)
402+
-> const ValueDecl * {
403+
SmallVector<ValueDecl *, 2> Members;
404+
P->lookupQualified(P->getType(), VD->getFullName(),
405+
NLOptions::NL_ProtocolMembers,
406+
/*resolver=*/nullptr, Members);
407+
SmallVector<const ValueDecl *, 1> ProtocolRequirements;
408+
for (auto Member : Members)
409+
if (!Member->isDefinition())
410+
ProtocolRequirements.push_back(Member);
411+
412+
if (ProtocolRequirements.size() == 1) {
413+
auto Requirement = ProtocolRequirements.front();
414+
if (!Requirement->getRawComment().isEmpty())
415+
return Requirement;
416+
}
417+
418+
return nullptr;
419+
};
420+
421+
if (const auto *VD = dyn_cast<ValueDecl>(D)) {
422+
SmallVector<const ValueDecl *, 4> RequirementsWithDocs;
423+
if (auto Requirement = getSingleRequirementWithNonemptyDoc(ProtoExt, VD))
424+
RequirementsWithDocs.push_back(Requirement);
425+
426+
for (auto Proto : ProtoExt->getInheritedProtocols(/*resolver=*/nullptr))
427+
if (auto Requirement = getSingleRequirementWithNonemptyDoc(Proto, VD))
428+
RequirementsWithDocs.push_back(Requirement);
429+
430+
if (RequirementsWithDocs.size() == 1)
431+
return getSingleDocComment(MC, RequirementsWithDocs.front());
432+
}
433+
return None;
434+
}
435+
395436
Optional<DocComment *>
396437
swift::getCascadingDocComment(swift::markup::MarkupContext &MC, const Decl *D) {
397438
auto Doc = getSingleDocComment(MC, D);
@@ -404,8 +445,9 @@ swift::getCascadingDocComment(swift::markup::MarkupContext &MC, const Decl *D) {
404445
if (auto BaseClassDoc = getAnyBaseClassDocComment(MC, CD, D))
405446
return BaseClassDoc;
406447

407-
// FIXME: Look at protocol requirement declarations if a protocol
408-
// extension implementation doesn't have a doc comment.
448+
if (const auto *PE = D->getDeclContext()->getAsProtocolExtensionContext())
449+
if (auto ReqDoc = getProtocolRequirementDocComment(MC, PE, D))
450+
return ReqDoc;
409451

410452
return None;
411453
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// RUN: %target-swift-ide-test -print-comments -source-filename %s | FileCheck %s
2+
3+
protocol ParentProtocol1 {
4+
/// ParentProtocol1.onlyParent1()
5+
func onlyParent1()
6+
// CHECK: Func/ParentProtocol1.onlyParent1 {{.*}} DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>onlyParent1()</Name><USR>s:FP14swift_ide_test15ParentProtocol111onlyParent1FT_T_</USR><Declaration>func onlyParent1()</Declaration><Abstract><Para>ParentProtocol1.onlyParent1()</Para></Abstract></Function>]
7+
8+
/// ParentProtocol1.commonParentRequirement()
9+
func commonParentRequirement()
10+
// CHECKL: Func/ParentProtocol1.commonParentRequirement {{.*}} DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>commonParentRequirement()</Name><USR>s:FP14swift_ide_test15ParentProtocol123commonParentRequirementFT_T_</USR><Declaration>func commonParentRequirement()</Declaration><Abstract><Para>ParentProtocol1.commonParentRequirement()</Para></Abstract></Function>]
11+
12+
/// ParentProtocol1.commonRequirementWithDocComment()
13+
func commonRequirementWithDocComment()
14+
// CHECK: Func/ParentProtocol1.commonRequirementWithDocComment {{.*}} DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>commonRequirementWithDocComment()</Name><USR>s:FP14swift_ide_test15ParentProtocol131commonRequirementWithDocCommentFT_T_</USR><Declaration>func commonRequirementWithDocComment()</Declaration><Abstract><Para>ParentProtocol1.commonRequirementWithDocComment()</Para></Abstract></Function>]
15+
16+
/// ParentProtocol1.commonRequirementWithoutDocComment()
17+
func commonRequirementWithoutDocComment()
18+
// CHECK: Func/ParentProtocol1.commonRequirementWithoutDocComment {{.*}} DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>commonRequirementWithoutDocComment()</Name><USR>s:FP14swift_ide_test15ParentProtocol134commonRequirementWithoutDocCommentFT_T_</USR><Declaration>func commonRequirementWithoutDocComment()</Declaration><Abstract><Para>ParentProtocol1.commonRequirementWithoutDocComment()</Para></Abstract></Function>]
19+
}
20+
21+
protocol ParentProtocol2 {
22+
/// ParentProtocol2.onlyParent2()
23+
func onlyParent2()
24+
// CHECK: Func/ParentProtocol2.onlyParent2 {{.*}} DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>onlyParent2()</Name><USR>s:FP14swift_ide_test15ParentProtocol211onlyParent2FT_T_</USR><Declaration>func onlyParent2()</Declaration><Abstract><Para>ParentProtocol2.onlyParent2()</Para></Abstract></Function>]
25+
26+
/// ParentProtocol2.commonParentRequirement()
27+
func commonParentRequirement()
28+
// CHECK: Func/ParentProtocol2.commonParentRequirement {{.*}} DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>commonParentRequirement()</Name><USR>s:FP14swift_ide_test15ParentProtocol223commonParentRequirementFT_T_</USR><Declaration>func commonParentRequirement()</Declaration><Abstract><Para>ParentProtocol2.commonParentRequirement()</Para></Abstract></Function>]
29+
30+
/// ParentProtocol2.commonRequirementWithDocComment()
31+
func commonRequirementWithDocComment()
32+
// CHECK: Func/ParentProtocol2.commonRequirementWithDocComment {{.*}} DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>commonRequirementWithDocComment()</Name><USR>s:FP14swift_ide_test15ParentProtocol231commonRequirementWithDocCommentFT_T_</USR><Declaration>func commonRequirementWithDocComment()</Declaration><Abstract><Para>ParentProtocol2.commonRequirementWithDocComment()</Para></Abstract></Function>]
33+
34+
/// ParentProtocol2.commonRequirementWithoutDocComment()
35+
func commonRequirementWithoutDocComment()
36+
// CHECK: Func/ParentProtocol2.commonRequirementWithoutDocComment {{.*}} DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>commonRequirementWithoutDocComment()</Name><USR>s:FP14swift_ide_test15ParentProtocol234commonRequirementWithoutDocCommentFT_T_</USR><Declaration>func commonRequirementWithoutDocComment()</Declaration><Abstract><Para>ParentProtocol2.commonRequirementWithoutDocComment()</Para></Abstract></Function>]
37+
}
38+
39+
protocol ChildProtocol : ParentProtocol1, ParentProtocol2 {
40+
/// ChildProtocol.commonRequirementWithDocComment()
41+
func commonRequirementWithDocComment()
42+
// CHECK: Func/ChildProtocol.commonRequirementWithDocComment {{.*}} DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>commonRequirementWithDocComment()</Name><USR>s:FP14swift_ide_test13ChildProtocol31commonRequirementWithDocCommentFT_T_</USR><Declaration>func commonRequirementWithDocComment()</Declaration><Abstract><Para>ChildProtocol.commonRequirementWithDocComment()</Para></Abstract></Function>]
43+
44+
// This should show nothing because there are two inherited requirements.
45+
func commonRequirementWithoutDocComment()
46+
// CHECK: Func/ChildProtocol.commonRequirementWithoutDocComment {{.*}} DocCommentAsXML=none
47+
}
48+
49+
// Test that ChildProtocol's default implementation for requirements
50+
// come from the right place.
51+
extension ChildProtocol {
52+
// Should come from ParentProtocol1.
53+
func onlyParent1() {}
54+
// CHECK: Func/onlyParent1 {{.*}} DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>onlyParent1()</Name><USR>s:FP14swift_ide_test15ParentProtocol111onlyParent1FT_T_</USR><Declaration>func onlyParent1()</Declaration><Abstract><Para>ParentProtocol1.onlyParent1()</Para></Abstract></Function>]
55+
56+
// Should come from ParentProtocol2.
57+
func onlyParent2() {}
58+
// CHECK: Func/onlyParent2 {{.*}} DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>onlyParent2()</Name><USR>s:FP14swift_ide_test15ParentProtocol211onlyParent2FT_T_</USR><Declaration>func onlyParent2()</Declaration><Abstract><Para>ParentProtocol2.onlyParent2()</Para></Abstract></Function>]
59+
60+
// Should show nothing because the requirement is in both parents.
61+
func commonParentRequirement() {}
62+
// CHECK: Func/commonParentRequirement {{.*}} DocCommentAsXML=none
63+
64+
// Should show nothing because the requirement is in both parents.
65+
func commonRequirementWithDocComment() {}
66+
// CHECK: Func/commonRequirementWithDocComment {{.*}} DocCommentAsXML=none
67+
68+
// Should show nothing because there are multiple requirements.
69+
func commonRequirementWithoutDocComment() {}
70+
// CHECK: Func/commonRequirementWithoutDocComment {{.*}} DocCommentAsXML=none
71+
}
72+

0 commit comments

Comments
 (0)