1 //===--- Hover.cpp - Information about code at the cursor location --------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "Hover.h" 10 11 #include "AST.h" 12 #include "CodeCompletionStrings.h" 13 #include "Config.h" 14 #include "FindTarget.h" 15 #include "Headers.h" 16 #include "IncludeCleaner.h" 17 #include "ParsedAST.h" 18 #include "Selection.h" 19 #include "SourceCode.h" 20 #include "clang-include-cleaner/Analysis.h" 21 #include "clang-include-cleaner/IncludeSpeller.h" 22 #include "clang-include-cleaner/Types.h" 23 #include "index/SymbolCollector.h" 24 #include "support/Markup.h" 25 #include "support/Trace.h" 26 #include "clang/AST/ASTContext.h" 27 #include "clang/AST/ASTDiagnostic.h" 28 #include "clang/AST/ASTTypeTraits.h" 29 #include "clang/AST/Attr.h" 30 #include "clang/AST/Decl.h" 31 #include "clang/AST/DeclBase.h" 32 #include "clang/AST/DeclCXX.h" 33 #include "clang/AST/DeclObjC.h" 34 #include "clang/AST/DeclTemplate.h" 35 #include "clang/AST/Expr.h" 36 #include "clang/AST/ExprCXX.h" 37 #include "clang/AST/OperationKinds.h" 38 #include "clang/AST/PrettyPrinter.h" 39 #include "clang/AST/RecordLayout.h" 40 #include "clang/AST/Type.h" 41 #include "clang/Basic/CharInfo.h" 42 #include "clang/Basic/LLVM.h" 43 #include "clang/Basic/SourceLocation.h" 44 #include "clang/Basic/SourceManager.h" 45 #include "clang/Basic/Specifiers.h" 46 #include "clang/Basic/TokenKinds.h" 47 #include "clang/Index/IndexSymbol.h" 48 #include "clang/Tooling/Syntax/Tokens.h" 49 #include "llvm/ADT/ArrayRef.h" 50 #include "llvm/ADT/DenseSet.h" 51 #include "llvm/ADT/STLExtras.h" 52 #include "llvm/ADT/SmallVector.h" 53 #include "llvm/ADT/StringExtras.h" 54 #include "llvm/ADT/StringRef.h" 55 #include "llvm/Support/Casting.h" 56 #include "llvm/Support/Error.h" 57 #include "llvm/Support/Format.h" 58 #include "llvm/Support/ScopedPrinter.h" 59 #include "llvm/Support/raw_ostream.h" 60 #include <algorithm> 61 #include <optional> 62 #include <string> 63 #include <vector> 64 65 namespace clang { 66 namespace clangd { 67 namespace { 68 69 PrintingPolicy getPrintingPolicy(PrintingPolicy Base) { 70 Base.AnonymousTagLocations = false; 71 Base.TerseOutput = true; 72 Base.PolishForDeclaration = true; 73 Base.ConstantsAsWritten = true; 74 Base.SuppressTemplateArgsInCXXConstructors = true; 75 return Base; 76 } 77 78 /// Given a declaration \p D, return a human-readable string representing the 79 /// local scope in which it is declared, i.e. class(es) and method name. Returns 80 /// an empty string if it is not local. 81 std::string getLocalScope(const Decl *D) { 82 std::vector<std::string> Scopes; 83 const DeclContext *DC = D->getDeclContext(); 84 85 // ObjC scopes won't have multiple components for us to join, instead: 86 // - Methods: "-[Class methodParam1:methodParam2]" 87 // - Classes, categories, and protocols: "MyClass(Category)" 88 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) 89 return printObjCMethod(*MD); 90 if (const ObjCContainerDecl *CD = dyn_cast<ObjCContainerDecl>(DC)) 91 return printObjCContainer(*CD); 92 93 auto GetName = [](const TypeDecl *D) { 94 if (!D->getDeclName().isEmpty()) { 95 PrintingPolicy Policy = D->getASTContext().getPrintingPolicy(); 96 Policy.SuppressScope = true; 97 return declaredType(D).getAsString(Policy); 98 } 99 if (auto *RD = dyn_cast<RecordDecl>(D)) 100 return ("(anonymous " + RD->getKindName() + ")").str(); 101 return std::string(""); 102 }; 103 while (DC) { 104 if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC)) 105 Scopes.push_back(GetName(TD)); 106 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) 107 Scopes.push_back(FD->getNameAsString()); 108 DC = DC->getParent(); 109 } 110 111 return llvm::join(llvm::reverse(Scopes), "::"); 112 } 113 114 /// Returns the human-readable representation for namespace containing the 115 /// declaration \p D. Returns empty if it is contained global namespace. 116 std::string getNamespaceScope(const Decl *D) { 117 const DeclContext *DC = D->getDeclContext(); 118 119 // ObjC does not have the concept of namespaces, so instead we support 120 // local scopes. 121 if (isa<ObjCMethodDecl, ObjCContainerDecl>(DC)) 122 return ""; 123 124 if (const TagDecl *TD = dyn_cast<TagDecl>(DC)) 125 return getNamespaceScope(TD); 126 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) 127 return getNamespaceScope(FD); 128 if (const NamespaceDecl *NSD = dyn_cast<NamespaceDecl>(DC)) { 129 // Skip inline/anon namespaces. 130 if (NSD->isInline() || NSD->isAnonymousNamespace()) 131 return getNamespaceScope(NSD); 132 } 133 if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC)) 134 return printQualifiedName(*ND); 135 136 return ""; 137 } 138 139 std::string printDefinition(const Decl *D, PrintingPolicy PP, 140 const syntax::TokenBuffer &TB) { 141 if (auto *VD = llvm::dyn_cast<VarDecl>(D)) { 142 if (auto *IE = VD->getInit()) { 143 // Initializers might be huge and result in lots of memory allocations in 144 // some catostrophic cases. Such long lists are not useful in hover cards 145 // anyway. 146 if (200 < TB.expandedTokens(IE->getSourceRange()).size()) 147 PP.SuppressInitializers = true; 148 } 149 } 150 std::string Definition; 151 llvm::raw_string_ostream OS(Definition); 152 D->print(OS, PP); 153 return Definition; 154 } 155 156 const char *getMarkdownLanguage(const ASTContext &Ctx) { 157 const auto &LangOpts = Ctx.getLangOpts(); 158 if (LangOpts.ObjC && LangOpts.CPlusPlus) 159 return "objective-cpp"; 160 return LangOpts.ObjC ? "objective-c" : "cpp"; 161 } 162 163 HoverInfo::PrintedType printType(QualType QT, ASTContext &ASTCtx, 164 const PrintingPolicy &PP) { 165 // TypePrinter doesn't resolve decltypes, so resolve them here. 166 // FIXME: This doesn't handle composite types that contain a decltype in them. 167 // We should rather have a printing policy for that. 168 while (!QT.isNull() && QT->isDecltypeType()) 169 QT = QT->castAs<DecltypeType>()->getUnderlyingType(); 170 HoverInfo::PrintedType Result; 171 llvm::raw_string_ostream OS(Result.Type); 172 // Special case: if the outer type is a tag type without qualifiers, then 173 // include the tag for extra clarity. 174 // This isn't very idiomatic, so don't attempt it for complex cases, including 175 // pointers/references, template specializations, etc. 176 if (!QT.isNull() && !QT.hasQualifiers() && PP.SuppressTagKeyword) { 177 if (auto *TT = llvm::dyn_cast<TagType>(QT.getTypePtr())) 178 OS << TT->getDecl()->getKindName() << " "; 179 } 180 QT.print(OS, PP); 181 182 const Config &Cfg = Config::current(); 183 if (!QT.isNull() && Cfg.Hover.ShowAKA) { 184 bool ShouldAKA = false; 185 QualType DesugaredTy = clang::desugarForDiagnostic(ASTCtx, QT, ShouldAKA); 186 if (ShouldAKA) 187 Result.AKA = DesugaredTy.getAsString(PP); 188 } 189 return Result; 190 } 191 192 HoverInfo::PrintedType printType(const TemplateTypeParmDecl *TTP) { 193 HoverInfo::PrintedType Result; 194 Result.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class"; 195 if (TTP->isParameterPack()) 196 Result.Type += "..."; 197 return Result; 198 } 199 200 HoverInfo::PrintedType printType(const NonTypeTemplateParmDecl *NTTP, 201 const PrintingPolicy &PP) { 202 auto PrintedType = printType(NTTP->getType(), NTTP->getASTContext(), PP); 203 if (NTTP->isParameterPack()) { 204 PrintedType.Type += "..."; 205 if (PrintedType.AKA) 206 *PrintedType.AKA += "..."; 207 } 208 return PrintedType; 209 } 210 211 HoverInfo::PrintedType printType(const TemplateTemplateParmDecl *TTP, 212 const PrintingPolicy &PP) { 213 HoverInfo::PrintedType Result; 214 llvm::raw_string_ostream OS(Result.Type); 215 OS << "template <"; 216 llvm::StringRef Sep = ""; 217 for (const Decl *Param : *TTP->getTemplateParameters()) { 218 OS << Sep; 219 Sep = ", "; 220 if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) 221 OS << printType(TTP).Type; 222 else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) 223 OS << printType(NTTP, PP).Type; 224 else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) 225 OS << printType(TTPD, PP).Type; 226 } 227 // FIXME: TemplateTemplateParameter doesn't store the info on whether this 228 // param was a "typename" or "class". 229 OS << "> class"; 230 return Result; 231 } 232 233 std::vector<HoverInfo::Param> 234 fetchTemplateParameters(const TemplateParameterList *Params, 235 const PrintingPolicy &PP) { 236 assert(Params); 237 std::vector<HoverInfo::Param> TempParameters; 238 239 for (const Decl *Param : *Params) { 240 HoverInfo::Param P; 241 if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { 242 P.Type = printType(TTP); 243 244 if (!TTP->getName().empty()) 245 P.Name = TTP->getNameAsString(); 246 247 if (TTP->hasDefaultArgument()) { 248 P.Default.emplace(); 249 llvm::raw_string_ostream Out(*P.Default); 250 TTP->getDefaultArgument().getArgument().print(PP, Out, 251 /*IncludeType=*/false); 252 } 253 } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { 254 P.Type = printType(NTTP, PP); 255 256 if (IdentifierInfo *II = NTTP->getIdentifier()) 257 P.Name = II->getName().str(); 258 259 if (NTTP->hasDefaultArgument()) { 260 P.Default.emplace(); 261 llvm::raw_string_ostream Out(*P.Default); 262 NTTP->getDefaultArgument().getArgument().print(PP, Out, 263 /*IncludeType=*/false); 264 } 265 } else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) { 266 P.Type = printType(TTPD, PP); 267 268 if (!TTPD->getName().empty()) 269 P.Name = TTPD->getNameAsString(); 270 271 if (TTPD->hasDefaultArgument()) { 272 P.Default.emplace(); 273 llvm::raw_string_ostream Out(*P.Default); 274 TTPD->getDefaultArgument().getArgument().print(PP, Out, 275 /*IncludeType*/ false); 276 } 277 } 278 TempParameters.push_back(std::move(P)); 279 } 280 281 return TempParameters; 282 } 283 284 const FunctionDecl *getUnderlyingFunction(const Decl *D) { 285 // Extract lambda from variables. 286 if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) { 287 auto QT = VD->getType(); 288 if (!QT.isNull()) { 289 while (!QT->getPointeeType().isNull()) 290 QT = QT->getPointeeType(); 291 292 if (const auto *CD = QT->getAsCXXRecordDecl()) 293 return CD->getLambdaCallOperator(); 294 } 295 } 296 297 // Non-lambda functions. 298 return D->getAsFunction(); 299 } 300 301 // Returns the decl that should be used for querying comments, either from index 302 // or AST. 303 const NamedDecl *getDeclForComment(const NamedDecl *D) { 304 const NamedDecl *DeclForComment = D; 305 if (const auto *TSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D)) { 306 // Template may not be instantiated e.g. if the type didn't need to be 307 // complete; fallback to primary template. 308 if (TSD->getTemplateSpecializationKind() == TSK_Undeclared) 309 DeclForComment = TSD->getSpecializedTemplate(); 310 else if (const auto *TIP = TSD->getTemplateInstantiationPattern()) 311 DeclForComment = TIP; 312 } else if (const auto *TSD = 313 llvm::dyn_cast<VarTemplateSpecializationDecl>(D)) { 314 if (TSD->getTemplateSpecializationKind() == TSK_Undeclared) 315 DeclForComment = TSD->getSpecializedTemplate(); 316 else if (const auto *TIP = TSD->getTemplateInstantiationPattern()) 317 DeclForComment = TIP; 318 } else if (const auto *FD = D->getAsFunction()) 319 if (const auto *TIP = FD->getTemplateInstantiationPattern()) 320 DeclForComment = TIP; 321 // Ensure that getDeclForComment(getDeclForComment(X)) = getDeclForComment(X). 322 // This is usually not needed, but in strange cases of comparision operators 323 // being instantiated from spasceship operater, which itself is a template 324 // instantiation the recursrive call is necessary. 325 if (D != DeclForComment) 326 DeclForComment = getDeclForComment(DeclForComment); 327 return DeclForComment; 328 } 329 330 // Look up information about D from the index, and add it to Hover. 331 void enhanceFromIndex(HoverInfo &Hover, const NamedDecl &ND, 332 const SymbolIndex *Index) { 333 assert(&ND == getDeclForComment(&ND)); 334 // We only add documentation, so don't bother if we already have some. 335 if (!Hover.Documentation.empty() || !Index) 336 return; 337 338 // Skip querying for non-indexable symbols, there's no point. 339 // We're searching for symbols that might be indexed outside this main file. 340 if (!SymbolCollector::shouldCollectSymbol(ND, ND.getASTContext(), 341 SymbolCollector::Options(), 342 /*IsMainFileOnly=*/false)) 343 return; 344 auto ID = getSymbolID(&ND); 345 if (!ID) 346 return; 347 LookupRequest Req; 348 Req.IDs.insert(ID); 349 Index->lookup(Req, [&](const Symbol &S) { 350 Hover.Documentation = std::string(S.Documentation); 351 }); 352 } 353 354 // Default argument might exist but be unavailable, in the case of unparsed 355 // arguments for example. This function returns the default argument if it is 356 // available. 357 const Expr *getDefaultArg(const ParmVarDecl *PVD) { 358 // Default argument can be unparsed or uninstantiated. For the former we 359 // can't do much, as token information is only stored in Sema and not 360 // attached to the AST node. For the latter though, it is safe to proceed as 361 // the expression is still valid. 362 if (!PVD->hasDefaultArg() || PVD->hasUnparsedDefaultArg()) 363 return nullptr; 364 return PVD->hasUninstantiatedDefaultArg() ? PVD->getUninstantiatedDefaultArg() 365 : PVD->getDefaultArg(); 366 } 367 368 HoverInfo::Param toHoverInfoParam(const ParmVarDecl *PVD, 369 const PrintingPolicy &PP) { 370 HoverInfo::Param Out; 371 Out.Type = printType(PVD->getType(), PVD->getASTContext(), PP); 372 if (!PVD->getName().empty()) 373 Out.Name = PVD->getNameAsString(); 374 if (const Expr *DefArg = getDefaultArg(PVD)) { 375 Out.Default.emplace(); 376 llvm::raw_string_ostream OS(*Out.Default); 377 DefArg->printPretty(OS, nullptr, PP); 378 } 379 return Out; 380 } 381 382 // Populates Type, ReturnType, and Parameters for function-like decls. 383 void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D, 384 const FunctionDecl *FD, 385 const PrintingPolicy &PP) { 386 HI.Parameters.emplace(); 387 for (const ParmVarDecl *PVD : FD->parameters()) 388 HI.Parameters->emplace_back(toHoverInfoParam(PVD, PP)); 389 390 // We don't want any type info, if name already contains it. This is true for 391 // constructors/destructors and conversion operators. 392 const auto NK = FD->getDeclName().getNameKind(); 393 if (NK == DeclarationName::CXXConstructorName || 394 NK == DeclarationName::CXXDestructorName || 395 NK == DeclarationName::CXXConversionFunctionName) 396 return; 397 398 HI.ReturnType = printType(FD->getReturnType(), FD->getASTContext(), PP); 399 QualType QT = FD->getType(); 400 if (const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) // Lambdas 401 QT = VD->getType().getDesugaredType(D->getASTContext()); 402 HI.Type = printType(QT, D->getASTContext(), PP); 403 // FIXME: handle variadics. 404 } 405 406 // Non-negative numbers are printed using min digits 407 // 0 => 0x0 408 // 100 => 0x64 409 // Negative numbers are sign-extended to 32/64 bits 410 // -2 => 0xfffffffe 411 // -2^32 => 0xffffffff00000000 412 static llvm::FormattedNumber printHex(const llvm::APSInt &V) { 413 assert(V.getSignificantBits() <= 64 && "Can't print more than 64 bits."); 414 uint64_t Bits = 415 V.getBitWidth() > 64 ? V.trunc(64).getZExtValue() : V.getZExtValue(); 416 if (V.isNegative() && V.getSignificantBits() <= 32) 417 return llvm::format_hex(uint32_t(Bits), 0); 418 return llvm::format_hex(Bits, 0); 419 } 420 421 std::optional<std::string> printExprValue(const Expr *E, 422 const ASTContext &Ctx) { 423 // InitListExpr has two forms, syntactic and semantic. They are the same thing 424 // (refer to a same AST node) in most cases. 425 // When they are different, RAV returns the syntactic form, and we should feed 426 // the semantic form to EvaluateAsRValue. 427 if (const auto *ILE = llvm::dyn_cast<InitListExpr>(E)) { 428 if (!ILE->isSemanticForm()) 429 E = ILE->getSemanticForm(); 430 } 431 432 // Evaluating [[foo]]() as "&foo" isn't useful, and prevents us walking up 433 // to the enclosing call. Evaluating an expression of void type doesn't 434 // produce a meaningful result. 435 QualType T = E->getType(); 436 if (T.isNull() || T->isFunctionType() || T->isFunctionPointerType() || 437 T->isFunctionReferenceType() || T->isVoidType()) 438 return std::nullopt; 439 440 Expr::EvalResult Constant; 441 // Attempt to evaluate. If expr is dependent, evaluation crashes! 442 if (E->isValueDependent() || !E->EvaluateAsRValue(Constant, Ctx) || 443 // Disable printing for record-types, as they are usually confusing and 444 // might make clang crash while printing the expressions. 445 Constant.Val.isStruct() || Constant.Val.isUnion()) 446 return std::nullopt; 447 448 // Show enums symbolically, not numerically like APValue::printPretty(). 449 if (T->isEnumeralType() && Constant.Val.isInt() && 450 Constant.Val.getInt().getSignificantBits() <= 64) { 451 // Compare to int64_t to avoid bit-width match requirements. 452 int64_t Val = Constant.Val.getInt().getExtValue(); 453 for (const EnumConstantDecl *ECD : 454 T->castAs<EnumType>()->getDecl()->enumerators()) 455 if (ECD->getInitVal() == Val) 456 return llvm::formatv("{0} ({1})", ECD->getNameAsString(), 457 printHex(Constant.Val.getInt())) 458 .str(); 459 } 460 // Show hex value of integers if they're at least 10 (or negative!) 461 if (T->isIntegralOrEnumerationType() && Constant.Val.isInt() && 462 Constant.Val.getInt().getSignificantBits() <= 64 && 463 Constant.Val.getInt().uge(10)) 464 return llvm::formatv("{0} ({1})", Constant.Val.getAsString(Ctx, T), 465 printHex(Constant.Val.getInt())) 466 .str(); 467 return Constant.Val.getAsString(Ctx, T); 468 } 469 470 struct PrintExprResult { 471 /// The evaluation result on expression `Expr`. 472 std::optional<std::string> PrintedValue; 473 /// The Expr object that represents the closest evaluable 474 /// expression. 475 const clang::Expr *TheExpr; 476 /// The node of selection tree where the traversal stops. 477 const SelectionTree::Node *TheNode; 478 }; 479 480 // Seek the closest evaluable expression along the ancestors of node N 481 // in a selection tree. If a node in the path can be converted to an evaluable 482 // Expr, a possible evaluation would happen and the associated context 483 // is returned. 484 // If evaluation couldn't be done, return the node where the traversal ends. 485 PrintExprResult printExprValue(const SelectionTree::Node *N, 486 const ASTContext &Ctx) { 487 for (; N; N = N->Parent) { 488 // Try to evaluate the first evaluatable enclosing expression. 489 if (const Expr *E = N->ASTNode.get<Expr>()) { 490 // Once we cross an expression of type 'cv void', the evaluated result 491 // has nothing to do with our original cursor position. 492 if (!E->getType().isNull() && E->getType()->isVoidType()) 493 break; 494 if (auto Val = printExprValue(E, Ctx)) 495 return PrintExprResult{/*PrintedValue=*/std::move(Val), /*Expr=*/E, 496 /*Node=*/N}; 497 } else if (N->ASTNode.get<Decl>() || N->ASTNode.get<Stmt>()) { 498 // Refuse to cross certain non-exprs. (TypeLoc are OK as part of Exprs). 499 // This tries to ensure we're showing a value related to the cursor. 500 break; 501 } 502 } 503 return PrintExprResult{/*PrintedValue=*/std::nullopt, /*Expr=*/nullptr, 504 /*Node=*/N}; 505 } 506 507 std::optional<StringRef> fieldName(const Expr *E) { 508 const auto *ME = llvm::dyn_cast<MemberExpr>(E->IgnoreCasts()); 509 if (!ME || !llvm::isa<CXXThisExpr>(ME->getBase()->IgnoreCasts())) 510 return std::nullopt; 511 const auto *Field = llvm::dyn_cast<FieldDecl>(ME->getMemberDecl()); 512 if (!Field || !Field->getDeclName().isIdentifier()) 513 return std::nullopt; 514 return Field->getDeclName().getAsIdentifierInfo()->getName(); 515 } 516 517 // If CMD is of the form T foo() { return FieldName; } then returns "FieldName". 518 std::optional<StringRef> getterVariableName(const CXXMethodDecl *CMD) { 519 assert(CMD->hasBody()); 520 if (CMD->getNumParams() != 0 || CMD->isVariadic()) 521 return std::nullopt; 522 const auto *Body = llvm::dyn_cast<CompoundStmt>(CMD->getBody()); 523 const auto *OnlyReturn = (Body && Body->size() == 1) 524 ? llvm::dyn_cast<ReturnStmt>(Body->body_front()) 525 : nullptr; 526 if (!OnlyReturn || !OnlyReturn->getRetValue()) 527 return std::nullopt; 528 return fieldName(OnlyReturn->getRetValue()); 529 } 530 531 // If CMD is one of the forms: 532 // void foo(T arg) { FieldName = arg; } 533 // R foo(T arg) { FieldName = arg; return *this; } 534 // void foo(T arg) { FieldName = std::move(arg); } 535 // R foo(T arg) { FieldName = std::move(arg); return *this; } 536 // then returns "FieldName" 537 std::optional<StringRef> setterVariableName(const CXXMethodDecl *CMD) { 538 assert(CMD->hasBody()); 539 if (CMD->isConst() || CMD->getNumParams() != 1 || CMD->isVariadic()) 540 return std::nullopt; 541 const ParmVarDecl *Arg = CMD->getParamDecl(0); 542 if (Arg->isParameterPack()) 543 return std::nullopt; 544 545 const auto *Body = llvm::dyn_cast<CompoundStmt>(CMD->getBody()); 546 if (!Body || Body->size() == 0 || Body->size() > 2) 547 return std::nullopt; 548 // If the second statement exists, it must be `return this` or `return *this`. 549 if (Body->size() == 2) { 550 auto *Ret = llvm::dyn_cast<ReturnStmt>(Body->body_back()); 551 if (!Ret || !Ret->getRetValue()) 552 return std::nullopt; 553 const Expr *RetVal = Ret->getRetValue()->IgnoreCasts(); 554 if (const auto *UO = llvm::dyn_cast<UnaryOperator>(RetVal)) { 555 if (UO->getOpcode() != UO_Deref) 556 return std::nullopt; 557 RetVal = UO->getSubExpr()->IgnoreCasts(); 558 } 559 if (!llvm::isa<CXXThisExpr>(RetVal)) 560 return std::nullopt; 561 } 562 // The first statement must be an assignment of the arg to a field. 563 const Expr *LHS, *RHS; 564 if (const auto *BO = llvm::dyn_cast<BinaryOperator>(Body->body_front())) { 565 if (BO->getOpcode() != BO_Assign) 566 return std::nullopt; 567 LHS = BO->getLHS(); 568 RHS = BO->getRHS(); 569 } else if (const auto *COCE = 570 llvm::dyn_cast<CXXOperatorCallExpr>(Body->body_front())) { 571 if (COCE->getOperator() != OO_Equal || COCE->getNumArgs() != 2) 572 return std::nullopt; 573 LHS = COCE->getArg(0); 574 RHS = COCE->getArg(1); 575 } else { 576 return std::nullopt; 577 } 578 579 // Detect the case when the item is moved into the field. 580 if (auto *CE = llvm::dyn_cast<CallExpr>(RHS->IgnoreCasts())) { 581 if (CE->getNumArgs() != 1) 582 return std::nullopt; 583 auto *ND = llvm::dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl()); 584 if (!ND || !ND->getIdentifier() || ND->getName() != "move" || 585 !ND->isInStdNamespace()) 586 return std::nullopt; 587 RHS = CE->getArg(0); 588 } 589 590 auto *DRE = llvm::dyn_cast<DeclRefExpr>(RHS->IgnoreCasts()); 591 if (!DRE || DRE->getDecl() != Arg) 592 return std::nullopt; 593 return fieldName(LHS); 594 } 595 596 std::string synthesizeDocumentation(const NamedDecl *ND) { 597 if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) { 598 // Is this an ordinary, non-static method whose definition is visible? 599 if (CMD->getDeclName().isIdentifier() && !CMD->isStatic() && 600 (CMD = llvm::dyn_cast_or_null<CXXMethodDecl>(CMD->getDefinition())) && 601 CMD->hasBody()) { 602 if (const auto GetterField = getterVariableName(CMD)) 603 return llvm::formatv("Trivial accessor for `{0}`.", *GetterField); 604 if (const auto SetterField = setterVariableName(CMD)) 605 return llvm::formatv("Trivial setter for `{0}`.", *SetterField); 606 } 607 } 608 return ""; 609 } 610 611 /// Generate a \p Hover object given the declaration \p D. 612 HoverInfo getHoverContents(const NamedDecl *D, const PrintingPolicy &PP, 613 const SymbolIndex *Index, 614 const syntax::TokenBuffer &TB) { 615 HoverInfo HI; 616 auto &Ctx = D->getASTContext(); 617 618 HI.AccessSpecifier = getAccessSpelling(D->getAccess()).str(); 619 HI.NamespaceScope = getNamespaceScope(D); 620 if (!HI.NamespaceScope->empty()) 621 HI.NamespaceScope->append("::"); 622 HI.LocalScope = getLocalScope(D); 623 if (!HI.LocalScope.empty()) 624 HI.LocalScope.append("::"); 625 626 HI.Name = printName(Ctx, *D); 627 const auto *CommentD = getDeclForComment(D); 628 HI.Documentation = getDeclComment(Ctx, *CommentD); 629 enhanceFromIndex(HI, *CommentD, Index); 630 if (HI.Documentation.empty()) 631 HI.Documentation = synthesizeDocumentation(D); 632 633 HI.Kind = index::getSymbolInfo(D).Kind; 634 635 // Fill in template params. 636 if (const TemplateDecl *TD = D->getDescribedTemplate()) { 637 HI.TemplateParameters = 638 fetchTemplateParameters(TD->getTemplateParameters(), PP); 639 D = TD; 640 } else if (const FunctionDecl *FD = D->getAsFunction()) { 641 if (const auto *FTD = FD->getDescribedTemplate()) { 642 HI.TemplateParameters = 643 fetchTemplateParameters(FTD->getTemplateParameters(), PP); 644 D = FTD; 645 } 646 } 647 648 // Fill in types and params. 649 if (const FunctionDecl *FD = getUnderlyingFunction(D)) 650 fillFunctionTypeAndParams(HI, D, FD, PP); 651 else if (const auto *VD = dyn_cast<ValueDecl>(D)) 652 HI.Type = printType(VD->getType(), Ctx, PP); 653 else if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D)) 654 HI.Type = TTP->wasDeclaredWithTypename() ? "typename" : "class"; 655 else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) 656 HI.Type = printType(TTP, PP); 657 else if (const auto *VT = dyn_cast<VarTemplateDecl>(D)) 658 HI.Type = printType(VT->getTemplatedDecl()->getType(), Ctx, PP); 659 else if (const auto *TN = dyn_cast<TypedefNameDecl>(D)) 660 HI.Type = printType(TN->getUnderlyingType().getDesugaredType(Ctx), Ctx, PP); 661 else if (const auto *TAT = dyn_cast<TypeAliasTemplateDecl>(D)) 662 HI.Type = printType(TAT->getTemplatedDecl()->getUnderlyingType(), Ctx, PP); 663 664 // Fill in value with evaluated initializer if possible. 665 if (const auto *Var = dyn_cast<VarDecl>(D); Var && !Var->isInvalidDecl()) { 666 if (const Expr *Init = Var->getInit()) 667 HI.Value = printExprValue(Init, Ctx); 668 } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) { 669 // Dependent enums (e.g. nested in template classes) don't have values yet. 670 if (!ECD->getType()->isDependentType()) 671 HI.Value = toString(ECD->getInitVal(), 10); 672 } 673 674 HI.Definition = printDefinition(D, PP, TB); 675 return HI; 676 } 677 678 /// The standard defines __func__ as a "predefined variable". 679 std::optional<HoverInfo> 680 getPredefinedExprHoverContents(const PredefinedExpr &PE, ASTContext &Ctx, 681 const PrintingPolicy &PP) { 682 HoverInfo HI; 683 HI.Name = PE.getIdentKindName(); 684 HI.Kind = index::SymbolKind::Variable; 685 HI.Documentation = "Name of the current function (predefined variable)"; 686 if (const StringLiteral *Name = PE.getFunctionName()) { 687 HI.Value.emplace(); 688 llvm::raw_string_ostream OS(*HI.Value); 689 Name->outputString(OS); 690 HI.Type = printType(Name->getType(), Ctx, PP); 691 } else { 692 // Inside templates, the approximate type `const char[]` is still useful. 693 QualType StringType = Ctx.getIncompleteArrayType(Ctx.CharTy.withConst(), 694 ArraySizeModifier::Normal, 695 /*IndexTypeQuals=*/0); 696 HI.Type = printType(StringType, Ctx, PP); 697 } 698 return HI; 699 } 700 701 HoverInfo evaluateMacroExpansion(unsigned int SpellingBeginOffset, 702 unsigned int SpellingEndOffset, 703 llvm::ArrayRef<syntax::Token> Expanded, 704 ParsedAST &AST) { 705 auto &Context = AST.getASTContext(); 706 auto &Tokens = AST.getTokens(); 707 auto PP = getPrintingPolicy(Context.getPrintingPolicy()); 708 auto Tree = SelectionTree::createRight(Context, Tokens, SpellingBeginOffset, 709 SpellingEndOffset); 710 711 // If macro expands to one single token, rule out punctuator or digraph. 712 // E.g., for the case `array L_BRACKET 42 R_BRACKET;` where L_BRACKET and 713 // R_BRACKET expand to 714 // '[' and ']' respectively, we don't want the type of 715 // 'array[42]' when user hovers on L_BRACKET. 716 if (Expanded.size() == 1) 717 if (tok::getPunctuatorSpelling(Expanded[0].kind())) 718 return {}; 719 720 auto *StartNode = Tree.commonAncestor(); 721 if (!StartNode) 722 return {}; 723 // If the common ancestor is partially selected, do evaluate if it has no 724 // children, thus we can disallow evaluation on incomplete expression. 725 // For example, 726 // #define PLUS_2 +2 727 // 40 PL^US_2 728 // In this case we don't want to present 'value: 2' as PLUS_2 actually expands 729 // to a non-value rather than a binary operand. 730 if (StartNode->Selected == SelectionTree::Selection::Partial) 731 if (!StartNode->Children.empty()) 732 return {}; 733 734 HoverInfo HI; 735 // Attempt to evaluate it from Expr first. 736 auto ExprResult = printExprValue(StartNode, Context); 737 HI.Value = std::move(ExprResult.PrintedValue); 738 if (auto *E = ExprResult.TheExpr) 739 HI.Type = printType(E->getType(), Context, PP); 740 741 // If failed, extract the type from Decl if possible. 742 if (!HI.Value && !HI.Type && ExprResult.TheNode) 743 if (auto *VD = ExprResult.TheNode->ASTNode.get<VarDecl>()) 744 HI.Type = printType(VD->getType(), Context, PP); 745 746 return HI; 747 } 748 749 /// Generate a \p Hover object given the macro \p MacroDecl. 750 HoverInfo getHoverContents(const DefinedMacro &Macro, const syntax::Token &Tok, 751 ParsedAST &AST) { 752 HoverInfo HI; 753 SourceManager &SM = AST.getSourceManager(); 754 HI.Name = std::string(Macro.Name); 755 HI.Kind = index::SymbolKind::Macro; 756 // FIXME: Populate documentation 757 // FIXME: Populate parameters 758 759 // Try to get the full definition, not just the name 760 SourceLocation StartLoc = Macro.Info->getDefinitionLoc(); 761 SourceLocation EndLoc = Macro.Info->getDefinitionEndLoc(); 762 // Ensure that EndLoc is a valid offset. For example it might come from 763 // preamble, and source file might've changed, in such a scenario EndLoc still 764 // stays valid, but getLocForEndOfToken will fail as it is no longer a valid 765 // offset. 766 // Note that this check is just to ensure there's text data inside the range. 767 // It will still succeed even when the data inside the range is irrelevant to 768 // macro definition. 769 if (SM.getPresumedLoc(EndLoc, /*UseLineDirectives=*/false).isValid()) { 770 EndLoc = Lexer::getLocForEndOfToken(EndLoc, 0, SM, AST.getLangOpts()); 771 bool Invalid; 772 StringRef Buffer = SM.getBufferData(SM.getFileID(StartLoc), &Invalid); 773 if (!Invalid) { 774 unsigned StartOffset = SM.getFileOffset(StartLoc); 775 unsigned EndOffset = SM.getFileOffset(EndLoc); 776 if (EndOffset <= Buffer.size() && StartOffset < EndOffset) 777 HI.Definition = 778 ("#define " + Buffer.substr(StartOffset, EndOffset - StartOffset)) 779 .str(); 780 } 781 } 782 783 if (auto Expansion = AST.getTokens().expansionStartingAt(&Tok)) { 784 // We drop expansion that's longer than the threshold. 785 // For extremely long expansion text, it's not readable from hover card 786 // anyway. 787 std::string ExpansionText; 788 for (const auto &ExpandedTok : Expansion->Expanded) { 789 ExpansionText += ExpandedTok.text(SM); 790 ExpansionText += " "; 791 if (ExpansionText.size() > 2048) { 792 ExpansionText.clear(); 793 break; 794 } 795 } 796 797 if (!ExpansionText.empty()) { 798 if (!HI.Definition.empty()) { 799 HI.Definition += "\n\n"; 800 } 801 HI.Definition += "// Expands to\n"; 802 HI.Definition += ExpansionText; 803 } 804 805 auto Evaluated = evaluateMacroExpansion( 806 /*SpellingBeginOffset=*/SM.getFileOffset(Tok.location()), 807 /*SpellingEndOffset=*/SM.getFileOffset(Tok.endLocation()), 808 /*Expanded=*/Expansion->Expanded, AST); 809 HI.Value = std::move(Evaluated.Value); 810 HI.Type = std::move(Evaluated.Type); 811 } 812 return HI; 813 } 814 815 std::string typeAsDefinition(const HoverInfo::PrintedType &PType) { 816 std::string Result; 817 llvm::raw_string_ostream OS(Result); 818 OS << PType.Type; 819 if (PType.AKA) 820 OS << " // aka: " << *PType.AKA; 821 return Result; 822 } 823 824 std::optional<HoverInfo> getThisExprHoverContents(const CXXThisExpr *CTE, 825 ASTContext &ASTCtx, 826 const PrintingPolicy &PP) { 827 QualType OriginThisType = CTE->getType()->getPointeeType(); 828 QualType ClassType = declaredType(OriginThisType->getAsTagDecl()); 829 // For partial specialization class, origin `this` pointee type will be 830 // parsed as `InjectedClassNameType`, which will ouput template arguments 831 // like "type-parameter-0-0". So we retrieve user written class type in this 832 // case. 833 QualType PrettyThisType = ASTCtx.getPointerType( 834 QualType(ClassType.getTypePtr(), OriginThisType.getCVRQualifiers())); 835 836 HoverInfo HI; 837 HI.Name = "this"; 838 HI.Definition = typeAsDefinition(printType(PrettyThisType, ASTCtx, PP)); 839 return HI; 840 } 841 842 /// Generate a HoverInfo object given the deduced type \p QT 843 HoverInfo getDeducedTypeHoverContents(QualType QT, const syntax::Token &Tok, 844 ASTContext &ASTCtx, 845 const PrintingPolicy &PP, 846 const SymbolIndex *Index) { 847 HoverInfo HI; 848 // FIXME: distinguish decltype(auto) vs decltype(expr) 849 HI.Name = tok::getTokenName(Tok.kind()); 850 HI.Kind = index::SymbolKind::TypeAlias; 851 852 if (QT->isUndeducedAutoType()) { 853 HI.Definition = "/* not deduced */"; 854 } else { 855 HI.Definition = typeAsDefinition(printType(QT, ASTCtx, PP)); 856 857 if (const auto *D = QT->getAsTagDecl()) { 858 const auto *CommentD = getDeclForComment(D); 859 HI.Documentation = getDeclComment(ASTCtx, *CommentD); 860 enhanceFromIndex(HI, *CommentD, Index); 861 } 862 } 863 864 return HI; 865 } 866 867 HoverInfo getStringLiteralContents(const StringLiteral *SL, 868 const PrintingPolicy &PP) { 869 HoverInfo HI; 870 871 HI.Name = "string-literal"; 872 HI.Size = (SL->getLength() + 1) * SL->getCharByteWidth() * 8; 873 HI.Type = SL->getType().getAsString(PP).c_str(); 874 875 return HI; 876 } 877 878 bool isLiteral(const Expr *E) { 879 // Unfortunately there's no common base Literal classes inherits from 880 // (apart from Expr), therefore these exclusions. 881 return llvm::isa<CompoundLiteralExpr>(E) || 882 llvm::isa<CXXBoolLiteralExpr>(E) || 883 llvm::isa<CXXNullPtrLiteralExpr>(E) || 884 llvm::isa<FixedPointLiteral>(E) || llvm::isa<FloatingLiteral>(E) || 885 llvm::isa<ImaginaryLiteral>(E) || llvm::isa<IntegerLiteral>(E) || 886 llvm::isa<StringLiteral>(E) || llvm::isa<UserDefinedLiteral>(E); 887 } 888 889 llvm::StringLiteral getNameForExpr(const Expr *E) { 890 // FIXME: Come up with names for `special` expressions. 891 // 892 // It's an known issue for GCC5, https://godbolt.org/z/Z_tbgi. Work around 893 // that by using explicit conversion constructor. 894 // 895 // TODO: Once GCC5 is fully retired and not the minimal requirement as stated 896 // in `GettingStarted`, please remove the explicit conversion constructor. 897 return llvm::StringLiteral("expression"); 898 } 899 900 void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI, 901 const PrintingPolicy &PP); 902 903 // Generates hover info for `this` and evaluatable expressions. 904 // FIXME: Support hover for literals (esp user-defined) 905 std::optional<HoverInfo> getHoverContents(const SelectionTree::Node *N, 906 const Expr *E, ParsedAST &AST, 907 const PrintingPolicy &PP, 908 const SymbolIndex *Index) { 909 std::optional<HoverInfo> HI; 910 911 if (const StringLiteral *SL = dyn_cast<StringLiteral>(E)) { 912 // Print the type and the size for string literals 913 HI = getStringLiteralContents(SL, PP); 914 } else if (isLiteral(E)) { 915 // There's not much value in hovering over "42" and getting a hover card 916 // saying "42 is an int", similar for most other literals. 917 // However, if we have CalleeArgInfo, it's still useful to show it. 918 maybeAddCalleeArgInfo(N, HI.emplace(), PP); 919 if (HI->CalleeArgInfo) { 920 // FIXME Might want to show the expression's value here instead? 921 // E.g. if the literal is in hex it might be useful to show the decimal 922 // value here. 923 HI->Name = "literal"; 924 return HI; 925 } 926 return std::nullopt; 927 } 928 929 // For `this` expr we currently generate hover with pointee type. 930 if (const CXXThisExpr *CTE = dyn_cast<CXXThisExpr>(E)) 931 HI = getThisExprHoverContents(CTE, AST.getASTContext(), PP); 932 if (const PredefinedExpr *PE = dyn_cast<PredefinedExpr>(E)) 933 HI = getPredefinedExprHoverContents(*PE, AST.getASTContext(), PP); 934 // For expressions we currently print the type and the value, iff it is 935 // evaluatable. 936 if (auto Val = printExprValue(E, AST.getASTContext())) { 937 HI.emplace(); 938 HI->Type = printType(E->getType(), AST.getASTContext(), PP); 939 HI->Value = *Val; 940 HI->Name = std::string(getNameForExpr(E)); 941 } 942 943 if (HI) 944 maybeAddCalleeArgInfo(N, *HI, PP); 945 946 return HI; 947 } 948 949 // Generates hover info for attributes. 950 std::optional<HoverInfo> getHoverContents(const Attr *A, ParsedAST &AST) { 951 HoverInfo HI; 952 HI.Name = A->getSpelling(); 953 if (A->hasScope()) 954 HI.LocalScope = A->getScopeName()->getName().str(); 955 { 956 llvm::raw_string_ostream OS(HI.Definition); 957 A->printPretty(OS, AST.getASTContext().getPrintingPolicy()); 958 } 959 HI.Documentation = Attr::getDocumentation(A->getKind()).str(); 960 return HI; 961 } 962 963 bool isParagraphBreak(llvm::StringRef Rest) { 964 return Rest.ltrim(" \t").starts_with("\n"); 965 } 966 967 bool punctuationIndicatesLineBreak(llvm::StringRef Line) { 968 constexpr llvm::StringLiteral Punctuation = R"txt(.:,;!?)txt"; 969 970 Line = Line.rtrim(); 971 return !Line.empty() && Punctuation.contains(Line.back()); 972 } 973 974 bool isHardLineBreakIndicator(llvm::StringRef Rest) { 975 // '-'/'*' md list, '@'/'\' documentation command, '>' md blockquote, 976 // '#' headings, '`' code blocks 977 constexpr llvm::StringLiteral LinebreakIndicators = R"txt(-*@\>#`)txt"; 978 979 Rest = Rest.ltrim(" \t"); 980 if (Rest.empty()) 981 return false; 982 983 if (LinebreakIndicators.contains(Rest.front())) 984 return true; 985 986 if (llvm::isDigit(Rest.front())) { 987 llvm::StringRef AfterDigit = Rest.drop_while(llvm::isDigit); 988 if (AfterDigit.starts_with(".") || AfterDigit.starts_with(")")) 989 return true; 990 } 991 return false; 992 } 993 994 bool isHardLineBreakAfter(llvm::StringRef Line, llvm::StringRef Rest) { 995 // Should we also consider whether Line is short? 996 return punctuationIndicatesLineBreak(Line) || isHardLineBreakIndicator(Rest); 997 } 998 999 void addLayoutInfo(const NamedDecl &ND, HoverInfo &HI) { 1000 if (ND.isInvalidDecl()) 1001 return; 1002 1003 const auto &Ctx = ND.getASTContext(); 1004 if (auto *RD = llvm::dyn_cast<RecordDecl>(&ND)) { 1005 if (auto Size = Ctx.getTypeSizeInCharsIfKnown(RD->getTypeForDecl())) 1006 HI.Size = Size->getQuantity() * 8; 1007 if (!RD->isDependentType() && RD->isCompleteDefinition()) 1008 HI.Align = Ctx.getTypeAlign(RD->getTypeForDecl()); 1009 return; 1010 } 1011 1012 if (const auto *FD = llvm::dyn_cast<FieldDecl>(&ND)) { 1013 const auto *Record = FD->getParent(); 1014 if (Record) 1015 Record = Record->getDefinition(); 1016 if (Record && !Record->isInvalidDecl() && !Record->isDependentType()) { 1017 HI.Align = Ctx.getTypeAlign(FD->getType()); 1018 const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Record); 1019 HI.Offset = Layout.getFieldOffset(FD->getFieldIndex()); 1020 if (FD->isBitField()) 1021 HI.Size = FD->getBitWidthValue(); 1022 else if (auto Size = Ctx.getTypeSizeInCharsIfKnown(FD->getType())) 1023 HI.Size = FD->isZeroSize(Ctx) ? 0 : Size->getQuantity() * 8; 1024 if (HI.Size) { 1025 unsigned EndOfField = *HI.Offset + *HI.Size; 1026 1027 // Calculate padding following the field. 1028 if (!Record->isUnion() && 1029 FD->getFieldIndex() + 1 < Layout.getFieldCount()) { 1030 // Measure padding up to the next class field. 1031 unsigned NextOffset = Layout.getFieldOffset(FD->getFieldIndex() + 1); 1032 if (NextOffset >= EndOfField) // next field could be a bitfield! 1033 HI.Padding = NextOffset - EndOfField; 1034 } else { 1035 // Measure padding up to the end of the object. 1036 HI.Padding = Layout.getSize().getQuantity() * 8 - EndOfField; 1037 } 1038 } 1039 // Offset in a union is always zero, so not really useful to report. 1040 if (Record->isUnion()) 1041 HI.Offset.reset(); 1042 } 1043 return; 1044 } 1045 } 1046 1047 HoverInfo::PassType::PassMode getPassMode(QualType ParmType) { 1048 if (ParmType->isReferenceType()) { 1049 if (ParmType->getPointeeType().isConstQualified()) 1050 return HoverInfo::PassType::ConstRef; 1051 return HoverInfo::PassType::Ref; 1052 } 1053 return HoverInfo::PassType::Value; 1054 } 1055 1056 // If N is passed as argument to a function, fill HI.CalleeArgInfo with 1057 // information about that argument. 1058 void maybeAddCalleeArgInfo(const SelectionTree::Node *N, HoverInfo &HI, 1059 const PrintingPolicy &PP) { 1060 const auto &OuterNode = N->outerImplicit(); 1061 if (!OuterNode.Parent) 1062 return; 1063 1064 const FunctionDecl *FD = nullptr; 1065 llvm::ArrayRef<const Expr *> Args; 1066 1067 if (const auto *CE = OuterNode.Parent->ASTNode.get<CallExpr>()) { 1068 FD = CE->getDirectCallee(); 1069 Args = {CE->getArgs(), CE->getNumArgs()}; 1070 } else if (const auto *CE = 1071 OuterNode.Parent->ASTNode.get<CXXConstructExpr>()) { 1072 FD = CE->getConstructor(); 1073 Args = {CE->getArgs(), CE->getNumArgs()}; 1074 } 1075 if (!FD) 1076 return; 1077 1078 // For non-function-call-like operators (e.g. operator+, operator<<) it's 1079 // not immediately obvious what the "passed as" would refer to and, given 1080 // fixed function signature, the value would be very low anyway, so we choose 1081 // to not support that. 1082 // Both variadic functions and operator() (especially relevant for lambdas) 1083 // should be supported in the future. 1084 if (!FD || FD->isOverloadedOperator() || FD->isVariadic()) 1085 return; 1086 1087 HoverInfo::PassType PassType; 1088 1089 auto Parameters = resolveForwardingParameters(FD); 1090 1091 // Find argument index for N. 1092 for (unsigned I = 0; I < Args.size() && I < Parameters.size(); ++I) { 1093 if (Args[I] != OuterNode.ASTNode.get<Expr>()) 1094 continue; 1095 1096 // Extract matching argument from function declaration. 1097 if (const ParmVarDecl *PVD = Parameters[I]) { 1098 HI.CalleeArgInfo.emplace(toHoverInfoParam(PVD, PP)); 1099 if (N == &OuterNode) 1100 PassType.PassBy = getPassMode(PVD->getType()); 1101 } 1102 break; 1103 } 1104 if (!HI.CalleeArgInfo) 1105 return; 1106 1107 // If we found a matching argument, also figure out if it's a 1108 // [const-]reference. For this we need to walk up the AST from the arg itself 1109 // to CallExpr and check all implicit casts, constructor calls, etc. 1110 if (const auto *E = N->ASTNode.get<Expr>()) { 1111 if (E->getType().isConstQualified()) 1112 PassType.PassBy = HoverInfo::PassType::ConstRef; 1113 } 1114 1115 for (auto *CastNode = N->Parent; 1116 CastNode != OuterNode.Parent && !PassType.Converted; 1117 CastNode = CastNode->Parent) { 1118 if (const auto *ImplicitCast = CastNode->ASTNode.get<ImplicitCastExpr>()) { 1119 switch (ImplicitCast->getCastKind()) { 1120 case CK_NoOp: 1121 case CK_DerivedToBase: 1122 case CK_UncheckedDerivedToBase: 1123 // If it was a reference before, it's still a reference. 1124 if (PassType.PassBy != HoverInfo::PassType::Value) 1125 PassType.PassBy = ImplicitCast->getType().isConstQualified() 1126 ? HoverInfo::PassType::ConstRef 1127 : HoverInfo::PassType::Ref; 1128 break; 1129 case CK_LValueToRValue: 1130 case CK_ArrayToPointerDecay: 1131 case CK_FunctionToPointerDecay: 1132 case CK_NullToPointer: 1133 case CK_NullToMemberPointer: 1134 // No longer a reference, but we do not show this as type conversion. 1135 PassType.PassBy = HoverInfo::PassType::Value; 1136 break; 1137 default: 1138 PassType.PassBy = HoverInfo::PassType::Value; 1139 PassType.Converted = true; 1140 break; 1141 } 1142 } else if (const auto *CtorCall = 1143 CastNode->ASTNode.get<CXXConstructExpr>()) { 1144 // We want to be smart about copy constructors. They should not show up as 1145 // type conversion, but instead as passing by value. 1146 if (CtorCall->getConstructor()->isCopyConstructor()) 1147 PassType.PassBy = HoverInfo::PassType::Value; 1148 else 1149 PassType.Converted = true; 1150 } else if (CastNode->ASTNode.get<MaterializeTemporaryExpr>()) { 1151 // Can't bind a non-const-ref to a temporary, so has to be const-ref 1152 PassType.PassBy = HoverInfo::PassType::ConstRef; 1153 } else { // Unknown implicit node, assume type conversion. 1154 PassType.PassBy = HoverInfo::PassType::Value; 1155 PassType.Converted = true; 1156 } 1157 } 1158 1159 HI.CallPassType.emplace(PassType); 1160 } 1161 1162 const NamedDecl *pickDeclToUse(llvm::ArrayRef<const NamedDecl *> Candidates) { 1163 if (Candidates.empty()) 1164 return nullptr; 1165 1166 // This is e.g the case for 1167 // namespace ns { void foo(); } 1168 // void bar() { using ns::foo; f^oo(); } 1169 // One declaration in Candidates will refer to the using declaration, 1170 // which isn't really useful for Hover. So use the other one, 1171 // which in this example would be the actual declaration of foo. 1172 if (Candidates.size() <= 2) { 1173 if (llvm::isa<UsingDecl>(Candidates.front())) 1174 return Candidates.back(); 1175 return Candidates.front(); 1176 } 1177 1178 // For something like 1179 // namespace ns { void foo(int); void foo(char); } 1180 // using ns::foo; 1181 // template <typename T> void bar() { fo^o(T{}); } 1182 // we actually want to show the using declaration, 1183 // it's not clear which declaration to pick otherwise. 1184 auto BaseDecls = llvm::make_filter_range( 1185 Candidates, [](const NamedDecl *D) { return llvm::isa<UsingDecl>(D); }); 1186 if (std::distance(BaseDecls.begin(), BaseDecls.end()) == 1) 1187 return *BaseDecls.begin(); 1188 1189 return Candidates.front(); 1190 } 1191 1192 void maybeAddSymbolProviders(ParsedAST &AST, HoverInfo &HI, 1193 include_cleaner::Symbol Sym) { 1194 trace::Span Tracer("Hover::maybeAddSymbolProviders"); 1195 1196 llvm::SmallVector<include_cleaner::Header> RankedProviders = 1197 include_cleaner::headersForSymbol(Sym, AST.getPreprocessor(), 1198 &AST.getPragmaIncludes()); 1199 if (RankedProviders.empty()) 1200 return; 1201 1202 const SourceManager &SM = AST.getSourceManager(); 1203 std::string Result; 1204 include_cleaner::Includes ConvertedIncludes = convertIncludes(AST); 1205 for (const auto &P : RankedProviders) { 1206 if (P.kind() == include_cleaner::Header::Physical && 1207 P.physical() == SM.getFileEntryForID(SM.getMainFileID())) 1208 // Main file ranked higher than any #include'd file 1209 break; 1210 1211 // Pick the best-ranked #include'd provider 1212 auto Matches = ConvertedIncludes.match(P); 1213 if (!Matches.empty()) { 1214 Result = Matches[0]->quote(); 1215 break; 1216 } 1217 } 1218 1219 if (!Result.empty()) { 1220 HI.Provider = std::move(Result); 1221 return; 1222 } 1223 1224 // Pick the best-ranked non-#include'd provider 1225 const auto &H = RankedProviders.front(); 1226 if (H.kind() == include_cleaner::Header::Physical && 1227 H.physical() == SM.getFileEntryForID(SM.getMainFileID())) 1228 // Do not show main file as provider, otherwise we'll show provider info 1229 // on local variables, etc. 1230 return; 1231 1232 HI.Provider = include_cleaner::spellHeader( 1233 {H, AST.getPreprocessor().getHeaderSearchInfo(), 1234 SM.getFileEntryForID(SM.getMainFileID())}); 1235 } 1236 1237 // FIXME: similar functions are present in FindHeaders.cpp (symbolName) 1238 // and IncludeCleaner.cpp (getSymbolName). Introduce a name() method into 1239 // include_cleaner::Symbol instead. 1240 std::string getSymbolName(include_cleaner::Symbol Sym) { 1241 std::string Name; 1242 switch (Sym.kind()) { 1243 case include_cleaner::Symbol::Declaration: 1244 if (const auto *ND = llvm::dyn_cast<NamedDecl>(&Sym.declaration())) 1245 Name = ND->getDeclName().getAsString(); 1246 break; 1247 case include_cleaner::Symbol::Macro: 1248 Name = Sym.macro().Name->getName(); 1249 break; 1250 } 1251 return Name; 1252 } 1253 1254 void maybeAddUsedSymbols(ParsedAST &AST, HoverInfo &HI, const Inclusion &Inc) { 1255 auto Converted = convertIncludes(AST); 1256 llvm::DenseSet<include_cleaner::Symbol> UsedSymbols; 1257 include_cleaner::walkUsed( 1258 AST.getLocalTopLevelDecls(), collectMacroReferences(AST), 1259 &AST.getPragmaIncludes(), AST.getPreprocessor(), 1260 [&](const include_cleaner::SymbolReference &Ref, 1261 llvm::ArrayRef<include_cleaner::Header> Providers) { 1262 if (Ref.RT != include_cleaner::RefType::Explicit || 1263 UsedSymbols.contains(Ref.Target)) 1264 return; 1265 1266 if (isPreferredProvider(Inc, Converted, Providers)) 1267 UsedSymbols.insert(Ref.Target); 1268 }); 1269 1270 for (const auto &UsedSymbolDecl : UsedSymbols) 1271 HI.UsedSymbolNames.push_back(getSymbolName(UsedSymbolDecl)); 1272 llvm::sort(HI.UsedSymbolNames); 1273 HI.UsedSymbolNames.erase( 1274 std::unique(HI.UsedSymbolNames.begin(), HI.UsedSymbolNames.end()), 1275 HI.UsedSymbolNames.end()); 1276 } 1277 1278 } // namespace 1279 1280 std::optional<HoverInfo> getHover(ParsedAST &AST, Position Pos, 1281 const format::FormatStyle &Style, 1282 const SymbolIndex *Index) { 1283 static constexpr trace::Metric HoverCountMetric( 1284 "hover", trace::Metric::Counter, "case"); 1285 PrintingPolicy PP = 1286 getPrintingPolicy(AST.getASTContext().getPrintingPolicy()); 1287 const SourceManager &SM = AST.getSourceManager(); 1288 auto CurLoc = sourceLocationInMainFile(SM, Pos); 1289 if (!CurLoc) { 1290 llvm::consumeError(CurLoc.takeError()); 1291 return std::nullopt; 1292 } 1293 const auto &TB = AST.getTokens(); 1294 auto TokensTouchingCursor = syntax::spelledTokensTouching(*CurLoc, TB); 1295 // Early exit if there were no tokens around the cursor. 1296 if (TokensTouchingCursor.empty()) 1297 return std::nullopt; 1298 1299 // Show full header file path if cursor is on include directive. 1300 for (const auto &Inc : AST.getIncludeStructure().MainFileIncludes) { 1301 if (Inc.Resolved.empty() || Inc.HashLine != Pos.line) 1302 continue; 1303 HoverCountMetric.record(1, "include"); 1304 HoverInfo HI; 1305 HI.Name = std::string(llvm::sys::path::filename(Inc.Resolved)); 1306 // FIXME: We don't have a fitting value for Kind. 1307 HI.Definition = 1308 URIForFile::canonicalize(Inc.Resolved, AST.tuPath()).file().str(); 1309 HI.DefinitionLanguage = ""; 1310 maybeAddUsedSymbols(AST, HI, Inc); 1311 return HI; 1312 } 1313 1314 // To be used as a backup for highlighting the selected token, we use back as 1315 // it aligns better with biases elsewhere (editors tend to send the position 1316 // for the left of the hovered token). 1317 CharSourceRange HighlightRange = 1318 TokensTouchingCursor.back().range(SM).toCharRange(SM); 1319 std::optional<HoverInfo> HI; 1320 // Macros and deducedtype only works on identifiers and auto/decltype keywords 1321 // respectively. Therefore they are only trggered on whichever works for them, 1322 // similar to SelectionTree::create(). 1323 for (const auto &Tok : TokensTouchingCursor) { 1324 if (Tok.kind() == tok::identifier) { 1325 // Prefer the identifier token as a fallback highlighting range. 1326 HighlightRange = Tok.range(SM).toCharRange(SM); 1327 if (auto M = locateMacroAt(Tok, AST.getPreprocessor())) { 1328 HoverCountMetric.record(1, "macro"); 1329 HI = getHoverContents(*M, Tok, AST); 1330 if (auto DefLoc = M->Info->getDefinitionLoc(); DefLoc.isValid()) { 1331 include_cleaner::Macro IncludeCleanerMacro{ 1332 AST.getPreprocessor().getIdentifierInfo(Tok.text(SM)), DefLoc}; 1333 maybeAddSymbolProviders(AST, *HI, 1334 include_cleaner::Symbol{IncludeCleanerMacro}); 1335 } 1336 break; 1337 } 1338 } else if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) { 1339 HoverCountMetric.record(1, "keyword"); 1340 if (auto Deduced = getDeducedType(AST.getASTContext(), Tok.location())) { 1341 HI = getDeducedTypeHoverContents(*Deduced, Tok, AST.getASTContext(), PP, 1342 Index); 1343 HighlightRange = Tok.range(SM).toCharRange(SM); 1344 break; 1345 } 1346 1347 // If we can't find interesting hover information for this 1348 // auto/decltype keyword, return nothing to avoid showing 1349 // irrelevant or incorrect informations. 1350 return std::nullopt; 1351 } 1352 } 1353 1354 // If it wasn't auto/decltype or macro, look for decls and expressions. 1355 if (!HI) { 1356 auto Offset = SM.getFileOffset(*CurLoc); 1357 // Editors send the position on the left of the hovered character. 1358 // So our selection tree should be biased right. (Tested with VSCode). 1359 SelectionTree ST = 1360 SelectionTree::createRight(AST.getASTContext(), TB, Offset, Offset); 1361 if (const SelectionTree::Node *N = ST.commonAncestor()) { 1362 // FIXME: Fill in HighlightRange with range coming from N->ASTNode. 1363 auto Decls = explicitReferenceTargets(N->ASTNode, DeclRelation::Alias, 1364 AST.getHeuristicResolver()); 1365 if (const auto *DeclToUse = pickDeclToUse(Decls)) { 1366 HoverCountMetric.record(1, "decl"); 1367 HI = getHoverContents(DeclToUse, PP, Index, TB); 1368 // Layout info only shown when hovering on the field/class itself. 1369 if (DeclToUse == N->ASTNode.get<Decl>()) 1370 addLayoutInfo(*DeclToUse, *HI); 1371 // Look for a close enclosing expression to show the value of. 1372 if (!HI->Value) 1373 HI->Value = printExprValue(N, AST.getASTContext()).PrintedValue; 1374 maybeAddCalleeArgInfo(N, *HI, PP); 1375 1376 if (!isa<NamespaceDecl>(DeclToUse)) 1377 maybeAddSymbolProviders(AST, *HI, 1378 include_cleaner::Symbol{*DeclToUse}); 1379 } else if (const Expr *E = N->ASTNode.get<Expr>()) { 1380 HoverCountMetric.record(1, "expr"); 1381 HI = getHoverContents(N, E, AST, PP, Index); 1382 } else if (const Attr *A = N->ASTNode.get<Attr>()) { 1383 HoverCountMetric.record(1, "attribute"); 1384 HI = getHoverContents(A, AST); 1385 } 1386 // FIXME: support hovers for other nodes? 1387 // - built-in types 1388 } 1389 } 1390 1391 if (!HI) 1392 return std::nullopt; 1393 1394 // Reformat Definition 1395 if (!HI->Definition.empty()) { 1396 auto Replacements = format::reformat( 1397 Style, HI->Definition, tooling::Range(0, HI->Definition.size())); 1398 if (auto Formatted = 1399 tooling::applyAllReplacements(HI->Definition, Replacements)) 1400 HI->Definition = *Formatted; 1401 } 1402 1403 HI->DefinitionLanguage = getMarkdownLanguage(AST.getASTContext()); 1404 HI->SymRange = halfOpenToRange(SM, HighlightRange); 1405 1406 return HI; 1407 } 1408 1409 // Sizes (and padding) are shown in bytes if possible, otherwise in bits. 1410 static std::string formatSize(uint64_t SizeInBits) { 1411 uint64_t Value = SizeInBits % 8 == 0 ? SizeInBits / 8 : SizeInBits; 1412 const char *Unit = Value != 0 && Value == SizeInBits ? "bit" : "byte"; 1413 return llvm::formatv("{0} {1}{2}", Value, Unit, Value == 1 ? "" : "s").str(); 1414 } 1415 1416 // Offsets are shown in bytes + bits, so offsets of different fields 1417 // can always be easily compared. 1418 static std::string formatOffset(uint64_t OffsetInBits) { 1419 const auto Bytes = OffsetInBits / 8; 1420 const auto Bits = OffsetInBits % 8; 1421 auto Offset = formatSize(Bytes * 8); 1422 if (Bits != 0) 1423 Offset += " and " + formatSize(Bits); 1424 return Offset; 1425 } 1426 1427 markup::Document HoverInfo::present() const { 1428 markup::Document Output; 1429 1430 // Header contains a text of the form: 1431 // variable `var` 1432 // 1433 // class `X` 1434 // 1435 // function `foo` 1436 // 1437 // expression 1438 // 1439 // Note that we are making use of a level-3 heading because VSCode renders 1440 // level 1 and 2 headers in a huge font, see 1441 // https://github.com/microsoft/vscode/issues/88417 for details. 1442 markup::Paragraph &Header = Output.addHeading(3); 1443 if (Kind != index::SymbolKind::Unknown) 1444 Header.appendText(index::getSymbolKindString(Kind)).appendSpace(); 1445 assert(!Name.empty() && "hover triggered on a nameless symbol"); 1446 Header.appendCode(Name); 1447 1448 if (!Provider.empty()) { 1449 markup::Paragraph &DI = Output.addParagraph(); 1450 DI.appendText("provided by"); 1451 DI.appendSpace(); 1452 DI.appendCode(Provider); 1453 Output.addRuler(); 1454 } 1455 1456 // Put a linebreak after header to increase readability. 1457 Output.addRuler(); 1458 // Print Types on their own lines to reduce chances of getting line-wrapped by 1459 // editor, as they might be long. 1460 if (ReturnType) { 1461 // For functions we display signature in a list form, e.g.: 1462 // → `x` 1463 // Parameters: 1464 // - `bool param1` 1465 // - `int param2 = 5` 1466 Output.addParagraph().appendText("→ ").appendCode( 1467 llvm::to_string(*ReturnType)); 1468 } 1469 1470 if (Parameters && !Parameters->empty()) { 1471 Output.addParagraph().appendText("Parameters: "); 1472 markup::BulletList &L = Output.addBulletList(); 1473 for (const auto &Param : *Parameters) 1474 L.addItem().addParagraph().appendCode(llvm::to_string(Param)); 1475 } 1476 1477 // Don't print Type after Parameters or ReturnType as this will just duplicate 1478 // the information 1479 if (Type && !ReturnType && !Parameters) 1480 Output.addParagraph().appendText("Type: ").appendCode( 1481 llvm::to_string(*Type)); 1482 1483 if (Value) { 1484 markup::Paragraph &P = Output.addParagraph(); 1485 P.appendText("Value = "); 1486 P.appendCode(*Value); 1487 } 1488 1489 if (Offset) 1490 Output.addParagraph().appendText("Offset: " + formatOffset(*Offset)); 1491 if (Size) { 1492 auto &P = Output.addParagraph().appendText("Size: " + formatSize(*Size)); 1493 if (Padding && *Padding != 0) { 1494 P.appendText( 1495 llvm::formatv(" (+{0} padding)", formatSize(*Padding)).str()); 1496 } 1497 if (Align) 1498 P.appendText(", alignment " + formatSize(*Align)); 1499 } 1500 1501 if (CalleeArgInfo) { 1502 assert(CallPassType); 1503 std::string Buffer; 1504 llvm::raw_string_ostream OS(Buffer); 1505 OS << "Passed "; 1506 if (CallPassType->PassBy != HoverInfo::PassType::Value) { 1507 OS << "by "; 1508 if (CallPassType->PassBy == HoverInfo::PassType::ConstRef) 1509 OS << "const "; 1510 OS << "reference "; 1511 } 1512 if (CalleeArgInfo->Name) 1513 OS << "as " << CalleeArgInfo->Name; 1514 else if (CallPassType->PassBy == HoverInfo::PassType::Value) 1515 OS << "by value"; 1516 if (CallPassType->Converted && CalleeArgInfo->Type) 1517 OS << " (converted to " << CalleeArgInfo->Type->Type << ")"; 1518 Output.addParagraph().appendText(OS.str()); 1519 } 1520 1521 if (!Documentation.empty()) 1522 parseDocumentation(Documentation, Output); 1523 1524 if (!Definition.empty()) { 1525 Output.addRuler(); 1526 std::string Buffer; 1527 1528 if (!Definition.empty()) { 1529 // Append scope comment, dropping trailing "::". 1530 // Note that we don't print anything for global namespace, to not annoy 1531 // non-c++ projects or projects that are not making use of namespaces. 1532 if (!LocalScope.empty()) { 1533 // Container name, e.g. class, method, function. 1534 // We might want to propagate some info about container type to print 1535 // function foo, class X, method X::bar, etc. 1536 Buffer += 1537 "// In " + llvm::StringRef(LocalScope).rtrim(':').str() + '\n'; 1538 } else if (NamespaceScope && !NamespaceScope->empty()) { 1539 Buffer += "// In namespace " + 1540 llvm::StringRef(*NamespaceScope).rtrim(':').str() + '\n'; 1541 } 1542 1543 if (!AccessSpecifier.empty()) { 1544 Buffer += AccessSpecifier + ": "; 1545 } 1546 1547 Buffer += Definition; 1548 } 1549 1550 Output.addCodeBlock(Buffer, DefinitionLanguage); 1551 } 1552 1553 if (!UsedSymbolNames.empty()) { 1554 Output.addRuler(); 1555 markup::Paragraph &P = Output.addParagraph(); 1556 P.appendText("provides "); 1557 1558 const std::vector<std::string>::size_type SymbolNamesLimit = 5; 1559 auto Front = llvm::ArrayRef(UsedSymbolNames).take_front(SymbolNamesLimit); 1560 1561 llvm::interleave( 1562 Front, [&](llvm::StringRef Sym) { P.appendCode(Sym); }, 1563 [&] { P.appendText(", "); }); 1564 if (UsedSymbolNames.size() > Front.size()) { 1565 P.appendText(" and "); 1566 P.appendText(std::to_string(UsedSymbolNames.size() - Front.size())); 1567 P.appendText(" more"); 1568 } 1569 } 1570 1571 return Output; 1572 } 1573 1574 // If the backtick at `Offset` starts a probable quoted range, return the range 1575 // (including the quotes). 1576 std::optional<llvm::StringRef> getBacktickQuoteRange(llvm::StringRef Line, 1577 unsigned Offset) { 1578 assert(Line[Offset] == '`'); 1579 1580 // The open-quote is usually preceded by whitespace. 1581 llvm::StringRef Prefix = Line.substr(0, Offset); 1582 constexpr llvm::StringLiteral BeforeStartChars = " \t(="; 1583 if (!Prefix.empty() && !BeforeStartChars.contains(Prefix.back())) 1584 return std::nullopt; 1585 1586 // The quoted string must be nonempty and usually has no leading/trailing ws. 1587 auto Next = Line.find('`', Offset + 1); 1588 if (Next == llvm::StringRef::npos) 1589 return std::nullopt; 1590 llvm::StringRef Contents = Line.slice(Offset + 1, Next); 1591 if (Contents.empty() || isWhitespace(Contents.front()) || 1592 isWhitespace(Contents.back())) 1593 return std::nullopt; 1594 1595 // The close-quote is usually followed by whitespace or punctuation. 1596 llvm::StringRef Suffix = Line.substr(Next + 1); 1597 constexpr llvm::StringLiteral AfterEndChars = " \t)=.,;:"; 1598 if (!Suffix.empty() && !AfterEndChars.contains(Suffix.front())) 1599 return std::nullopt; 1600 1601 return Line.slice(Offset, Next + 1); 1602 } 1603 1604 void parseDocumentationLine(llvm::StringRef Line, markup::Paragraph &Out) { 1605 // Probably this is appendText(Line), but scan for something interesting. 1606 for (unsigned I = 0; I < Line.size(); ++I) { 1607 switch (Line[I]) { 1608 case '`': 1609 if (auto Range = getBacktickQuoteRange(Line, I)) { 1610 Out.appendText(Line.substr(0, I)); 1611 Out.appendCode(Range->trim("`"), /*Preserve=*/true); 1612 return parseDocumentationLine(Line.substr(I + Range->size()), Out); 1613 } 1614 break; 1615 } 1616 } 1617 Out.appendText(Line).appendSpace(); 1618 } 1619 1620 void parseDocumentation(llvm::StringRef Input, markup::Document &Output) { 1621 std::vector<llvm::StringRef> ParagraphLines; 1622 auto FlushParagraph = [&] { 1623 if (ParagraphLines.empty()) 1624 return; 1625 auto &P = Output.addParagraph(); 1626 for (llvm::StringRef Line : ParagraphLines) 1627 parseDocumentationLine(Line, P); 1628 ParagraphLines.clear(); 1629 }; 1630 1631 llvm::StringRef Line, Rest; 1632 for (std::tie(Line, Rest) = Input.split('\n'); 1633 !(Line.empty() && Rest.empty()); 1634 std::tie(Line, Rest) = Rest.split('\n')) { 1635 1636 // After a linebreak remove spaces to avoid 4 space markdown code blocks. 1637 // FIXME: make FlushParagraph handle this. 1638 Line = Line.ltrim(); 1639 if (!Line.empty()) 1640 ParagraphLines.push_back(Line); 1641 1642 if (isParagraphBreak(Rest) || isHardLineBreakAfter(Line, Rest)) { 1643 FlushParagraph(); 1644 } 1645 } 1646 FlushParagraph(); 1647 } 1648 1649 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 1650 const HoverInfo::PrintedType &T) { 1651 OS << T.Type; 1652 if (T.AKA) 1653 OS << " (aka " << *T.AKA << ")"; 1654 return OS; 1655 } 1656 1657 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 1658 const HoverInfo::Param &P) { 1659 if (P.Type) 1660 OS << P.Type->Type; 1661 if (P.Name) 1662 OS << " " << *P.Name; 1663 if (P.Default) 1664 OS << " = " << *P.Default; 1665 if (P.Type && P.Type->AKA) 1666 OS << " (aka " << *P.Type->AKA << ")"; 1667 return OS; 1668 } 1669 1670 } // namespace clangd 1671 } // namespace clang 1672