Skip to content

Commit fc114ff

Browse files
[clangd] Retrieve documentation for class member instance from index
Fixes clangd/clangd#2290
1 parent 95a4c9c commit fc114ff

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"
@@ -1883,7 +1884,15 @@ class CodeCompleteFlow {
18831884
for (auto &Cand : C.first) {
18841885
if (Cand.SemaResult &&
18851886
Cand.SemaResult->Kind == CodeCompletionResult::RK_Declaration) {
1886-
auto ID = clangd::getSymbolID(Cand.SemaResult->getDeclaration());
1887+
const NamedDecl *DeclToLookup = Cand.SemaResult->getDeclaration();
1888+
// For instantiations of members of class templates, the
1889+
// documentation will be stored at the member's original
1890+
// declaration.
1891+
if (const NamedDecl *Adjusted =
1892+
dyn_cast<NamedDecl>(&adjustDeclToTemplate(*DeclToLookup))) {
1893+
DeclToLookup = Adjusted;
1894+
}
1895+
auto ID = clangd::getSymbolID(DeclToLookup);
18871896
if (!ID)
18881897
continue;
18891898
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
@@ -351,76 +351,6 @@ void ASTContext::addComment(const RawComment &RC) {
351351
Comments.addComment(RC, LangOpts.CommentOpts, BumpAlloc);
352352
}
353353

354-
/// If we have a 'templated' declaration for a template, adjust 'D' to
355-
/// refer to the actual template.
356-
/// If we have an implicit instantiation, adjust 'D' to refer to template.
357-
static const Decl &adjustDeclToTemplate(const Decl &D) {
358-
if (const auto *FD = dyn_cast<FunctionDecl>(&D)) {
359-
// Is this function declaration part of a function template?
360-
if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate())
361-
return *FTD;
362-
363-
// Nothing to do if function is not an implicit instantiation.
364-
if (FD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation)
365-
return D;
366-
367-
// Function is an implicit instantiation of a function template?
368-
if (const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate())
369-
return *FTD;
370-
371-
// Function is instantiated from a member definition of a class template?
372-
if (const FunctionDecl *MemberDecl =
373-
FD->getInstantiatedFromMemberFunction())
374-
return *MemberDecl;
375-
376-
return D;
377-
}
378-
if (const auto *VD = dyn_cast<VarDecl>(&D)) {
379-
// Static data member is instantiated from a member definition of a class
380-
// template?
381-
if (VD->isStaticDataMember())
382-
if (const VarDecl *MemberDecl = VD->getInstantiatedFromStaticDataMember())
383-
return *MemberDecl;
384-
385-
return D;
386-
}
387-
if (const auto *CRD = dyn_cast<CXXRecordDecl>(&D)) {
388-
// Is this class declaration part of a class template?
389-
if (const ClassTemplateDecl *CTD = CRD->getDescribedClassTemplate())
390-
return *CTD;
391-
392-
// Class is an implicit instantiation of a class template or partial
393-
// specialization?
394-
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CRD)) {
395-
if (CTSD->getSpecializationKind() != TSK_ImplicitInstantiation)
396-
return D;
397-
llvm::PointerUnion<ClassTemplateDecl *,
398-
ClassTemplatePartialSpecializationDecl *>
399-
PU = CTSD->getSpecializedTemplateOrPartial();
400-
return isa<ClassTemplateDecl *>(PU)
401-
? *static_cast<const Decl *>(cast<ClassTemplateDecl *>(PU))
402-
: *static_cast<const Decl *>(
403-
cast<ClassTemplatePartialSpecializationDecl *>(PU));
404-
}
405-
406-
// Class is instantiated from a member definition of a class template?
407-
if (const MemberSpecializationInfo *Info =
408-
CRD->getMemberSpecializationInfo())
409-
return *Info->getInstantiatedFrom();
410-
411-
return D;
412-
}
413-
if (const auto *ED = dyn_cast<EnumDecl>(&D)) {
414-
// Enum is instantiated from a member definition of a class template?
415-
if (const EnumDecl *MemberDecl = ED->getInstantiatedFromMemberEnum())
416-
return *MemberDecl;
417-
418-
return D;
419-
}
420-
// FIXME: Adjust alias templates?
421-
return D;
422-
}
423-
424354
const RawComment *ASTContext::getRawCommentForAnyRedecl(
425355
const Decl *D,
426356
const Decl **OriginalDecl) const {

clang/lib/AST/DeclTemplate.cpp

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

0 commit comments

Comments
 (0)