Skip to content

Commit 255db37

Browse files
[clangd] Retrieve documentation for class member instance from index (#153337)
Fixes clangd/clangd#2290
1 parent 95e0ae9 commit 255db37

File tree

5 files changed

+106
-73
lines changed

5 files changed

+106
-73
lines changed

clang-tools-extra/clangd/CodeComplete.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "support/Trace.h"
4444
#include "clang/AST/Decl.h"
4545
#include "clang/AST/DeclBase.h"
46+
#include "clang/AST/DeclTemplate.h"
4647
#include "clang/Basic/CharInfo.h"
4748
#include "clang/Basic/LangOptions.h"
4849
#include "clang/Basic/SourceLocation.h"
@@ -1886,7 +1887,15 @@ class CodeCompleteFlow {
18861887
for (auto &Cand : C.first) {
18871888
if (Cand.SemaResult &&
18881889
Cand.SemaResult->Kind == CodeCompletionResult::RK_Declaration) {
1889-
auto ID = clangd::getSymbolID(Cand.SemaResult->getDeclaration());
1890+
const NamedDecl *DeclToLookup = Cand.SemaResult->getDeclaration();
1891+
// For instantiations of members of class templates, the
1892+
// documentation will be stored at the member's original
1893+
// declaration.
1894+
if (const NamedDecl *Adjusted =
1895+
dyn_cast<NamedDecl>(&adjustDeclToTemplate(*DeclToLookup))) {
1896+
DeclToLookup = Adjusted;
1897+
}
1898+
auto ID = clangd::getSymbolID(DeclToLookup);
18901899
if (!ID)
18911900
continue;
18921901
Req.IDs.insert(ID);

clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,23 +1154,45 @@ TEST(CompletionTest, CommentsOnMembersFromHeader) {
11541154
/// This is a member function.
11551155
int delta();
11561156
};
1157+
1158+
template <typename T>
1159+
struct beta {
1160+
/// This is a member field inside a template.
1161+
int omega;
1162+
1163+
/// This is a member function inside a template.
1164+
int epsilon();
1165+
};
11571166
)cpp";
11581167

11591168
auto File = testPath("foo.cpp");
11601169
Annotations Test(R"cpp(
11611170
#include "foo.h"
11621171
alpha a;
1163-
int x = a.^
1172+
beta<int> b;
1173+
int x = a.$p1^;
1174+
int y = b.$p2^;
11641175
)cpp");
11651176
runAddDocument(Server, File, Test.code());
11661177
auto CompletionList =
1167-
llvm::cantFail(runCodeComplete(Server, File, Test.point(), {}));
1178+
llvm::cantFail(runCodeComplete(Server, File, Test.point("p1"), {}));
11681179

11691180
EXPECT_THAT(CompletionList.Completions,
11701181
Contains(AllOf(named("gamma"), doc("This is a member field."))));
11711182
EXPECT_THAT(
11721183
CompletionList.Completions,
11731184
Contains(AllOf(named("delta"), doc("This is a member function."))));
1185+
1186+
CompletionList =
1187+
llvm::cantFail(runCodeComplete(Server, File, Test.point("p2"), {}));
1188+
1189+
EXPECT_THAT(CompletionList.Completions,
1190+
Contains(AllOf(named("omega")
1191+
/* FIXME: Doc retrieval does not work yet*/)));
1192+
EXPECT_THAT(
1193+
CompletionList.Completions,
1194+
Contains(AllOf(named("epsilon"),
1195+
doc("This is a member function inside a template."))));
11741196
}
11751197

11761198
TEST(CompletionTest, CommentsOnMembersFromHeaderOverloadBundling) {

clang/include/clang/AST/DeclTemplate.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3399,6 +3399,11 @@ inline UnsignedOrNone getExpandedPackSize(const NamedDecl *Param) {
33993399
/// for their AssociatedDecl.
34003400
TemplateParameterList *getReplacedTemplateParameterList(const Decl *D);
34013401

3402+
/// If we have a 'templated' declaration for a template, adjust 'D' to
3403+
/// refer to the actual template.
3404+
/// If we have an implicit instantiation, adjust 'D' to refer to template.
3405+
const Decl &adjustDeclToTemplate(const Decl &D);
3406+
34023407
} // namespace clang
34033408

34043409
#endif // LLVM_CLANG_AST_DECLTEMPLATE_H

clang/lib/AST/ASTContext.cpp

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -330,76 +330,6 @@ void ASTContext::addComment(const RawComment &RC) {
330330
Comments.addComment(RC, LangOpts.CommentOpts, BumpAlloc);
331331
}
332332

333-
/// If we have a 'templated' declaration for a template, adjust 'D' to
334-
/// refer to the actual template.
335-
/// If we have an implicit instantiation, adjust 'D' to refer to template.
336-
static const Decl &adjustDeclToTemplate(const Decl &D) {
337-
if (const auto *FD = dyn_cast<FunctionDecl>(&D)) {
338-
// Is this function declaration part of a function template?
339-
if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate())
340-
return *FTD;
341-
342-
// Nothing to do if function is not an implicit instantiation.
343-
if (FD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
344-
return D;
345-
346-
// Function is an implicit instantiation of a function template?
347-
if (const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate())
348-
return *FTD;
349-
350-
// Function is instantiated from a member definition of a class template?
351-
if (const FunctionDecl *MemberDecl =
352-
FD->getInstantiatedFromMemberFunction())
353-
return *MemberDecl;
354-
355-
return D;
356-
}
357-
if (const auto *VD = dyn_cast<VarDecl>(&D)) {
358-
// Static data member is instantiated from a member definition of a class
359-
// template?
360-
if (VD->isStaticDataMember())
361-
if (const VarDecl *MemberDecl = VD->getInstantiatedFromStaticDataMember())
362-
return *MemberDecl;
363-
364-
return D;
365-
}
366-
if (const auto *CRD = dyn_cast<CXXRecordDecl>(&D)) {
367-
// Is this class declaration part of a class template?
368-
if (const ClassTemplateDecl *CTD = CRD->getDescribedClassTemplate())
369-
return *CTD;
370-
371-
// Class is an implicit instantiation of a class template or partial
372-
// specialization?
373-
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CRD)) {
374-
if (CTSD->getSpecializationKind() != TSK_ImplicitInstantiation)
375-
return D;
376-
llvm::PointerUnion<ClassTemplateDecl *,
377-
ClassTemplatePartialSpecializationDecl *>
378-
PU = CTSD->getSpecializedTemplateOrPartial();
379-
return isa<ClassTemplateDecl *>(PU)
380-
? *static_cast<const Decl *>(cast<ClassTemplateDecl *>(PU))
381-
: *static_cast<const Decl *>(
382-
cast<ClassTemplatePartialSpecializationDecl *>(PU));
383-
}
384-
385-
// Class is instantiated from a member definition of a class template?
386-
if (const MemberSpecializationInfo *Info =
387-
CRD->getMemberSpecializationInfo())
388-
return *Info->getInstantiatedFrom();
389-
390-
return D;
391-
}
392-
if (const auto *ED = dyn_cast<EnumDecl>(&D)) {
393-
// Enum is instantiated from a member definition of a class template?
394-
if (const EnumDecl *MemberDecl = ED->getInstantiatedFromMemberEnum())
395-
return *MemberDecl;
396-
397-
return D;
398-
}
399-
// FIXME: Adjust alias templates?
400-
return D;
401-
}
402-
403333
const RawComment *ASTContext::getRawCommentForAnyRedecl(
404334
const Decl *D,
405335
const Decl **OriginalDecl) const {

clang/lib/AST/DeclTemplate.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,3 +1708,70 @@ TemplateParameterList *clang::getReplacedTemplateParameterList(const Decl *D) {
17081708
llvm_unreachable("Unhandled templated declaration kind");
17091709
}
17101710
}
1711+
1712+
const Decl &clang::adjustDeclToTemplate(const Decl &D) {
1713+
if (const auto *FD = dyn_cast<FunctionDecl>(&D)) {
1714+
// Is this function declaration part of a function template?
1715+
if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate())
1716+
return *FTD;
1717+
1718+
// Nothing to do if function is not an implicit instantiation.
1719+
if (FD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
1720+
return D;
1721+
1722+
// Function is an implicit instantiation of a function template?
1723+
if (const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate())
1724+
return *FTD;
1725+
1726+
// Function is instantiated from a member definition of a class template?
1727+
if (const FunctionDecl *MemberDecl =
1728+
FD->getInstantiatedFromMemberFunction())
1729+
return *MemberDecl;
1730+
1731+
return D;
1732+
}
1733+
if (const auto *VD = dyn_cast<VarDecl>(&D)) {
1734+
// Static data member is instantiated from a member definition of a class
1735+
// template?
1736+
if (VD->isStaticDataMember())
1737+
if (const VarDecl *MemberDecl = VD->getInstantiatedFromStaticDataMember())
1738+
return *MemberDecl;
1739+
1740+
return D;
1741+
}
1742+
if (const auto *CRD = dyn_cast<CXXRecordDecl>(&D)) {
1743+
// Is this class declaration part of a class template?
1744+
if (const ClassTemplateDecl *CTD = CRD->getDescribedClassTemplate())
1745+
return *CTD;
1746+
1747+
// Class is an implicit instantiation of a class template or partial
1748+
// specialization?
1749+
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CRD)) {
1750+
if (CTSD->getSpecializationKind() != TSK_ImplicitInstantiation)
1751+
return D;
1752+
llvm::PointerUnion<ClassTemplateDecl *,
1753+
ClassTemplatePartialSpecializationDecl *>
1754+
PU = CTSD->getSpecializedTemplateOrPartial();
1755+
return isa<ClassTemplateDecl *>(PU)
1756+
? *static_cast<const Decl *>(cast<ClassTemplateDecl *>(PU))
1757+
: *static_cast<const Decl *>(
1758+
cast<ClassTemplatePartialSpecializationDecl *>(PU));
1759+
}
1760+
1761+
// Class is instantiated from a member definition of a class template?
1762+
if (const MemberSpecializationInfo *Info =
1763+
CRD->getMemberSpecializationInfo())
1764+
return *Info->getInstantiatedFrom();
1765+
1766+
return D;
1767+
}
1768+
if (const auto *ED = dyn_cast<EnumDecl>(&D)) {
1769+
// Enum is instantiated from a member definition of a class template?
1770+
if (const EnumDecl *MemberDecl = ED->getInstantiatedFromMemberEnum())
1771+
return *MemberDecl;
1772+
1773+
return D;
1774+
}
1775+
// FIXME: Adjust alias templates?
1776+
return D;
1777+
}

0 commit comments

Comments
 (0)