diff --git a/clang-tools-extra/clangd/AST.h b/clang-tools-extra/clangd/AST.h --- a/clang-tools-extra/clangd/AST.h +++ b/clang-tools-extra/clangd/AST.h @@ -111,6 +111,11 @@ /// 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 rather than vector. +QualType declaredType(const TypeDecl *D); + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -246,6 +246,12 @@ printNamespaceScope(Context) ); } +QualType declaredType(const TypeDecl *D) { + if (const auto *CTSD = llvm::dyn_cast(D)) + if (const auto *TSI = CTSD->getTypeAsWritten()) + return TSI->getType(); + return D->getASTContext().getTypeDeclType(D); +} } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -566,6 +566,51 @@ 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(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(FD)){ + HI.ReturnType = "void"; + } else { + HI.ReturnType = FD->getReturnType().getAsString(Policy); + + QualType FunctionType = FD->getType(); + if (const VarDecl *VD = llvm::dyn_cast(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 @@ // 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(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(D)) { HI.Type.emplace(); llvm::raw_string_ostream OS(*HI.Type); diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -918,11 +918,20 @@ HI.Name = "X"; HI.LocalScope = "X::"; // FIXME: Should be X:: HI.Kind = SymbolKind::Constructor; - HI.Type = "void ()"; // FIXME: Should be None - HI.ReturnType = "void"; // FIXME: Should be None or X + HI.ReturnType = "X"; 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(