brintos

brintos / llvm-project-archived public Read only

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