forked from OSchip/llvm-project
[clangd][Hover] Handle uninstantiated default args
Summary: Default args might exist but be unparsed or uninstantiated. getDefaultArg asserts on those. This patch makes sure we don't crash in such scenarios. Reviewers: sammccall, ilya-biryukov Subscribers: MaskRay, jkorous, arphaman, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D73723
This commit is contained in:
parent
0426c2d07d
commit
9c903d0373
|
@ -250,6 +250,20 @@ void enhanceFromIndex(HoverInfo &Hover, const NamedDecl &ND,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default argument might exist but be unavailable, in the case of unparsed
|
||||||
|
// arguments for example. This function returns the default argument if it is
|
||||||
|
// available.
|
||||||
|
const Expr *getDefaultArg(const ParmVarDecl *PVD) {
|
||||||
|
// Default argument can be unparsed or uninstatiated. For the former we
|
||||||
|
// can't do much, as token information is only stored in Sema and not
|
||||||
|
// attached to the AST node. For the latter though, it is safe to proceed as
|
||||||
|
// the expression is still valid.
|
||||||
|
if (!PVD->hasDefaultArg() || PVD->hasUnparsedDefaultArg())
|
||||||
|
return nullptr;
|
||||||
|
return PVD->hasUninstantiatedDefaultArg() ? PVD->getUninstantiatedDefaultArg()
|
||||||
|
: PVD->getDefaultArg();
|
||||||
|
}
|
||||||
|
|
||||||
// Populates Type, ReturnType, and Parameters for function-like decls.
|
// Populates Type, ReturnType, and Parameters for function-like decls.
|
||||||
void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
|
void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
|
||||||
const FunctionDecl *FD,
|
const FunctionDecl *FD,
|
||||||
|
@ -269,10 +283,10 @@ void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
|
||||||
}
|
}
|
||||||
if (!PVD->getName().empty())
|
if (!PVD->getName().empty())
|
||||||
P.Name = PVD->getNameAsString();
|
P.Name = PVD->getNameAsString();
|
||||||
if (PVD->hasDefaultArg()) {
|
if (const Expr *DefArg = getDefaultArg(PVD)) {
|
||||||
P.Default.emplace();
|
P.Default.emplace();
|
||||||
llvm::raw_string_ostream Out(*P.Default);
|
llvm::raw_string_ostream Out(*P.Default);
|
||||||
PVD->getDefaultArg()->printPretty(Out, nullptr, Policy);
|
DefArg->printPretty(Out, nullptr, Policy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1609,6 +1609,22 @@ TEST(Hover, All) {
|
||||||
HI.Type = "unsigned long";
|
HI.Type = "unsigned long";
|
||||||
HI.Value = "1";
|
HI.Value = "1";
|
||||||
}},
|
}},
|
||||||
|
{
|
||||||
|
R"cpp(
|
||||||
|
template <typename T = int>
|
||||||
|
void foo(const T& = T()) {
|
||||||
|
[[f^oo]]<>(3);
|
||||||
|
})cpp",
|
||||||
|
[](HoverInfo &HI) {
|
||||||
|
HI.Name = "foo";
|
||||||
|
HI.Kind = index::SymbolKind::Function;
|
||||||
|
HI.Type = "void (const int &)";
|
||||||
|
HI.ReturnType = "void";
|
||||||
|
HI.Parameters = {
|
||||||
|
{std::string("const int &"), llvm::None, std::string("T()")}};
|
||||||
|
HI.Definition = "template <> void foo<int>(const int &)";
|
||||||
|
HI.NamespaceScope = "";
|
||||||
|
}},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a tiny index, so tests above can verify documentation is fetched.
|
// Create a tiny index, so tests above can verify documentation is fetched.
|
||||||
|
|
Loading…
Reference in New Issue