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
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<DecltypeType>()->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<TagType>(QT.getTypePtr()))
+ OS << TT->getDecl()->getKindName() << " ";
+ }
+ OS.flush();
+ QT.print(OS, PP);
+ return Result;
}
std::string printType(const TemplateTypeParmDecl *TTP) {
}
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;
}
// 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.
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<VarDecl>(D)) // Lambdas
QT = VD->getType().getDesugaredType(D->getASTContext());
- HI.Type = printType(QT, Policy);
+ HI.Type = printType(QT, PP);
// FIXME: handle variadics.
}
}
/// 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();
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);
// 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<ValueDecl>(D))
- HI.Type = printType(VD->getType(), Policy);
+ HI.Type = printType(VD->getType(), PP);
else if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
HI.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class";
else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(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<VarDecl>(D)) {
HI.Value = ECD->getInitVal().toString(10);
}
- HI.Definition = printDefinition(D);
+ HI.Definition = printDefinition(D, PP);
return HI;
}
}
llvm::Optional<HoverInfo> 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
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);
// Generates hover info for `this` and evaluatable expressions.
// FIXME: Support hover for literals (esp user-defined)
llvm::Optional<HoverInfo> 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.
HoverInfo HI;
// For `this` expr we currently generate hover with pointee type.
if (const CXXThisExpr *CTE = dyn_cast<CXXThisExpr>(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;
// 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;
// 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)
llvm::Optional<HoverInfo> 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) {
}
} 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;
// 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<Decl>())
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<Expr>()) {
- HI = getHoverContents(E, AST, Index);
+ HI = getHoverContents(E, AST, PP, Index);
}
// FIXME: support hovers for other nodes?
// - built-in types