diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -49,16 +49,13 @@ namespace clangd { namespace { -PrintingPolicy printingPolicyForDecls(PrintingPolicy Base) { - PrintingPolicy Policy(Base); - - Policy.AnonymousTagLocations = false; - Policy.TerseOutput = true; - Policy.PolishForDeclaration = true; - Policy.ConstantsAsWritten = true; - Policy.SuppressTagKeyword = false; - - return Policy; +PrintingPolicy getPrintingPolicy(PrintingPolicy Base) { + Base.AnonymousTagLocations = false; + Base.TerseOutput = true; + Base.PolishForDeclaration = true; + Base.ConstantsAsWritten = true; + Base.SuppressTemplateArgsInCXXConstructors = true; + return Base; } /// Given a declaration \p D, return a human-readable string representing the @@ -108,26 +105,33 @@ return ""; } -std::string printDefinition(const Decl *D) { +std::string printDefinition(const Decl *D, const PrintingPolicy &PP) { std::string Definition; llvm::raw_string_ostream OS(Definition); - PrintingPolicy Policy = - printingPolicyForDecls(D->getASTContext().getPrintingPolicy()); - Policy.IncludeTagDefinition = false; - Policy.SuppressTemplateArgsInCXXConstructors = true; - Policy.SuppressTagKeyword = true; - D->print(OS, Policy); + D->print(OS, PP); OS.flush(); return Definition; } -std::string printType(QualType QT, const PrintingPolicy &Policy) { +std::string printType(QualType QT, const PrintingPolicy &PP) { // TypePrinter doesn't resolve decltypes, so resolve them here. // FIXME: This doesn't handle composite types that contain a decltype in them. // We should rather have a printing policy for that. while (!QT.isNull() && QT->isDecltypeType()) QT = QT->getAs()->getUnderlyingType(); - return QT.getAsString(Policy); + std::string Result; + llvm::raw_string_ostream OS(Result); + // Special case: if the outer type is a tag type without qualifiers, then + // include the tag for extra clarity. + // This isn't very idiomatic, so don't attempt it for complex cases, including + // pointers/references, template specializations, etc. + if (!QT.isNull() && !QT.hasQualifiers() && PP.SuppressTagKeyword) { + if (auto *TT = llvm::dyn_cast(QT.getTypePtr())) + OS << TT->getDecl()->getKindName() << " "; + } + OS.flush(); + QT.print(OS, PP); + return Result; } std::string printType(const TemplateTypeParmDecl *TTP) { @@ -291,15 +295,15 @@ } HoverInfo::Param toHoverInfoParam(const ParmVarDecl *PVD, - const PrintingPolicy &Policy) { + const PrintingPolicy &PP) { HoverInfo::Param Out; - Out.Type = printType(PVD->getType(), Policy); + Out.Type = printType(PVD->getType(), PP); if (!PVD->getName().empty()) Out.Name = PVD->getNameAsString(); if (const Expr *DefArg = getDefaultArg(PVD)) { Out.Default.emplace(); llvm::raw_string_ostream OS(*Out.Default); - DefArg->printPretty(OS, nullptr, Policy); + DefArg->printPretty(OS, nullptr, PP); } return Out; } @@ -307,10 +311,10 @@ // Populates Type, ReturnType, and Parameters for function-like decls. void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D, const FunctionDecl *FD, - const PrintingPolicy &Policy) { + const PrintingPolicy &PP) { HI.Parameters.emplace(); for (const ParmVarDecl *PVD : FD->parameters()) - HI.Parameters->emplace_back(toHoverInfoParam(PVD, Policy)); + HI.Parameters->emplace_back(toHoverInfoParam(PVD, PP)); // We don't want any type info, if name already contains it. This is true for // constructors/destructors and conversion operators. @@ -320,11 +324,11 @@ NK == DeclarationName::CXXConversionFunctionName) return; - HI.ReturnType = printType(FD->getReturnType(), Policy); + HI.ReturnType = printType(FD->getReturnType(), PP); QualType QT = FD->getType(); if (const VarDecl *VD = llvm::dyn_cast(D)) // Lambdas QT = VD->getType().getDesugaredType(D->getASTContext()); - HI.Type = printType(QT, Policy); + HI.Type = printType(QT, PP); // FIXME: handle variadics. } @@ -492,7 +496,8 @@ } /// Generate a \p Hover object given the declaration \p D. -HoverInfo getHoverContents(const NamedDecl *D, const SymbolIndex *Index) { +HoverInfo getHoverContents(const NamedDecl *D, const PrintingPolicy &PP, + const SymbolIndex *Index) { HoverInfo HI; const ASTContext &Ctx = D->getASTContext(); @@ -504,7 +509,6 @@ if (!HI.LocalScope.empty()) HI.LocalScope.append("::"); - PrintingPolicy Policy = printingPolicyForDecls(Ctx.getPrintingPolicy()); HI.Name = printName(Ctx, *D); const auto *CommentD = getDeclForComment(D); HI.Documentation = getDeclComment(Ctx, *CommentD); @@ -517,25 +521,25 @@ // Fill in template params. if (const TemplateDecl *TD = D->getDescribedTemplate()) { HI.TemplateParameters = - fetchTemplateParameters(TD->getTemplateParameters(), Policy); + fetchTemplateParameters(TD->getTemplateParameters(), PP); D = TD; } else if (const FunctionDecl *FD = D->getAsFunction()) { if (const auto *FTD = FD->getDescribedTemplate()) { HI.TemplateParameters = - fetchTemplateParameters(FTD->getTemplateParameters(), Policy); + fetchTemplateParameters(FTD->getTemplateParameters(), PP); D = FTD; } } // Fill in types and params. if (const FunctionDecl *FD = getUnderlyingFunction(D)) - fillFunctionTypeAndParams(HI, D, FD, Policy); + fillFunctionTypeAndParams(HI, D, FD, PP); else if (const auto *VD = dyn_cast(D)) - HI.Type = printType(VD->getType(), Policy); + HI.Type = printType(VD->getType(), PP); else if (const auto *TTP = dyn_cast(D)) HI.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class"; else if (const auto *TTP = dyn_cast(D)) - HI.Type = printType(TTP, Policy); + HI.Type = printType(TTP, PP); // Fill in value with evaluated initializer if possible. if (const auto *Var = dyn_cast(D)) { @@ -547,7 +551,7 @@ HI.Value = ECD->getInitVal().toString(10); } - HI.Definition = printDefinition(D); + HI.Definition = printDefinition(D, PP); return HI; } @@ -587,7 +591,8 @@ } llvm::Optional getThisExprHoverContents(const CXXThisExpr *CTE, - ASTContext &ASTCtx) { + ASTContext &ASTCtx, + const PrintingPolicy &PP) { QualType OriginThisType = CTE->getType()->getPointeeType(); QualType ClassType = declaredType(OriginThisType->getAsTagDecl()); // For partial specialization class, origin `this` pointee type will be @@ -597,30 +602,26 @@ QualType PrettyThisType = ASTCtx.getPointerType( QualType(ClassType.getTypePtr(), OriginThisType.getCVRQualifiers())); - auto Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy()); - Policy.SuppressTagKeyword = true; - Policy.SuppressScope = true; HoverInfo HI; HI.Name = "this"; - HI.Definition = PrettyThisType.getAsString(Policy); + HI.Definition = printType(PrettyThisType, PP); return HI; } /// Generate a HoverInfo object given the deduced type \p QT HoverInfo getDeducedTypeHoverContents(QualType QT, const syntax::Token &Tok, ASTContext &ASTCtx, + const PrintingPolicy &PP, const SymbolIndex *Index) { HoverInfo HI; // FIXME: distinguish decltype(auto) vs decltype(expr) HI.Name = tok::getTokenName(Tok.kind()); HI.Kind = index::SymbolKind::TypeAlias; - auto PP = printingPolicyForDecls(ASTCtx.getLangOpts()); - if (QT->isUndeducedAutoType()) { HI.Definition = "/* not deduced */"; } else { - HI.Definition = QT.getAsString(PP); + HI.Definition = printType(QT, PP); if (const auto *D = QT->getAsTagDecl()) { const auto *CommentD = getDeclForComment(D); @@ -657,6 +658,7 @@ // Generates hover info for `this` and evaluatable expressions. // FIXME: Support hover for literals (esp user-defined) llvm::Optional getHoverContents(const Expr *E, ParsedAST &AST, + const PrintingPolicy &PP, const SymbolIndex *Index) { // There's not much value in hovering over "42" and getting a hover card // saying "42 is an int", similar for other literals. @@ -666,14 +668,11 @@ HoverInfo HI; // For `this` expr we currently generate hover with pointee type. if (const CXXThisExpr *CTE = dyn_cast(E)) - return getThisExprHoverContents(CTE, AST.getASTContext()); + return getThisExprHoverContents(CTE, AST.getASTContext(), PP); // For expressions we currently print the type and the value, iff it is // evaluatable. if (auto Val = printExprValue(E, AST.getASTContext())) { - auto Policy = - printingPolicyForDecls(AST.getASTContext().getPrintingPolicy()); - Policy.SuppressTagKeyword = true; - HI.Type = printType(E->getType(), Policy); + HI.Type = printType(E->getType(), PP); HI.Value = *Val; HI.Name = std::string(getNameForExpr(E)); return HI; @@ -744,7 +743,7 @@ // If N is passed as argument to a function, fill HI.CalleeArgInfo with // information about that argument. void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI, - const PrintingPolicy &Policy) { + const PrintingPolicy &PP) { const auto &OuterNode = N->outerImplicit(); if (!OuterNode.Parent) return; @@ -768,7 +767,7 @@ // Extract matching argument from function declaration. if (const ParmVarDecl *PVD = FD->getParamDecl(I)) - HI.CalleeArgInfo.emplace(toHoverInfoParam(PVD, Policy)); + HI.CalleeArgInfo.emplace(toHoverInfoParam(PVD, PP)); break; } if (!HI.CalleeArgInfo) @@ -832,6 +831,8 @@ llvm::Optional getHover(ParsedAST &AST, Position Pos, format::FormatStyle Style, const SymbolIndex *Index) { + PrintingPolicy PP = + getPrintingPolicy(AST.getASTContext().getPrintingPolicy()); const SourceManager &SM = AST.getSourceManager(); auto CurLoc = sourceLocationInMainFile(SM, Pos); if (!CurLoc) { @@ -863,7 +864,7 @@ } } else if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) { if (auto Deduced = getDeducedType(AST.getASTContext(), Tok.location())) { - HI = getDeducedTypeHoverContents(*Deduced, Tok, AST.getASTContext(), + HI = getDeducedTypeHoverContents(*Deduced, Tok, AST.getASTContext(), PP, Index); HighlightRange = Tok.range(SM).toCharRange(SM); break; @@ -888,16 +889,16 @@ // FIXME: Fill in HighlightRange with range coming from N->ASTNode. auto Decls = explicitReferenceTargets(N->ASTNode, DeclRelation::Alias); if (!Decls.empty()) { - HI = getHoverContents(Decls.front(), Index); + HI = getHoverContents(Decls.front(), PP, Index); // Layout info only shown when hovering on the field/class itself. if (Decls.front() == N->ASTNode.get()) addLayoutInfo(*Decls.front(), *HI); // Look for a close enclosing expression to show the value of. if (!HI->Value) HI->Value = printExprValue(N, AST.getASTContext()); - maybeAddCalleeArgInfo(N, *HI, AST.getASTContext().getPrintingPolicy()); + maybeAddCalleeArgInfo(N, *HI, PP); } else if (const Expr *E = N->ASTNode.get()) { - HI = getHoverContents(E, AST, Index); + HI = getHoverContents(E, AST, PP, Index); } // FIXME: support hovers for other nodes? // - built-in types diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -239,7 +239,7 @@ HI.Name = "c"; HI.Kind = index::SymbolKind::Variable; HI.Definition = "auto *c = &b"; - HI.Type = "class (lambda) **"; + HI.Type = "(lambda) **"; HI.ReturnType = "bool"; HI.Parameters = { {std::string("int"), std::string("T"), llvm::None}, @@ -611,7 +611,7 @@ [](HoverInfo &HI) { HI.Name = "auto"; HI.Kind = index::SymbolKind::TypeAlias; - HI.Definition = "class Foo"; + HI.Definition = "class Foo"; }}, {// Falls back to primary template, when the type is not instantiated. R"cpp( @@ -718,8 +718,8 @@ HI.Definition = "X &setY(float v)"; HI.LocalScope = "X::"; HI.Documentation = "Trivial setter for `Y`."; - HI.Type = "struct X &(float)"; - HI.ReturnType = "struct X &"; + HI.Type = "X &(float)"; + HI.ReturnType = "X &"; HI.Parameters.emplace(); HI.Parameters->emplace_back(); HI.Parameters->back().Type = "float"; @@ -1943,7 +1943,7 @@ HI.Kind = index::SymbolKind::Variable; HI.NamespaceScope = ""; HI.LocalScope = "test::"; - HI.Type = "struct Test &&"; + HI.Type = "Test &&"; HI.Definition = "Test &&test = {}"; }}, { @@ -2211,7 +2211,7 @@ )cpp", [](HoverInfo &HI) { HI.Name = "this"; - HI.Definition = "Foo *"; + HI.Definition = "ns::Foo *"; }}, { R"cpp(// this expr for template class