[clangd] More sensible output for constructors/destructors in hover.

Summary:
Previously: both had type void() and return type void.
Now: neither have a type. Constructors return T, destructors return void.

Reviewers: hokein

Subscribers: merge_guards_bot, ilya-biryukov, MaskRay, jkorous, arphaman, kadircet, usaxena95, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D70317
This commit is contained in:
Sam McCall 2019-11-18 21:29:17 +01:00
parent f0021f95a1
commit 6ec0714098
4 changed files with 68 additions and 41 deletions

View File

@ -246,6 +246,12 @@ std::string printType(const QualType QT, const DeclContext & Context){
printNamespaceScope(Context) );
}
QualType declaredType(const TypeDecl *D) {
if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D))
if (const auto *TSI = CTSD->getTypeAsWritten())
return TSI->getType();
return D->getASTContext().getTypeDeclType(D);
}
} // namespace clangd
} // namespace clang

View File

@ -111,6 +111,11 @@ bool isExplicitTemplateSpecialization(const NamedDecl *D);
/// void foo() -> returns null
NestedNameSpecifierLoc getQualifierLoc(const NamedDecl &ND);
// Returns a type corresponding to a declaration of that type.
// Unlike the method on ASTContext, attempts to preserve the type as-written
// (i.e. vector<T*> rather than vector<type-parameter-0-0 *>.
QualType declaredType(const TypeDecl *D);
} // namespace clangd
} // namespace clang

View File

@ -566,6 +566,51 @@ static void enhanceFromIndex(HoverInfo &Hover, const Decl *D,
Req, [&](const Symbol &S) { Hover.Documentation = S.Documentation; });
}
// Populates Type, ReturnType, and Parameters for function-like decls.
static void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
const FunctionDecl *FD,
const PrintingPolicy &Policy) {
HI.Parameters.emplace();
for (const ParmVarDecl *PVD : FD->parameters()) {
HI.Parameters->emplace_back();
auto &P = HI.Parameters->back();
if (!PVD->getType().isNull()) {
P.Type.emplace();
llvm::raw_string_ostream OS(*P.Type);
PVD->getType().print(OS, Policy);
} else {
std::string Param;
llvm::raw_string_ostream OS(Param);
PVD->dump(OS);
OS.flush();
elog("Got param with null type: {0}", Param);
}
if (!PVD->getName().empty())
P.Name = PVD->getNameAsString();
if (PVD->hasDefaultArg()) {
P.Default.emplace();
llvm::raw_string_ostream Out(*P.Default);
PVD->getDefaultArg()->printPretty(Out, nullptr, Policy);
}
}
if (const auto* CCD = llvm::dyn_cast<CXXConstructorDecl>(FD)) {
// Constructor's "return type" is the class type.
HI.ReturnType = declaredType(CCD->getParent()).getAsString(Policy);
// Don't provide any type for the constructor itself.
} else if (const auto* CDD = llvm::dyn_cast<CXXDestructorDecl>(FD)){
HI.ReturnType = "void";
} else {
HI.ReturnType = FD->getReturnType().getAsString(Policy);
QualType FunctionType = FD->getType();
if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) // Lambdas
FunctionType = VD->getType().getDesugaredType(D->getASTContext());
HI.Type = FunctionType.getAsString(Policy);
}
// FIXME: handle variadics.
}
/// Generate a \p Hover object given the declaration \p D.
static HoverInfo getHoverContents(const Decl *D, const SymbolIndex *Index) {
HoverInfo HI;
@ -601,45 +646,7 @@ static HoverInfo getHoverContents(const Decl *D, const SymbolIndex *Index) {
// Fill in types and params.
if (const FunctionDecl *FD = getUnderlyingFunction(D)) {
HI.ReturnType.emplace();
{
llvm::raw_string_ostream OS(*HI.ReturnType);
FD->getReturnType().print(OS, Policy);
}
HI.Parameters.emplace();
for (const ParmVarDecl *PVD : FD->parameters()) {
HI.Parameters->emplace_back();
auto &P = HI.Parameters->back();
if (!PVD->getType().isNull()) {
P.Type.emplace();
llvm::raw_string_ostream OS(*P.Type);
PVD->getType().print(OS, Policy);
} else {
std::string Param;
llvm::raw_string_ostream OS(Param);
PVD->dump(OS);
OS.flush();
elog("Got param with null type: {0}", Param);
}
if (!PVD->getName().empty())
P.Name = PVD->getNameAsString();
if (PVD->hasDefaultArg()) {
P.Default.emplace();
llvm::raw_string_ostream Out(*P.Default);
PVD->getDefaultArg()->printPretty(Out, nullptr, Policy);
}
}
HI.Type.emplace();
llvm::raw_string_ostream TypeOS(*HI.Type);
// Lambdas
if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D))
VD->getType().getDesugaredType(D->getASTContext()).print(TypeOS, Policy);
// Functions
else
FD->getType().print(TypeOS, Policy);
// FIXME: handle variadics.
fillFunctionTypeAndParams(HI, D, FD, Policy);
} else if (const auto *VD = dyn_cast<ValueDecl>(D)) {
HI.Type.emplace();
llvm::raw_string_ostream OS(*HI.Type);

View File

@ -918,11 +918,20 @@ void foo())cpp";
HI.Name = "X";
HI.LocalScope = "X::"; // FIXME: Should be X<T *>::
HI.Kind = SymbolKind::Constructor;
HI.Type = "void ()"; // FIXME: Should be None
HI.ReturnType = "void"; // FIXME: Should be None or X<T*>
HI.ReturnType = "X<T *>";
HI.Definition = "X()";
HI.Parameters.emplace();
}},
{"class X { [[^~]]X(); };", // FIXME: Should be [[~X]]()
[](HoverInfo &HI) {
HI.NamespaceScope = "";
HI.Name = "~X";
HI.LocalScope = "X::";
HI.Kind = SymbolKind::Constructor;
HI.ReturnType = "void";
HI.Definition = "~X()";
HI.Parameters.emplace();
}},
// auto on lambda
{R"cpp(