Skip to content

Commit 1426bb4

Browse files
committed
[clangd] Print underlying type for decltypes in hover
Summary: Fixes clangd/clangd#249 Reviewers: sammccall Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D72498 (cherry picked from commit 0474fe4)
1 parent 7350a04 commit 1426bb4

File tree

2 files changed

+74
-15
lines changed

2 files changed

+74
-15
lines changed

clang-tools-extra/clangd/Hover.cpp

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ void printParams(llvm::raw_ostream &OS,
123123
}
124124
}
125125

126+
std::string printType(QualType QT, const PrintingPolicy &Policy) {
127+
// TypePrinter doesn't resolve decltypes, so resolve them here.
128+
// FIXME: This doesn't handle composite types that contain a decltype in them.
129+
// We should rather have a printing policy for that.
130+
while (const auto *DT = QT->getAs<DecltypeType>())
131+
QT = DT->getUnderlyingType();
132+
return QT.getAsString(Policy);
133+
}
134+
126135
std::vector<HoverInfo::Param>
127136
fetchTemplateParameters(const TemplateParameterList *Params,
128137
const PrintingPolicy &PP) {
@@ -131,8 +140,7 @@ fetchTemplateParameters(const TemplateParameterList *Params,
131140

132141
for (const Decl *Param : *Params) {
133142
HoverInfo::Param P;
134-
P.Type.emplace();
135-
if (const auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
143+
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
136144
P.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
137145
if (TTP->isParameterPack())
138146
*P.Type += "...";
@@ -141,21 +149,21 @@ fetchTemplateParameters(const TemplateParameterList *Params,
141149
P.Name = TTP->getNameAsString();
142150
if (TTP->hasDefaultArgument())
143151
P.Default = TTP->getDefaultArgument().getAsString(PP);
144-
} else if (const auto NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
152+
} else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
145153
if (IdentifierInfo *II = NTTP->getIdentifier())
146154
P.Name = II->getName().str();
147155

148-
llvm::raw_string_ostream Out(*P.Type);
149-
NTTP->getType().print(Out, PP);
156+
P.Type = printType(NTTP->getType(), PP);
150157
if (NTTP->isParameterPack())
151-
Out << "...";
158+
*P.Type += "...";
152159

153160
if (NTTP->hasDefaultArgument()) {
154161
P.Default.emplace();
155162
llvm::raw_string_ostream Out(*P.Default);
156163
NTTP->getDefaultArgument()->printPretty(Out, nullptr, PP);
157164
}
158-
} else if (const auto TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
165+
} else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
166+
P.Type.emplace();
159167
llvm::raw_string_ostream OS(*P.Type);
160168
OS << "template <";
161169
printParams(OS,
@@ -241,7 +249,7 @@ void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
241249
HI.Parameters->emplace_back();
242250
auto &P = HI.Parameters->back();
243251
if (!PVD->getType().isNull()) {
244-
P.Type = PVD->getType().getAsString(Policy);
252+
P.Type = printType(PVD->getType(), Policy);
245253
} else {
246254
std::string Param;
247255
llvm::raw_string_ostream OS(Param);
@@ -265,12 +273,12 @@ void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
265273
} else if (llvm::isa<CXXDestructorDecl>(FD)) {
266274
HI.ReturnType = "void";
267275
} else {
268-
HI.ReturnType = FD->getReturnType().getAsString(Policy);
276+
HI.ReturnType = printType(FD->getReturnType(), Policy);
269277

270-
QualType FunctionType = FD->getType();
278+
QualType QT = FD->getType();
271279
if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) // Lambdas
272-
FunctionType = VD->getType().getDesugaredType(D->getASTContext());
273-
HI.Type = FunctionType.getAsString(Policy);
280+
QT = VD->getType().getDesugaredType(D->getASTContext());
281+
HI.Type = printType(QT, Policy);
274282
}
275283
// FIXME: handle variadics.
276284
}
@@ -342,7 +350,7 @@ HoverInfo getHoverContents(const NamedDecl *D, const SymbolIndex *Index) {
342350
fetchTemplateParameters(TD->getTemplateParameters(), Policy);
343351
D = TD;
344352
} else if (const FunctionDecl *FD = D->getAsFunction()) {
345-
if (const auto FTD = FD->getDescribedTemplate()) {
353+
if (const auto *FTD = FD->getDescribedTemplate()) {
346354
HI.TemplateParameters =
347355
fetchTemplateParameters(FTD->getTemplateParameters(), Policy);
348356
D = FTD;
@@ -353,7 +361,7 @@ HoverInfo getHoverContents(const NamedDecl *D, const SymbolIndex *Index) {
353361
if (const FunctionDecl *FD = getUnderlyingFunction(D))
354362
fillFunctionTypeAndParams(HI, D, FD, Policy);
355363
else if (const auto *VD = dyn_cast<ValueDecl>(D))
356-
HI.Type = VD->getType().getAsString(Policy);
364+
HI.Type = printType(VD->getType(), Policy);
357365

358366
// Fill in value with evaluated initializer if possible.
359367
if (const auto *Var = dyn_cast<VarDecl>(D)) {
@@ -449,7 +457,7 @@ llvm::Optional<HoverInfo> getHoverContents(const Expr *E, ParsedAST &AST) {
449457
auto Policy =
450458
printingPolicyForDecls(AST.getASTContext().getPrintingPolicy());
451459
Policy.SuppressTagKeyword = true;
452-
HI.Type = E->getType().getAsString(Policy);
460+
HI.Type = printType(E->getType(), Policy);
453461
HI.Value = *Val;
454462
HI.Name = getNameForExpr(E);
455463
return HI;

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,56 @@ TEST(Hover, All) {
15141514
HI.Name = "cls<cls<cls<int> > >";
15151515
HI.Documentation = "type of nested templates.";
15161516
}},
1517+
{
1518+
R"cpp(// type with decltype
1519+
int a;
1520+
decltype(a) [[b^]] = a;)cpp",
1521+
[](HoverInfo &HI) {
1522+
HI.Definition = "decltype(a) b = a";
1523+
HI.Kind = index::SymbolKind::Variable;
1524+
HI.NamespaceScope = "";
1525+
HI.Name = "b";
1526+
HI.Type = "int";
1527+
}},
1528+
{
1529+
R"cpp(// type with decltype
1530+
int a;
1531+
decltype(a) c;
1532+
decltype(c) [[b^]] = a;)cpp",
1533+
[](HoverInfo &HI) {
1534+
HI.Definition = "decltype(c) b = a";
1535+
HI.Kind = index::SymbolKind::Variable;
1536+
HI.NamespaceScope = "";
1537+
HI.Name = "b";
1538+
HI.Type = "int";
1539+
}},
1540+
{
1541+
R"cpp(// type with decltype
1542+
int a;
1543+
const decltype(a) [[b^]] = a;)cpp",
1544+
[](HoverInfo &HI) {
1545+
HI.Definition = "const decltype(a) b = a";
1546+
HI.Kind = index::SymbolKind::Variable;
1547+
HI.NamespaceScope = "";
1548+
HI.Name = "b";
1549+
HI.Type = "int";
1550+
}},
1551+
{
1552+
R"cpp(// type with decltype
1553+
int a;
1554+
auto [[f^oo]](decltype(a) x) -> decltype(a) { return 0; })cpp",
1555+
[](HoverInfo &HI) {
1556+
HI.Definition = "auto foo(decltype(a) x) -> decltype(a)";
1557+
HI.Kind = index::SymbolKind::Function;
1558+
HI.NamespaceScope = "";
1559+
HI.Name = "foo";
1560+
// FIXME: Handle composite types with decltype with a printing
1561+
// policy.
1562+
HI.Type = "auto (decltype(a)) -> decltype(a)";
1563+
HI.ReturnType = "int";
1564+
HI.Parameters = {
1565+
{std::string("int"), std::string("x"), llvm::None}};
1566+
}},
15171567
};
15181568

15191569
// Create a tiny index, so tests above can verify documentation is fetched.
@@ -1542,6 +1592,7 @@ TEST(Hover, All) {
15421592
Expected.SymRange = T.range();
15431593
Case.ExpectedBuilder(Expected);
15441594

1595+
SCOPED_TRACE(H->present().asPlainText());
15451596
EXPECT_EQ(H->NamespaceScope, Expected.NamespaceScope);
15461597
EXPECT_EQ(H->LocalScope, Expected.LocalScope);
15471598
EXPECT_EQ(H->Name, Expected.Name);

0 commit comments

Comments
 (0)