[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:
Kadir Cetinkaya 2020-01-30 18:42:01 +01:00
parent 0426c2d07d
commit 9c903d0373
No known key found for this signature in database
GPG Key ID: E39E36B8D2057ED6
2 changed files with 32 additions and 2 deletions

View File

@ -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.
void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
const FunctionDecl *FD,
@ -269,10 +283,10 @@ void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
}
if (!PVD->getName().empty())
P.Name = PVD->getNameAsString();
if (PVD->hasDefaultArg()) {
if (const Expr *DefArg = getDefaultArg(PVD)) {
P.Default.emplace();
llvm::raw_string_ostream Out(*P.Default);
PVD->getDefaultArg()->printPretty(Out, nullptr, Policy);
DefArg->printPretty(Out, nullptr, Policy);
}
}

View File

@ -1609,6 +1609,22 @@ TEST(Hover, All) {
HI.Type = "unsigned long";
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.