brintos

brintos / llvm-project-archived public Read only

0
0
Text · 96.2 KiB · ef45acf Raw
2514 lines · cpp
1//===--- XRefs.cpp -----------------------------------------------*- C++-*-===//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#include "XRefs.h"9#include "AST.h"10#include "FindSymbols.h"11#include "FindTarget.h"12#include "Headers.h"13#include "IncludeCleaner.h"14#include "ParsedAST.h"15#include "Protocol.h"16#include "Quality.h"17#include "Selection.h"18#include "SourceCode.h"19#include "URI.h"20#include "clang-include-cleaner/Analysis.h"21#include "clang-include-cleaner/Types.h"22#include "index/Index.h"23#include "index/Merge.h"24#include "index/Ref.h"25#include "index/Relation.h"26#include "index/SymbolCollector.h"27#include "index/SymbolID.h"28#include "index/SymbolLocation.h"29#include "support/Logger.h"30#include "clang/AST/ASTContext.h"31#include "clang/AST/ASTTypeTraits.h"32#include "clang/AST/Attr.h"33#include "clang/AST/Attrs.inc"34#include "clang/AST/Decl.h"35#include "clang/AST/DeclCXX.h"36#include "clang/AST/DeclObjC.h"37#include "clang/AST/DeclTemplate.h"38#include "clang/AST/DeclVisitor.h"39#include "clang/AST/ExprCXX.h"40#include "clang/AST/RecursiveASTVisitor.h"41#include "clang/AST/Stmt.h"42#include "clang/AST/StmtCXX.h"43#include "clang/AST/StmtVisitor.h"44#include "clang/AST/Type.h"45#include "clang/Basic/LLVM.h"46#include "clang/Basic/LangOptions.h"47#include "clang/Basic/SourceLocation.h"48#include "clang/Basic/SourceManager.h"49#include "clang/Basic/TokenKinds.h"50#include "clang/Index/IndexDataConsumer.h"51#include "clang/Index/IndexSymbol.h"52#include "clang/Index/IndexingAction.h"53#include "clang/Index/IndexingOptions.h"54#include "clang/Index/USRGeneration.h"55#include "clang/Lex/Lexer.h"56#include "clang/Sema/HeuristicResolver.h"57#include "clang/Tooling/Syntax/Tokens.h"58#include "llvm/ADT/ArrayRef.h"59#include "llvm/ADT/DenseMap.h"60#include "llvm/ADT/DenseSet.h"61#include "llvm/ADT/STLExtras.h"62#include "llvm/ADT/ScopeExit.h"63#include "llvm/ADT/SmallSet.h"64#include "llvm/ADT/SmallVector.h"65#include "llvm/ADT/StringRef.h"66#include "llvm/Support/Casting.h"67#include "llvm/Support/Error.h"68#include "llvm/Support/ErrorHandling.h"69#include "llvm/Support/Path.h"70#include "llvm/Support/raw_ostream.h"71#include <algorithm>72#include <optional>73#include <string>74#include <vector>75 76namespace clang {77namespace clangd {78namespace {79 80// Returns the single definition of the entity declared by D, if visible.81// In particular:82// - for non-redeclarable kinds (e.g. local vars), return D83// - for kinds that allow multiple definitions (e.g. namespaces), return nullptr84// Kinds of nodes that always return nullptr here will not have definitions85// reported by locateSymbolAt().86const NamedDecl *getDefinition(const NamedDecl *D) {87  assert(D);88  // Decl has one definition that we can find.89  if (const auto *TD = dyn_cast<TagDecl>(D))90    return TD->getDefinition();91  if (const auto *VD = dyn_cast<VarDecl>(D))92    return VD->getDefinition();93  if (const auto *FD = dyn_cast<FunctionDecl>(D))94    return FD->getDefinition();95  if (const auto *CTD = dyn_cast<ClassTemplateDecl>(D))96    if (const auto *RD = CTD->getTemplatedDecl())97      return RD->getDefinition();98  if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {99    if (MD->isThisDeclarationADefinition())100      return MD;101    // Look for the method definition inside the implementation decl.102    auto *DeclCtx = cast<Decl>(MD->getDeclContext());103    if (DeclCtx->isInvalidDecl())104      return nullptr;105 106    if (const auto *CD = dyn_cast<ObjCContainerDecl>(DeclCtx))107      if (const auto *Impl = getCorrespondingObjCImpl(CD))108        return Impl->getMethod(MD->getSelector(), MD->isInstanceMethod());109  }110  if (const auto *CD = dyn_cast<ObjCContainerDecl>(D))111    return getCorrespondingObjCImpl(CD);112  // Only a single declaration is allowed.113  if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||114      isa<TemplateTemplateParmDecl>(D)) // except cases above115    return D;116  // Multiple definitions are allowed.117  return nullptr; // except cases above118}119 120void logIfOverflow(const SymbolLocation &Loc) {121  if (Loc.Start.hasOverflow() || Loc.End.hasOverflow())122    log("Possible overflow in symbol location: {0}", Loc);123}124 125// Convert a SymbolLocation to LSP's Location.126// TUPath is used to resolve the path of URI.127std::optional<Location> toLSPLocation(const SymbolLocation &Loc,128                                      llvm::StringRef TUPath) {129  if (!Loc)130    return std::nullopt;131  auto LSPLoc = indexToLSPLocation(Loc, TUPath);132  if (!LSPLoc) {133    elog("{0}", LSPLoc.takeError());134    return std::nullopt;135  }136  logIfOverflow(Loc);137  return *LSPLoc;138}139 140SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {141  SymbolLocation SymLoc;142  URIStorage = Loc.uri.uri();143  SymLoc.FileURI = URIStorage.c_str();144  SymLoc.Start.setLine(Loc.range.start.line);145  SymLoc.Start.setColumn(Loc.range.start.character);146  SymLoc.End.setLine(Loc.range.end.line);147  SymLoc.End.setColumn(Loc.range.end.character);148  return SymLoc;149}150 151// Returns the preferred location between an AST location and an index location.152SymbolLocation getPreferredLocation(const Location &ASTLoc,153                                    const SymbolLocation &IdxLoc,154                                    std::string &Scratch) {155  // Also use a mock symbol for the index location so that other fields (e.g.156  // definition) are not factored into the preference.157  Symbol ASTSym, IdxSym;158  ASTSym.ID = IdxSym.ID = SymbolID("mock_symbol_id");159  ASTSym.CanonicalDeclaration = toIndexLocation(ASTLoc, Scratch);160  IdxSym.CanonicalDeclaration = IdxLoc;161  auto Merged = mergeSymbol(ASTSym, IdxSym);162  return Merged.CanonicalDeclaration;163}164 165std::vector<std::pair<const NamedDecl *, DeclRelationSet>>166getDeclAtPositionWithRelations(ParsedAST &AST, SourceLocation Pos,167                               DeclRelationSet Relations,168                               ASTNodeKind *NodeKind = nullptr) {169  unsigned Offset = AST.getSourceManager().getDecomposedSpellingLoc(Pos).second;170  std::vector<std::pair<const NamedDecl *, DeclRelationSet>> Result;171  auto ResultFromTree = [&](SelectionTree ST) {172    if (const SelectionTree::Node *N = ST.commonAncestor()) {173      if (NodeKind)174        *NodeKind = N->ASTNode.getNodeKind();175      // Attributes don't target decls, look at the176      // thing it's attached to.177      // We still report the original NodeKind!178      // This makes the `override` hack work.179      if (N->ASTNode.get<Attr>() && N->Parent)180        N = N->Parent;181      llvm::copy_if(allTargetDecls(N->ASTNode, AST.getHeuristicResolver()),182                    std::back_inserter(Result),183                    [&](auto &Entry) { return !(Entry.second & ~Relations); });184    }185    return !Result.empty();186  };187  SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Offset,188                            Offset, ResultFromTree);189  return Result;190}191 192std::vector<const NamedDecl *>193getDeclAtPosition(ParsedAST &AST, SourceLocation Pos, DeclRelationSet Relations,194                  ASTNodeKind *NodeKind = nullptr) {195  std::vector<const NamedDecl *> Result;196  for (auto &Entry :197       getDeclAtPositionWithRelations(AST, Pos, Relations, NodeKind))198    Result.push_back(Entry.first);199  return Result;200}201 202// Expects Loc to be a SpellingLocation, will bail out otherwise as it can't203// figure out a filename.204std::optional<Location> makeLocation(const ASTContext &AST, SourceLocation Loc,205                                     llvm::StringRef TUPath) {206  const auto &SM = AST.getSourceManager();207  const auto F = SM.getFileEntryRefForID(SM.getFileID(Loc));208  if (!F)209    return std::nullopt;210  auto FilePath = getCanonicalPath(*F, SM.getFileManager());211  if (!FilePath) {212    log("failed to get path!");213    return std::nullopt;214  }215  Location L;216  L.uri = URIForFile::canonicalize(*FilePath, TUPath);217  // We call MeasureTokenLength here as TokenBuffer doesn't store spelled tokens218  // outside the main file.219  auto TokLen = Lexer::MeasureTokenLength(Loc, SM, AST.getLangOpts());220  L.range = halfOpenToRange(221      SM, CharSourceRange::getCharRange(Loc, Loc.getLocWithOffset(TokLen)));222  return L;223}224 225// Treat #included files as symbols, to enable go-to-definition on them.226std::optional<LocatedSymbol> locateFileReferent(const Position &Pos,227                                                ParsedAST &AST,228                                                llvm::StringRef MainFilePath) {229  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {230    if (!Inc.Resolved.empty() && Inc.HashLine == Pos.line) {231      LocatedSymbol File;232      File.Name = std::string(llvm::sys::path::filename(Inc.Resolved));233      File.PreferredDeclaration = {234          URIForFile::canonicalize(Inc.Resolved, MainFilePath), Range{}};235      File.Definition = File.PreferredDeclaration;236      // We're not going to find any further symbols on #include lines.237      return File;238    }239  }240  return std::nullopt;241}242 243// Macros are simple: there's no declaration/definition distinction.244// As a consequence, there's no need to look them up in the index either.245std::optional<LocatedSymbol>246locateMacroReferent(const syntax::Token &TouchedIdentifier, ParsedAST &AST,247                    llvm::StringRef MainFilePath) {248  if (auto M = locateMacroAt(TouchedIdentifier, AST.getPreprocessor())) {249    if (auto Loc =250            makeLocation(AST.getASTContext(), M->NameLoc, MainFilePath)) {251      LocatedSymbol Macro;252      Macro.Name = std::string(M->Name);253      Macro.PreferredDeclaration = *Loc;254      Macro.Definition = Loc;255      Macro.ID = getSymbolID(M->Name, M->Info, AST.getSourceManager());256      return Macro;257    }258  }259  return std::nullopt;260}261 262// A wrapper around `Decl::getCanonicalDecl` to support cases where Clang's263// definition of a canonical declaration doesn't match up to what a programmer264// would expect. For example, Objective-C classes can have three types of265// declarations:266//267// - forward declaration(s): @class MyClass;268// - true declaration (interface definition): @interface MyClass ... @end269// - true definition (implementation): @implementation MyClass ... @end270//271// Clang will consider the forward declaration to be the canonical declaration272// because it is first. We actually want the class definition if it is273// available since that is what a programmer would consider the primary274// declaration to be.275const NamedDecl *getPreferredDecl(const NamedDecl *D) {276  // FIXME: Canonical declarations of some symbols might refer to built-in277  // decls with possibly-invalid source locations (e.g. global new operator).278  // In such cases we should pick up a redecl with valid source location279  // instead of failing.280  D = llvm::cast<NamedDecl>(D->getCanonicalDecl());281 282  // Prefer Objective-C class/protocol definitions over the forward declaration.283  if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))284    if (const auto *DefinitionID = ID->getDefinition())285      return DefinitionID;286  if (const auto *PD = dyn_cast<ObjCProtocolDecl>(D))287    if (const auto *DefinitionID = PD->getDefinition())288      return DefinitionID;289 290  return D;291}292 293std::vector<LocatedSymbol> findImplementors(llvm::DenseSet<SymbolID> IDs,294                                            RelationKind Predicate,295                                            const SymbolIndex *Index,296                                            llvm::StringRef MainFilePath) {297  if (IDs.empty() || !Index)298    return {};299  static constexpr trace::Metric FindImplementorsMetric(300      "find_implementors", trace::Metric::Counter, "case");301  switch (Predicate) {302  case RelationKind::BaseOf:303    FindImplementorsMetric.record(1, "find-base");304    break;305  case RelationKind::OverriddenBy:306    FindImplementorsMetric.record(1, "find-override");307    break;308  }309 310  RelationsRequest Req;311  Req.Predicate = Predicate;312  Req.Subjects = std::move(IDs);313  std::vector<LocatedSymbol> Results;314  Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {315    auto DeclLoc =316        indexToLSPLocation(Object.CanonicalDeclaration, MainFilePath);317    if (!DeclLoc) {318      elog("Find overrides: {0}", DeclLoc.takeError());319      return;320    }321    Results.emplace_back();322    Results.back().Name = Object.Name.str();323    Results.back().PreferredDeclaration = *DeclLoc;324    auto DefLoc = indexToLSPLocation(Object.Definition, MainFilePath);325    if (!DefLoc) {326      elog("Failed to convert location: {0}", DefLoc.takeError());327      return;328    }329    Results.back().Definition = *DefLoc;330  });331  return Results;332}333 334// Given LocatedSymbol results derived from the AST, query the index to obtain335// definitions and preferred declarations.336void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,337                                    const SymbolIndex *Index,338                                    llvm::StringRef MainFilePath) {339  LookupRequest QueryRequest;340  llvm::DenseMap<SymbolID, unsigned> ResultIndex;341  for (unsigned I = 0; I < Result.size(); ++I) {342    if (auto ID = Result[I].ID) {343      ResultIndex.try_emplace(ID, I);344      QueryRequest.IDs.insert(ID);345    }346  }347  if (!Index || QueryRequest.IDs.empty())348    return;349  std::string Scratch;350  Index->lookup(QueryRequest, [&](const Symbol &Sym) {351    auto &R = Result[ResultIndex.lookup(Sym.ID)];352 353    if (R.Definition) { // from AST354      // Special case: if the AST yielded a definition, then it may not be355      // the right *declaration*. Prefer the one from the index.356      if (auto Loc = toLSPLocation(Sym.CanonicalDeclaration, MainFilePath))357        R.PreferredDeclaration = *Loc;358 359      // We might still prefer the definition from the index, e.g. for360      // generated symbols.361      if (auto Loc = toLSPLocation(362              getPreferredLocation(*R.Definition, Sym.Definition, Scratch),363              MainFilePath))364        R.Definition = *Loc;365    } else {366      R.Definition = toLSPLocation(Sym.Definition, MainFilePath);367 368      // Use merge logic to choose AST or index declaration.369      if (auto Loc = toLSPLocation(370              getPreferredLocation(R.PreferredDeclaration,371                                   Sym.CanonicalDeclaration, Scratch),372              MainFilePath))373        R.PreferredDeclaration = *Loc;374    }375  });376}377 378bool objcMethodIsTouched(const SourceManager &SM, const ObjCMethodDecl *OMD,379                         SourceLocation Loc) {380  unsigned NumSels = OMD->getNumSelectorLocs();381  for (unsigned I = 0; I < NumSels; ++I)382    if (SM.getSpellingLoc(OMD->getSelectorLoc(I)) == Loc)383      return true;384  return false;385}386 387// Decls are more complicated.388// The AST contains at least a declaration, maybe a definition.389// These are up-to-date, and so generally preferred over index results.390// We perform a single batch index lookup to find additional definitions.391std::vector<LocatedSymbol>392locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier,393                  ParsedAST &AST, llvm::StringRef MainFilePath,394                  const SymbolIndex *Index, ASTNodeKind &NodeKind) {395  const SourceManager &SM = AST.getSourceManager();396  // Results follow the order of Symbols.Decls.397  std::vector<LocatedSymbol> Result;398 399  static constexpr trace::Metric LocateASTReferentMetric(400      "locate_ast_referent", trace::Metric::Counter, "case");401  auto AddResultDecl = [&](const NamedDecl *D) {402    D = getPreferredDecl(D);403    auto Loc =404        makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath);405    if (!Loc)406      return;407 408    Result.emplace_back();409    Result.back().Name = printName(AST.getASTContext(), *D);410    Result.back().PreferredDeclaration = *Loc;411    Result.back().ID = getSymbolID(D);412    if (const NamedDecl *Def = getDefinition(D))413      Result.back().Definition = makeLocation(414          AST.getASTContext(), nameLocation(*Def, SM), MainFilePath);415  };416 417  // Emit all symbol locations (declaration or definition) from AST.418  DeclRelationSet Relations =419      DeclRelation::TemplatePattern | DeclRelation::Alias;420  auto Candidates =421      getDeclAtPositionWithRelations(AST, CurLoc, Relations, &NodeKind);422  llvm::DenseSet<SymbolID> VirtualMethods;423  for (const auto &E : Candidates) {424    const NamedDecl *D = E.first;425    if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(D)) {426      // Special case: virtual void ^method() = 0: jump to all overrides.427      // FIXME: extend it to ^virtual, unfortunately, virtual location is not428      // saved in the AST.429      if (CMD->isPureVirtual()) {430        if (TouchedIdentifier && SM.getSpellingLoc(CMD->getLocation()) ==431                                     TouchedIdentifier->location()) {432          VirtualMethods.insert(getSymbolID(CMD));433          LocateASTReferentMetric.record(1, "method-to-override");434        }435      }436      // Special case: void foo() ^override: jump to the overridden method.437      if (NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverrideAttr>()) ||438          NodeKind.isSame(ASTNodeKind::getFromNodeKind<FinalAttr>())) {439        // We may be overridding multiple methods - offer them all.440        for (const NamedDecl *ND : CMD->overridden_methods())441          AddResultDecl(ND);442        continue;443      }444    }445    // Special case: - (void)^method {} should jump to overrides, but the decl446    // shouldn't, only the definition. Note that an Objective-C method can447    // override a parent class or protocol.448    //449    // FIXME: Support jumping from a protocol decl to overrides on go-to450    // definition.451    if (const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D)) {452      if (OMD->isThisDeclarationADefinition() && TouchedIdentifier &&453          objcMethodIsTouched(SM, OMD, TouchedIdentifier->location())) {454        llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;455        OMD->getOverriddenMethods(Overrides);456        if (!Overrides.empty()) {457          for (const auto *Override : Overrides)458            AddResultDecl(Override);459          LocateASTReferentMetric.record(1, "objc-overriden-method");460        }461        AddResultDecl(OMD);462        continue;463      }464    }465 466    // Special case: the cursor is on an alias, prefer other results.467    // This targets "using ns::^Foo", where the target is more interesting.468    // This does not trigger on renaming aliases:469    //   `using Foo = ^Bar` already targets Bar via a TypeLoc470    //   `using ^Foo = Bar` has no other results, as Underlying is filtered.471    if (E.second & DeclRelation::Alias && Candidates.size() > 1 &&472        // beginLoc/endLoc are a token range, so rewind the identifier we're in.473        SM.isPointWithin(TouchedIdentifier ? TouchedIdentifier->location()474                                           : CurLoc,475                         D->getBeginLoc(), D->getEndLoc()))476      continue;477 478    // Special case: the point of declaration of a template specialization,479    // it's more useful to navigate to the template declaration.480    if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {481      if (TouchedIdentifier &&482          D->getLocation() == TouchedIdentifier->location()) {483        LocateASTReferentMetric.record(1, "template-specialization-to-primary");484        AddResultDecl(CTSD->getSpecializedTemplate());485        continue;486      }487    }488 489    // Special case: if the class name is selected, also map Objective-C490    // categories and category implementations back to their class interface.491    //492    // Since `TouchedIdentifier` might refer to the `ObjCCategoryImplDecl`493    // instead of the `ObjCCategoryDecl` we intentionally check the contents494    // of the locs when checking for class name equivalence.495    if (const auto *CD = dyn_cast<ObjCCategoryDecl>(D))496      if (const auto *ID = CD->getClassInterface())497        if (TouchedIdentifier &&498            (CD->getLocation() == TouchedIdentifier->location() ||499             ID->getName() == TouchedIdentifier->text(SM))) {500          LocateASTReferentMetric.record(1, "objc-category-to-class");501          AddResultDecl(ID);502        }503 504    LocateASTReferentMetric.record(1, "regular");505    // Otherwise the target declaration is the right one.506    AddResultDecl(D);507  }508  enhanceLocatedSymbolsFromIndex(Result, Index, MainFilePath);509 510  auto Overrides = findImplementors(VirtualMethods, RelationKind::OverriddenBy,511                                    Index, MainFilePath);512  Result.insert(Result.end(), Overrides.begin(), Overrides.end());513  return Result;514}515 516std::vector<LocatedSymbol> locateSymbolForType(const ParsedAST &AST,517                                               const QualType &Type,518                                               const SymbolIndex *Index) {519  const auto &SM = AST.getSourceManager();520  auto MainFilePath = AST.tuPath();521 522  // FIXME: this sends unique_ptr<Foo> to unique_ptr<T>.523  // Likely it would be better to send it to Foo (heuristically) or to both.524  auto Decls = targetDecl(DynTypedNode::create(Type.getNonReferenceType()),525                          DeclRelation::TemplatePattern | DeclRelation::Alias,526                          AST.getHeuristicResolver());527  if (Decls.empty())528    return {};529 530  std::vector<LocatedSymbol> Results;531  const auto &ASTContext = AST.getASTContext();532 533  for (const NamedDecl *D : Decls) {534    D = getPreferredDecl(D);535 536    auto Loc = makeLocation(ASTContext, nameLocation(*D, SM), MainFilePath);537    if (!Loc)538      continue;539 540    Results.emplace_back();541    Results.back().Name = printName(ASTContext, *D);542    Results.back().PreferredDeclaration = *Loc;543    Results.back().ID = getSymbolID(D);544    if (const NamedDecl *Def = getDefinition(D))545      Results.back().Definition =546          makeLocation(ASTContext, nameLocation(*Def, SM), MainFilePath);547  }548  enhanceLocatedSymbolsFromIndex(Results, Index, MainFilePath);549 550  return Results;551}552 553bool tokenSpelledAt(SourceLocation SpellingLoc, const syntax::TokenBuffer &TB) {554  auto ExpandedTokens = TB.expandedTokens(555      TB.sourceManager().getMacroArgExpandedLocation(SpellingLoc));556  return !ExpandedTokens.empty();557}558 559llvm::StringRef sourcePrefix(SourceLocation Loc, const SourceManager &SM) {560  auto D = SM.getDecomposedLoc(Loc);561  bool Invalid = false;562  llvm::StringRef Buf = SM.getBufferData(D.first, &Invalid);563  if (Invalid || D.second > Buf.size())564    return "";565  return Buf.substr(0, D.second);566}567 568bool isDependentName(ASTNodeKind NodeKind) {569  return NodeKind.isSame(ASTNodeKind::getFromNodeKind<OverloadExpr>()) ||570         NodeKind.isSame(571             ASTNodeKind::getFromNodeKind<CXXDependentScopeMemberExpr>()) ||572         NodeKind.isSame(573             ASTNodeKind::getFromNodeKind<DependentScopeDeclRefExpr>());574}575 576} // namespace577 578std::vector<LocatedSymbol> locateSymbolTextually(const SpelledWord &Word,579                                                 ParsedAST &AST,580                                                 const SymbolIndex *Index,581                                                 llvm::StringRef MainFilePath,582                                                 ASTNodeKind NodeKind) {583  // Don't use heuristics if this is a real identifier, or not an584  // identifier.585  // Exception: dependent names, because those may have useful textual586  // matches that AST-based heuristics cannot find.587  if ((Word.ExpandedToken && !isDependentName(NodeKind)) ||588      !Word.LikelyIdentifier || !Index)589    return {};590  // We don't want to handle words in string literals. (It'd be nice to list591  // *allowed* token kinds explicitly, but comment Tokens aren't retained).592  if (Word.PartOfSpelledToken &&593      isStringLiteral(Word.PartOfSpelledToken->kind()))594    return {};595 596  const auto &SM = AST.getSourceManager();597  // Look up the selected word in the index.598  FuzzyFindRequest Req;599  Req.Query = Word.Text.str();600  Req.ProximityPaths = {MainFilePath.str()};601  // Find the namespaces to query by lexing the file.602  Req.Scopes =603      visibleNamespaces(sourcePrefix(Word.Location, SM), AST.getLangOpts());604  // FIXME: For extra strictness, consider AnyScope=false.605  Req.AnyScope = true;606  // We limit the results to 3 further below. This limit is to avoid fetching607  // too much data, while still likely having enough for 3 results to remain608  // after additional filtering.609  Req.Limit = 10;610  bool TooMany = false;611  using ScoredLocatedSymbol = std::pair<float, LocatedSymbol>;612  std::vector<ScoredLocatedSymbol> ScoredResults;613  Index->fuzzyFind(Req, [&](const Symbol &Sym) {614    // Only consider exact name matches, including case.615    // This is to avoid too many false positives.616    // We could relax this in the future (e.g. to allow for typos) if we make617    // the query more accurate by other means.618    if (Sym.Name != Word.Text)619      return;620 621    // Exclude constructor results. They have the same name as the class,622    // but we don't have enough context to prefer them over the class.623    if (Sym.SymInfo.Kind == index::SymbolKind::Constructor)624      return;625 626    auto MaybeDeclLoc =627        indexToLSPLocation(Sym.CanonicalDeclaration, MainFilePath);628    if (!MaybeDeclLoc) {629      log("locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError());630      return;631    }632    LocatedSymbol Located;633    Located.PreferredDeclaration = *MaybeDeclLoc;634    Located.Name = (Sym.Name + Sym.TemplateSpecializationArgs).str();635    Located.ID = Sym.ID;636    if (Sym.Definition) {637      auto MaybeDefLoc = indexToLSPLocation(Sym.Definition, MainFilePath);638      if (!MaybeDefLoc) {639        log("locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError());640        return;641      }642      Located.PreferredDeclaration = *MaybeDefLoc;643      Located.Definition = *MaybeDefLoc;644    }645 646    if (ScoredResults.size() >= 5) {647      // If we have more than 5 results, don't return anything,648      // as confidence is too low.649      // FIXME: Alternatively, try a stricter query?650      TooMany = true;651      return;652    }653 654    SymbolQualitySignals Quality;655    Quality.merge(Sym);656    SymbolRelevanceSignals Relevance;657    Relevance.Name = Sym.Name;658    Relevance.Query = SymbolRelevanceSignals::Generic;659    Relevance.merge(Sym);660    auto Score = evaluateSymbolAndRelevance(Quality.evaluateHeuristics(),661                                            Relevance.evaluateHeuristics());662    dlog("locateSymbolNamedTextuallyAt: {0}{1} = {2}\n{3}{4}\n", Sym.Scope,663         Sym.Name, Score, Quality, Relevance);664 665    ScoredResults.push_back({Score, std::move(Located)});666  });667 668  if (TooMany) {669    vlog("Heuristic index lookup for {0} returned too many candidates, ignored",670         Word.Text);671    return {};672  }673 674  llvm::sort(ScoredResults,675             [](const ScoredLocatedSymbol &A, const ScoredLocatedSymbol &B) {676               return A.first > B.first;677             });678  std::vector<LocatedSymbol> Results;679  for (auto &Res : std::move(ScoredResults))680    Results.push_back(std::move(Res.second));681  if (Results.empty())682    vlog("No heuristic index definition for {0}", Word.Text);683  else684    log("Found definition heuristically in index for {0}", Word.Text);685  return Results;686}687 688const syntax::Token *findNearbyIdentifier(const SpelledWord &Word,689                                          const syntax::TokenBuffer &TB) {690  // Don't use heuristics if this is a real identifier.691  // Unlikely identifiers are OK if they were used as identifiers nearby.692  if (Word.ExpandedToken)693    return nullptr;694  // We don't want to handle words in string literals. (It'd be nice to list695  // *allowed* token kinds explicitly, but comment Tokens aren't retained).696  if (Word.PartOfSpelledToken &&697      isStringLiteral(Word.PartOfSpelledToken->kind()))698    return {};699 700  const SourceManager &SM = TB.sourceManager();701  // We prefer the closest possible token, line-wise. Backwards is penalized.702  // Ties are implicitly broken by traversal order (first-one-wins).703  auto File = SM.getFileID(Word.Location);704  unsigned WordLine = SM.getSpellingLineNumber(Word.Location);705  auto Cost = [&](SourceLocation Loc) -> unsigned {706    assert(SM.getFileID(Loc) == File && "spelled token in wrong file?");707    unsigned Line = SM.getSpellingLineNumber(Loc);708    return Line >= WordLine ? Line - WordLine : 2 * (WordLine - Line);709  };710  const syntax::Token *BestTok = nullptr;711  unsigned BestCost = -1;712  // Search bounds are based on word length:713  // - forward: 2^N lines714  // - backward: 2^(N-1) lines.715  unsigned MaxDistance =716      1U << std::min<unsigned>(Word.Text.size(),717                               std::numeric_limits<unsigned>::digits - 1);718  // Line number for SM.translateLineCol() should be one-based, also719  // SM.translateLineCol() can handle line number greater than720  // number of lines in the file.721  // - LineMin = max(1, WordLine + 1 - 2^(N-1))722  // - LineMax = WordLine + 1 + 2^N723  unsigned LineMin =724      WordLine + 1 <= MaxDistance / 2 ? 1 : WordLine + 1 - MaxDistance / 2;725  unsigned LineMax = WordLine + 1 + MaxDistance;726  SourceLocation LocMin = SM.translateLineCol(File, LineMin, 1);727  assert(LocMin.isValid());728  SourceLocation LocMax = SM.translateLineCol(File, LineMax, 1);729  assert(LocMax.isValid());730 731  // Updates BestTok and BestCost if Tok is a good candidate.732  // May return true if the cost is too high for this token.733  auto Consider = [&](const syntax::Token &Tok) {734    if (Tok.location() < LocMin || Tok.location() > LocMax)735      return true; // we are too far from the word, break the outer loop.736    if (!(Tok.kind() == tok::identifier && Tok.text(SM) == Word.Text))737      return false;738    // No point guessing the same location we started with.739    if (Tok.location() == Word.Location)740      return false;741    // We've done cheap checks, compute cost so we can break the caller's loop.742    unsigned TokCost = Cost(Tok.location());743    if (TokCost >= BestCost)744      return true; // causes the outer loop to break.745    // Allow locations that might be part of the AST, and macros (even if empty)746    // but not things like disabled preprocessor sections.747    if (!(tokenSpelledAt(Tok.location(), TB) || TB.expansionStartingAt(&Tok)))748      return false;749    // We already verified this token is an improvement.750    BestCost = TokCost;751    BestTok = &Tok;752    return false;753  };754  auto SpelledTokens = TB.spelledTokens(File);755  // Find where the word occurred in the token stream, to search forward & back.756  auto *I = llvm::partition_point(SpelledTokens, [&](const syntax::Token &T) {757    assert(SM.getFileID(T.location()) == SM.getFileID(Word.Location));758    return T.location() < Word.Location; // Comparison OK: same file.759  });760  // Search for matches after the cursor.761  for (const syntax::Token &Tok : llvm::ArrayRef(I, SpelledTokens.end()))762    if (Consider(Tok))763      break; // costs of later tokens are greater...764  // Search for matches before the cursor.765  for (const syntax::Token &Tok :766       llvm::reverse(llvm::ArrayRef(SpelledTokens.begin(), I)))767    if (Consider(Tok))768      break;769 770  if (BestTok)771    vlog(772        "Word {0} under cursor {1} isn't a token (after PP), trying nearby {2}",773        Word.Text, Word.Location.printToString(SM),774        BestTok->location().printToString(SM));775 776  return BestTok;777}778 779std::vector<LocatedSymbol> locateSymbolAt(ParsedAST &AST, Position Pos,780                                          const SymbolIndex *Index) {781  const auto &SM = AST.getSourceManager();782  auto MainFilePath = AST.tuPath();783 784  if (auto File = locateFileReferent(Pos, AST, MainFilePath))785    return {std::move(*File)};786 787  auto CurLoc = sourceLocationInMainFile(SM, Pos);788  if (!CurLoc) {789    elog("locateSymbolAt failed to convert position to source location: {0}",790         CurLoc.takeError());791    return {};792  }793 794  const syntax::Token *TouchedIdentifier = nullptr;795  auto TokensTouchingCursor =796      syntax::spelledTokensTouching(*CurLoc, AST.getTokens());797  for (const syntax::Token &Tok : TokensTouchingCursor) {798    if (Tok.kind() == tok::identifier) {799      if (auto Macro = locateMacroReferent(Tok, AST, MainFilePath))800        // Don't look at the AST or index if we have a macro result.801        // (We'd just return declarations referenced from the macro's802        // expansion.)803        return {*std::move(Macro)};804 805      TouchedIdentifier = &Tok;806      break;807    }808 809    if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {810      // go-to-definition on auto should find the definition of the deduced811      // type, if possible812      if (auto Deduced =813              getDeducedType(AST.getASTContext(), AST.getHeuristicResolver(),814                             Tok.location())) {815        auto LocSym = locateSymbolForType(AST, *Deduced, Index);816        if (!LocSym.empty())817          return LocSym;818      }819    }820  }821 822  ASTNodeKind NodeKind;823  auto ASTResults = locateASTReferent(*CurLoc, TouchedIdentifier, AST,824                                      MainFilePath, Index, NodeKind);825  if (!ASTResults.empty())826    return ASTResults;827 828  // If the cursor can't be resolved directly, try fallback strategies.829  auto Word =830      SpelledWord::touching(*CurLoc, AST.getTokens(), AST.getLangOpts());831  if (Word) {832    // Is the same word nearby a real identifier that might refer to something?833    if (const syntax::Token *NearbyIdent =834            findNearbyIdentifier(*Word, AST.getTokens())) {835      if (auto Macro = locateMacroReferent(*NearbyIdent, AST, MainFilePath)) {836        log("Found macro definition heuristically using nearby identifier {0}",837            Word->Text);838        return {*std::move(Macro)};839      }840      ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent, AST,841                                     MainFilePath, Index, NodeKind);842      if (!ASTResults.empty()) {843        log("Found definition heuristically using nearby identifier {0}",844            NearbyIdent->text(SM));845        return ASTResults;846      }847      vlog("No definition found using nearby identifier {0} at {1}", Word->Text,848           Word->Location.printToString(SM));849    }850    // No nearby word, or it didn't refer to anything either. Try the index.851    auto TextualResults =852        locateSymbolTextually(*Word, AST, Index, MainFilePath, NodeKind);853    if (!TextualResults.empty())854      return TextualResults;855  }856 857  return {};858}859 860std::vector<DocumentLink> getDocumentLinks(ParsedAST &AST) {861  const auto &SM = AST.getSourceManager();862 863  std::vector<DocumentLink> Result;864  for (auto &Inc : AST.getIncludeStructure().MainFileIncludes) {865    if (Inc.Resolved.empty())866      continue;867 868    // Get the location of the # symbole of the "#include ..." statement869    auto HashLoc = SM.getComposedLoc(SM.getMainFileID(), Inc.HashOffset);870 871    // get the # Token itself, std::next to get the "include" token and the872    // first token after (aka "File Token")873    const auto *HashTok = AST.getTokens().spelledTokenContaining(HashLoc);874    assert(HashTok && "got inclusion at wrong offset");875    const auto *IncludeTok = std::next(HashTok);876    const auto *FileTok = std::next(IncludeTok);877 878    // The File Token can either be of kind :879    // "less" if using the "#include <h-char-sequence> new-line" syntax880    // "string_literal" if using the "#include "q-char-sequence" new-line"881    // syntax something else (most likely "identifier") if using the "#include882    // pp-tokens new-line" syntax (#include with macro argument)883 884    CharSourceRange FileRange;885 886    if (FileTok->kind() == tok::TokenKind::less) {887      // FileTok->range would only include the '<' char. Hence we explicitly use888      // Inc.Written's length.889      FileRange =890          syntax::FileRange(SM, FileTok->location(), Inc.Written.length())891              .toCharRange(SM);892    } else if (FileTok->kind() == tok::TokenKind::string_literal) {893      // FileTok->range includes the quotes for string literals so just return894      // it.895      FileRange = FileTok->range(SM).toCharRange(SM);896    } else {897      // FileTok is the first Token of a macro spelling898 899      // Report the range of the first token (as it should be the macro900      // identifier)901      // We could use the AST to find the last spelled token of the macro and902      // report a range spanning the full macro expression, but it would require903      // using token-buffers that are deemed too unstable and crash-prone904      // due to optimizations in cland905 906      FileRange = FileTok->range(SM).toCharRange(SM);907    }908 909    Result.push_back(910        DocumentLink({halfOpenToRange(SM, FileRange),911                      URIForFile::canonicalize(Inc.Resolved, AST.tuPath())}));912  }913 914  return Result;915}916 917namespace {918 919/// Collects references to symbols within the main file.920class ReferenceFinder : public index::IndexDataConsumer {921public:922  struct Reference {923    syntax::Token SpelledTok;924    index::SymbolRoleSet Role;925    const Decl *Container;926 927    Range range(const SourceManager &SM) const {928      return halfOpenToRange(SM, SpelledTok.range(SM).toCharRange(SM));929    }930  };931 932  ReferenceFinder(const ParsedAST &AST,933                  const llvm::ArrayRef<const NamedDecl *> Targets,934                  bool PerToken)935      : PerToken(PerToken), AST(AST) {936    for (const NamedDecl *ND : Targets)937      TargetDecls.insert(ND->getCanonicalDecl());938  }939 940  std::vector<Reference> take() && {941    llvm::sort(References, [](const Reference &L, const Reference &R) {942      auto LTok = L.SpelledTok.location();943      auto RTok = R.SpelledTok.location();944      return std::tie(LTok, L.Role) < std::tie(RTok, R.Role);945    });946    // We sometimes see duplicates when parts of the AST get traversed twice.947    References.erase(llvm::unique(References,948                                  [](const Reference &L, const Reference &R) {949                                    auto LTok = L.SpelledTok.location();950                                    auto RTok = R.SpelledTok.location();951                                    return std::tie(LTok, L.Role) ==952                                           std::tie(RTok, R.Role);953                                  }),954                     References.end());955    return std::move(References);956  }957 958  bool959  handleDeclOccurrence(const Decl *D, index::SymbolRoleSet Roles,960                       llvm::ArrayRef<index::SymbolRelation> Relations,961                       SourceLocation Loc,962                       index::IndexDataConsumer::ASTNodeInfo ASTNode) override {963    if (!TargetDecls.contains(D->getCanonicalDecl()))964      return true;965    const SourceManager &SM = AST.getSourceManager();966    if (!isInsideMainFile(Loc, SM))967      return true;968    const auto &TB = AST.getTokens();969 970    llvm::SmallVector<SourceLocation, 1> Locs;971    if (PerToken) {972      // Check whether this is one of the few constructs where the reference973      // can be split over several tokens.974      if (auto *OME = llvm::dyn_cast_or_null<ObjCMessageExpr>(ASTNode.OrigE)) {975        OME->getSelectorLocs(Locs);976      } else if (auto *OMD =977                     llvm::dyn_cast_or_null<ObjCMethodDecl>(ASTNode.OrigD)) {978        OMD->getSelectorLocs(Locs);979      }980      // Sanity check: we expect the *first* token to match the reported loc.981      // Otherwise, maybe it was e.g. some other kind of reference to a Decl.982      if (!Locs.empty() && Locs.front() != Loc)983        Locs.clear(); // First token doesn't match, assume our guess was wrong.984    }985    if (Locs.empty())986      Locs.push_back(Loc);987 988    SymbolCollector::Options CollectorOpts;989    CollectorOpts.CollectMainFileSymbols = true;990    for (SourceLocation L : Locs) {991      L = SM.getFileLoc(L);992      if (const auto *Tok = TB.spelledTokenContaining(L))993        References.push_back(994            {*Tok, Roles,995             SymbolCollector::getRefContainer(ASTNode.Parent, CollectorOpts)});996    }997    return true;998  }999 1000private:1001  bool PerToken; // If true, report 3 references for split ObjC selector names.1002  std::vector<Reference> References;1003  const ParsedAST &AST;1004  llvm::DenseSet<const Decl *> TargetDecls;1005};1006 1007std::vector<ReferenceFinder::Reference>1008findRefs(const llvm::ArrayRef<const NamedDecl *> TargetDecls, ParsedAST &AST,1009         bool PerToken) {1010  ReferenceFinder RefFinder(AST, TargetDecls, PerToken);1011  index::IndexingOptions IndexOpts;1012  IndexOpts.SystemSymbolFilter =1013      index::IndexingOptions::SystemSymbolFilterKind::All;1014  IndexOpts.IndexFunctionLocals = true;1015  IndexOpts.IndexParametersInDeclarations = true;1016  IndexOpts.IndexTemplateParameters = true;1017  indexTopLevelDecls(AST.getASTContext(), AST.getPreprocessor(),1018                     AST.getLocalTopLevelDecls(), RefFinder, IndexOpts);1019  return std::move(RefFinder).take();1020}1021 1022const Stmt *getFunctionBody(DynTypedNode N) {1023  if (const auto *FD = N.get<FunctionDecl>())1024    return FD->getBody();1025  if (const auto *FD = N.get<BlockDecl>())1026    return FD->getBody();1027  if (const auto *FD = N.get<LambdaExpr>())1028    return FD->getBody();1029  if (const auto *FD = N.get<ObjCMethodDecl>())1030    return FD->getBody();1031  return nullptr;1032}1033 1034const Stmt *getLoopBody(DynTypedNode N) {1035  if (const auto *LS = N.get<ForStmt>())1036    return LS->getBody();1037  if (const auto *LS = N.get<CXXForRangeStmt>())1038    return LS->getBody();1039  if (const auto *LS = N.get<WhileStmt>())1040    return LS->getBody();1041  if (const auto *LS = N.get<DoStmt>())1042    return LS->getBody();1043  return nullptr;1044}1045 1046// AST traversal to highlight control flow statements under some root.1047// Once we hit further control flow we prune the tree (or at least restrict1048// what we highlight) so we capture e.g. breaks from the outer loop only.1049class FindControlFlow : public RecursiveASTVisitor<FindControlFlow> {1050  // Types of control-flow statements we might highlight.1051  enum Target {1052    Break = 1,1053    Continue = 2,1054    Return = 4,1055    Case = 8,1056    Throw = 16,1057    Goto = 32,1058    All = Break | Continue | Return | Case | Throw | Goto,1059  };1060  int Ignore = 0;     // bitmask of Target - what are we *not* highlighting?1061  SourceRange Bounds; // Half-open, restricts reported targets.1062  std::vector<SourceLocation> &Result;1063  const SourceManager &SM;1064 1065  // Masks out targets for a traversal into D.1066  // Traverses the subtree using Delegate() if any targets remain.1067  template <typename Func>1068  bool filterAndTraverse(DynTypedNode D, const Func &Delegate) {1069    auto RestoreIgnore = llvm::make_scope_exit(1070        [OldIgnore(Ignore), this] { Ignore = OldIgnore; });1071    if (getFunctionBody(D))1072      Ignore = All;1073    else if (getLoopBody(D))1074      Ignore |= Continue | Break;1075    else if (D.get<SwitchStmt>())1076      Ignore |= Break | Case;1077    // Prune tree if we're not looking for anything.1078    return (Ignore == All) ? true : Delegate();1079  }1080 1081  void found(Target T, SourceLocation Loc) {1082    if (T & Ignore)1083      return;1084    if (SM.isBeforeInTranslationUnit(Loc, Bounds.getBegin()) ||1085        SM.isBeforeInTranslationUnit(Bounds.getEnd(), Loc))1086      return;1087    Result.push_back(Loc);1088  }1089 1090public:1091  FindControlFlow(SourceRange Bounds, std::vector<SourceLocation> &Result,1092                  const SourceManager &SM)1093      : Bounds(Bounds), Result(Result), SM(SM) {}1094 1095  // When traversing function or loops, limit targets to those that still1096  // refer to the original root.1097  bool TraverseDecl(Decl *D) {1098    return !D || filterAndTraverse(DynTypedNode::create(*D), [&] {1099      return RecursiveASTVisitor::TraverseDecl(D);1100    });1101  }1102  bool TraverseStmt(Stmt *S) {1103    return !S || filterAndTraverse(DynTypedNode::create(*S), [&] {1104      return RecursiveASTVisitor::TraverseStmt(S);1105    });1106  }1107 1108  // Add leaves that we found and want.1109  bool VisitReturnStmt(ReturnStmt *R) {1110    found(Return, R->getReturnLoc());1111    return true;1112  }1113  bool VisitBreakStmt(BreakStmt *B) {1114    found(Break, B->getKwLoc());1115    return true;1116  }1117  bool VisitContinueStmt(ContinueStmt *C) {1118    found(Continue, C->getKwLoc());1119    return true;1120  }1121  bool VisitSwitchCase(SwitchCase *C) {1122    found(Case, C->getKeywordLoc());1123    return true;1124  }1125  bool VisitCXXThrowExpr(CXXThrowExpr *T) {1126    found(Throw, T->getThrowLoc());1127    return true;1128  }1129  bool VisitGotoStmt(GotoStmt *G) {1130    // Goto is interesting if its target is outside the root.1131    if (const auto *LD = G->getLabel()) {1132      if (SM.isBeforeInTranslationUnit(LD->getLocation(), Bounds.getBegin()) ||1133          SM.isBeforeInTranslationUnit(Bounds.getEnd(), LD->getLocation()))1134        found(Goto, G->getGotoLoc());1135    }1136    return true;1137  }1138};1139 1140// Given a location within a switch statement, return the half-open range that1141// covers the case it's contained in.1142// We treat `case X: case Y: ...` as one case, and assume no other fallthrough.1143SourceRange findCaseBounds(const SwitchStmt &Switch, SourceLocation Loc,1144                           const SourceManager &SM) {1145  // Cases are not stored in order, sort them first.1146  // (In fact they seem to be stored in reverse order, don't rely on this)1147  std::vector<const SwitchCase *> Cases;1148  for (const SwitchCase *Case = Switch.getSwitchCaseList(); Case;1149       Case = Case->getNextSwitchCase())1150    Cases.push_back(Case);1151  llvm::sort(Cases, [&](const SwitchCase *L, const SwitchCase *R) {1152    return SM.isBeforeInTranslationUnit(L->getKeywordLoc(), R->getKeywordLoc());1153  });1154 1155  // Find the first case after the target location, the end of our range.1156  auto CaseAfter = llvm::partition_point(Cases, [&](const SwitchCase *C) {1157    return !SM.isBeforeInTranslationUnit(Loc, C->getKeywordLoc());1158  });1159  SourceLocation End = CaseAfter == Cases.end() ? Switch.getEndLoc()1160                                                : (*CaseAfter)->getKeywordLoc();1161 1162  // Our target can be before the first case - cases are optional!1163  if (CaseAfter == Cases.begin())1164    return SourceRange(Switch.getBeginLoc(), End);1165  // The start of our range is usually the previous case, but...1166  auto CaseBefore = std::prev(CaseAfter);1167  // ... rewind CaseBefore to the first in a `case A: case B: ...` sequence.1168  while (CaseBefore != Cases.begin() &&1169         (*std::prev(CaseBefore))->getSubStmt() == *CaseBefore)1170    --CaseBefore;1171  return SourceRange((*CaseBefore)->getKeywordLoc(), End);1172}1173 1174// Returns the locations of control flow statements related to N. e.g.:1175//   for    => branches: break/continue/return/throw1176//   break  => controlling loop (forwhile/do), and its related control flow1177//   return => all returns/throws from the same function1178// When an inner block is selected, we include branches bound to outer blocks1179// as these are exits from the inner block. e.g. return in a for loop.1180// FIXME: We don't analyze catch blocks, throw is treated the same as return.1181std::vector<SourceLocation> relatedControlFlow(const SelectionTree::Node &N) {1182  const SourceManager &SM =1183      N.getDeclContext().getParentASTContext().getSourceManager();1184  std::vector<SourceLocation> Result;1185 1186  // First, check if we're at a node that can resolve to a root.1187  enum class Cur { None, Break, Continue, Return, Case, Throw } Cursor;1188  if (N.ASTNode.get<BreakStmt>()) {1189    Cursor = Cur::Break;1190  } else if (N.ASTNode.get<ContinueStmt>()) {1191    Cursor = Cur::Continue;1192  } else if (N.ASTNode.get<ReturnStmt>()) {1193    Cursor = Cur::Return;1194  } else if (N.ASTNode.get<CXXThrowExpr>()) {1195    Cursor = Cur::Throw;1196  } else if (N.ASTNode.get<SwitchCase>()) {1197    Cursor = Cur::Case;1198  } else if (const GotoStmt *GS = N.ASTNode.get<GotoStmt>()) {1199    // We don't know what root to associate with, but highlight the goto/label.1200    Result.push_back(GS->getGotoLoc());1201    if (const auto *LD = GS->getLabel())1202      Result.push_back(LD->getLocation());1203    Cursor = Cur::None;1204  } else {1205    Cursor = Cur::None;1206  }1207 1208  const Stmt *Root = nullptr; // Loop or function body to traverse.1209  SourceRange Bounds;1210  // Look up the tree for a root (or just at this node if we didn't find a leaf)1211  for (const auto *P = &N; P; P = P->Parent) {1212    // return associates with enclosing function1213    if (const Stmt *FunctionBody = getFunctionBody(P->ASTNode)) {1214      if (Cursor == Cur::Return || Cursor == Cur::Throw) {1215        Root = FunctionBody;1216      }1217      break; // other leaves don't cross functions.1218    }1219    // break/continue associate with enclosing loop.1220    if (const Stmt *LoopBody = getLoopBody(P->ASTNode)) {1221      if (Cursor == Cur::None || Cursor == Cur::Break ||1222          Cursor == Cur::Continue) {1223        Root = LoopBody;1224        // Highlight the loop keyword itself.1225        // FIXME: for do-while, this only covers the `do`..1226        Result.push_back(P->ASTNode.getSourceRange().getBegin());1227        break;1228      }1229    }1230    // For switches, users think of case statements as control flow blocks.1231    // We highlight only occurrences surrounded by the same case.1232    // We don't detect fallthrough (other than 'case X, case Y').1233    if (const auto *SS = P->ASTNode.get<SwitchStmt>()) {1234      if (Cursor == Cur::Break || Cursor == Cur::Case) {1235        Result.push_back(SS->getSwitchLoc()); // Highlight the switch.1236        Root = SS->getBody();1237        // Limit to enclosing case, if there is one.1238        Bounds = findCaseBounds(*SS, N.ASTNode.getSourceRange().getBegin(), SM);1239        break;1240      }1241    }1242    // If we didn't start at some interesting node, we're done.1243    if (Cursor == Cur::None)1244      break;1245  }1246  if (Root) {1247    if (!Bounds.isValid())1248      Bounds = Root->getSourceRange();1249    FindControlFlow(Bounds, Result, SM).TraverseStmt(const_cast<Stmt *>(Root));1250  }1251  return Result;1252}1253 1254DocumentHighlight toHighlight(const ReferenceFinder::Reference &Ref,1255                              const SourceManager &SM) {1256  DocumentHighlight DH;1257  DH.range = Ref.range(SM);1258  if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Write))1259    DH.kind = DocumentHighlightKind::Write;1260  else if (Ref.Role & index::SymbolRoleSet(index::SymbolRole::Read))1261    DH.kind = DocumentHighlightKind::Read;1262  else1263    DH.kind = DocumentHighlightKind::Text;1264  return DH;1265}1266 1267std::optional<DocumentHighlight> toHighlight(SourceLocation Loc,1268                                             const syntax::TokenBuffer &TB) {1269  Loc = TB.sourceManager().getFileLoc(Loc);1270  if (const auto *Tok = TB.spelledTokenContaining(Loc)) {1271    DocumentHighlight Result;1272    Result.range = halfOpenToRange(1273        TB.sourceManager(),1274        CharSourceRange::getCharRange(Tok->location(), Tok->endLocation()));1275    return Result;1276  }1277  return std::nullopt;1278}1279 1280} // namespace1281 1282std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST,1283                                                      Position Pos) {1284  const SourceManager &SM = AST.getSourceManager();1285  // FIXME: show references to macro within file?1286  auto CurLoc = sourceLocationInMainFile(SM, Pos);1287  if (!CurLoc) {1288    llvm::consumeError(CurLoc.takeError());1289    return {};1290  }1291  std::vector<DocumentHighlight> Result;1292  auto TryTree = [&](SelectionTree ST) {1293    if (const SelectionTree::Node *N = ST.commonAncestor()) {1294      DeclRelationSet Relations =1295          DeclRelation::TemplatePattern | DeclRelation::Alias;1296      auto TargetDecls =1297          targetDecl(N->ASTNode, Relations, AST.getHeuristicResolver());1298      if (!TargetDecls.empty()) {1299        // FIXME: we may get multiple DocumentHighlights with the same location1300        // and different kinds, deduplicate them.1301        for (const auto &Ref : findRefs(TargetDecls, AST, /*PerToken=*/true))1302          Result.push_back(toHighlight(Ref, SM));1303        return true;1304      }1305      auto ControlFlow = relatedControlFlow(*N);1306      if (!ControlFlow.empty()) {1307        for (SourceLocation Loc : ControlFlow)1308          if (auto Highlight = toHighlight(Loc, AST.getTokens()))1309            Result.push_back(std::move(*Highlight));1310        return true;1311      }1312    }1313    return false;1314  };1315 1316  unsigned Offset =1317      AST.getSourceManager().getDecomposedSpellingLoc(*CurLoc).second;1318  SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), Offset,1319                            Offset, TryTree);1320  return Result;1321}1322 1323std::vector<LocatedSymbol> findImplementations(ParsedAST &AST, Position Pos,1324                                               const SymbolIndex *Index) {1325  // We rely on index to find the implementations in subclasses.1326  // FIXME: Index can be stale, so we may loose some latest results from the1327  // main file.1328  if (!Index)1329    return {};1330  const SourceManager &SM = AST.getSourceManager();1331  auto CurLoc = sourceLocationInMainFile(SM, Pos);1332  if (!CurLoc) {1333    elog("Failed to convert position to source location: {0}",1334         CurLoc.takeError());1335    return {};1336  }1337  DeclRelationSet Relations =1338      DeclRelation::TemplatePattern | DeclRelation::Alias;1339  llvm::DenseSet<SymbolID> IDs;1340  RelationKind QueryKind = RelationKind::OverriddenBy;1341  for (const NamedDecl *ND : getDeclAtPosition(AST, *CurLoc, Relations)) {1342    if (const auto *CXXMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {1343      if (CXXMD->isVirtual()) {1344        IDs.insert(getSymbolID(ND));1345        QueryKind = RelationKind::OverriddenBy;1346      }1347    } else if (const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {1348      IDs.insert(getSymbolID(RD));1349      QueryKind = RelationKind::BaseOf;1350    } else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(ND)) {1351      IDs.insert(getSymbolID(OMD));1352      QueryKind = RelationKind::OverriddenBy;1353    } else if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {1354      IDs.insert(getSymbolID(ID));1355      QueryKind = RelationKind::BaseOf;1356    }1357  }1358  return findImplementors(std::move(IDs), QueryKind, Index, AST.tuPath());1359}1360 1361namespace {1362// Recursively finds all the overridden methods of `CMD` in complete type1363// hierarchy.1364void getOverriddenMethods(const CXXMethodDecl *CMD,1365                          llvm::DenseSet<SymbolID> &OverriddenMethods) {1366  if (!CMD)1367    return;1368  for (const CXXMethodDecl *Base : CMD->overridden_methods()) {1369    if (auto ID = getSymbolID(Base))1370      OverriddenMethods.insert(ID);1371    getOverriddenMethods(Base, OverriddenMethods);1372  }1373}1374 1375// Recursively finds all the overridden methods of `OMD` in complete type1376// hierarchy.1377void getOverriddenMethods(const ObjCMethodDecl *OMD,1378                          llvm::DenseSet<SymbolID> &OverriddenMethods) {1379  if (!OMD)1380    return;1381  llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides;1382  OMD->getOverriddenMethods(Overrides);1383  for (const ObjCMethodDecl *Base : Overrides) {1384    if (auto ID = getSymbolID(Base))1385      OverriddenMethods.insert(ID);1386    getOverriddenMethods(Base, OverriddenMethods);1387  }1388}1389 1390std::optional<std::string>1391stringifyContainerForMainFileRef(const Decl *Container) {1392  // FIXME We might also want to display the signature here1393  // When doing so, remember to also add the Signature to index results!1394  if (auto *ND = llvm::dyn_cast_if_present<NamedDecl>(Container))1395    return printQualifiedName(*ND);1396  return {};1397}1398 1399std::optional<ReferencesResult>1400maybeFindIncludeReferences(ParsedAST &AST, Position Pos,1401                           URIForFile URIMainFile) {1402  const auto &Includes = AST.getIncludeStructure().MainFileIncludes;1403  auto IncludeOnLine = llvm::find_if(Includes, [&Pos](const Inclusion &Inc) {1404    return Inc.HashLine == Pos.line;1405  });1406  if (IncludeOnLine == Includes.end())1407    return std::nullopt;1408 1409  const SourceManager &SM = AST.getSourceManager();1410  ReferencesResult Results;1411  auto Converted = convertIncludes(AST);1412  include_cleaner::walkUsed(1413      AST.getLocalTopLevelDecls(), collectMacroReferences(AST),1414      &AST.getPragmaIncludes(), AST.getPreprocessor(),1415      [&](const include_cleaner::SymbolReference &Ref,1416          llvm::ArrayRef<include_cleaner::Header> Providers) {1417        if (Ref.RT != include_cleaner::RefType::Explicit ||1418            !isPreferredProvider(*IncludeOnLine, Converted, Providers))1419          return;1420 1421        auto Loc = SM.getFileLoc(Ref.RefLocation);1422        // File locations can be outside of the main file if macro is1423        // expanded through an #include.1424        while (SM.getFileID(Loc) != SM.getMainFileID())1425          Loc = SM.getIncludeLoc(SM.getFileID(Loc));1426 1427        ReferencesResult::Reference Result;1428        const auto *Token = AST.getTokens().spelledTokenContaining(Loc);1429        assert(Token && "references expected token here");1430        Result.Loc.range = Range{sourceLocToPosition(SM, Token->location()),1431                                 sourceLocToPosition(SM, Token->endLocation())};1432        Result.Loc.uri = URIMainFile;1433        Results.References.push_back(std::move(Result));1434      });1435  if (Results.References.empty())1436    return std::nullopt;1437 1438  // Add the #include line to the references list.1439  ReferencesResult::Reference Result;1440  Result.Loc.range = rangeTillEOL(SM.getBufferData(SM.getMainFileID()),1441                                  IncludeOnLine->HashOffset);1442  Result.Loc.uri = URIMainFile;1443  Results.References.push_back(std::move(Result));1444  return Results;1445}1446} // namespace1447 1448ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,1449                                const SymbolIndex *Index, bool AddContext) {1450  ReferencesResult Results;1451  const SourceManager &SM = AST.getSourceManager();1452  auto MainFilePath = AST.tuPath();1453  auto URIMainFile = URIForFile::canonicalize(MainFilePath, MainFilePath);1454  auto CurLoc = sourceLocationInMainFile(SM, Pos);1455  if (!CurLoc) {1456    llvm::consumeError(CurLoc.takeError());1457    return {};1458  }1459 1460  const auto IncludeReferences =1461      maybeFindIncludeReferences(AST, Pos, URIMainFile);1462  if (IncludeReferences)1463    return *IncludeReferences;1464 1465  llvm::DenseSet<SymbolID> IDsToQuery, OverriddenMethods;1466 1467  const auto *IdentifierAtCursor =1468      syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());1469  std::optional<DefinedMacro> Macro;1470  if (IdentifierAtCursor)1471    Macro = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor());1472  if (Macro) {1473    // Handle references to macro.1474    if (auto MacroSID = getSymbolID(Macro->Name, Macro->Info, SM)) {1475      // Collect macro references from main file.1476      const auto &IDToRefs = AST.getMacros().MacroRefs;1477      auto Refs = IDToRefs.find(MacroSID);1478      if (Refs != IDToRefs.end()) {1479        for (const auto &Ref : Refs->second) {1480          ReferencesResult::Reference Result;1481          Result.Loc.range = Ref.toRange(SM);1482          Result.Loc.uri = URIMainFile;1483          if (Ref.IsDefinition) {1484            Result.Attributes |= ReferencesResult::Declaration;1485            Result.Attributes |= ReferencesResult::Definition;1486          }1487          Results.References.push_back(std::move(Result));1488        }1489      }1490      IDsToQuery.insert(MacroSID);1491    }1492  } else {1493    // Handle references to Decls.1494 1495    DeclRelationSet Relations =1496        DeclRelation::TemplatePattern | DeclRelation::Alias;1497    std::vector<const NamedDecl *> Decls =1498        getDeclAtPosition(AST, *CurLoc, Relations);1499    llvm::SmallVector<const NamedDecl *> TargetsInMainFile;1500    for (const NamedDecl *D : Decls) {1501      auto ID = getSymbolID(D);1502      if (!ID)1503        continue;1504      TargetsInMainFile.push_back(D);1505      // Not all symbols can be referenced from outside (e.g. function-locals).1506      // TODO: we could skip TU-scoped symbols here (e.g. static functions) if1507      // we know this file isn't a header. The details might be tricky.1508      if (D->getParentFunctionOrMethod())1509        continue;1510      IDsToQuery.insert(ID);1511    }1512 1513    RelationsRequest OverriddenBy;1514    if (Index) {1515      OverriddenBy.Predicate = RelationKind::OverriddenBy;1516      for (const NamedDecl *ND : Decls) {1517        // Special case: For virtual methods, report decl/def of overrides and1518        // references to all overridden methods in complete type hierarchy.1519        if (const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {1520          if (CMD->isVirtual()) {1521            if (auto ID = getSymbolID(CMD))1522              OverriddenBy.Subjects.insert(ID);1523            getOverriddenMethods(CMD, OverriddenMethods);1524          }1525        }1526        // Special case: Objective-C methods can override a parent class or1527        // protocol, we should be sure to report references to those.1528        if (const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(ND)) {1529          OverriddenBy.Subjects.insert(getSymbolID(OMD));1530          getOverriddenMethods(OMD, OverriddenMethods);1531        }1532      }1533    }1534 1535    // We traverse the AST to find references in the main file.1536    auto MainFileRefs = findRefs(TargetsInMainFile, AST, /*PerToken=*/false);1537    // We may get multiple refs with the same location and different Roles, as1538    // cross-reference is only interested in locations, we deduplicate them1539    // by the location to avoid emitting duplicated locations.1540    MainFileRefs.erase(llvm::unique(MainFileRefs,1541                                    [](const ReferenceFinder::Reference &L,1542                                       const ReferenceFinder::Reference &R) {1543                                      return L.SpelledTok.location() ==1544                                             R.SpelledTok.location();1545                                    }),1546                       MainFileRefs.end());1547    for (const auto &Ref : MainFileRefs) {1548      ReferencesResult::Reference Result;1549      Result.Loc.range = Ref.range(SM);1550      Result.Loc.uri = URIMainFile;1551      if (AddContext)1552        Result.Loc.containerName =1553            stringifyContainerForMainFileRef(Ref.Container);1554      if (Ref.Role & static_cast<unsigned>(index::SymbolRole::Declaration))1555        Result.Attributes |= ReferencesResult::Declaration;1556      // clang-index doesn't report definitions as declarations, but they are.1557      if (Ref.Role & static_cast<unsigned>(index::SymbolRole::Definition))1558        Result.Attributes |=1559            ReferencesResult::Definition | ReferencesResult::Declaration;1560      Results.References.push_back(std::move(Result));1561    }1562    // Add decl/def of overridding methods.1563    if (Index && !OverriddenBy.Subjects.empty()) {1564      LookupRequest ContainerLookup;1565      // Different overrides will always be contained in different classes, so1566      // we have a one-to-one mapping between SymbolID and index here, thus we1567      // don't need to use std::vector as the map's value type.1568      llvm::DenseMap<SymbolID, size_t> RefIndexForContainer;1569      Index->relations(OverriddenBy, [&](const SymbolID &Subject,1570                                         const Symbol &Object) {1571        if (Limit && Results.References.size() >= Limit) {1572          Results.HasMore = true;1573          return;1574        }1575        const auto LSPLocDecl =1576            toLSPLocation(Object.CanonicalDeclaration, MainFilePath);1577        const auto LSPLocDef = toLSPLocation(Object.Definition, MainFilePath);1578        if (LSPLocDecl && LSPLocDecl != LSPLocDef) {1579          ReferencesResult::Reference Result;1580          Result.Loc = {std::move(*LSPLocDecl), std::nullopt};1581          Result.Attributes =1582              ReferencesResult::Declaration | ReferencesResult::Override;1583          RefIndexForContainer.insert({Object.ID, Results.References.size()});1584          ContainerLookup.IDs.insert(Object.ID);1585          Results.References.push_back(std::move(Result));1586        }1587        if (LSPLocDef) {1588          ReferencesResult::Reference Result;1589          Result.Loc = {std::move(*LSPLocDef), std::nullopt};1590          Result.Attributes = ReferencesResult::Declaration |1591                              ReferencesResult::Definition |1592                              ReferencesResult::Override;1593          RefIndexForContainer.insert({Object.ID, Results.References.size()});1594          ContainerLookup.IDs.insert(Object.ID);1595          Results.References.push_back(std::move(Result));1596        }1597      });1598 1599      if (!ContainerLookup.IDs.empty() && AddContext)1600        Index->lookup(ContainerLookup, [&](const Symbol &Container) {1601          auto Ref = RefIndexForContainer.find(Container.ID);1602          assert(Ref != RefIndexForContainer.end());1603          Results.References[Ref->getSecond()].Loc.containerName =1604              Container.Scope.str() + Container.Name.str();1605        });1606    }1607  }1608  // Now query the index for references from other files.1609  auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs, bool AllowAttributes,1610                        bool AllowMainFileSymbols) {1611    if (IDs.empty() || !Index || Results.HasMore)1612      return;1613    RefsRequest Req;1614    Req.IDs = std::move(IDs);1615    if (Limit) {1616      if (Limit < Results.References.size()) {1617        // We've already filled our quota, still check the index to correctly1618        // return the `HasMore` info.1619        Req.Limit = 0;1620      } else {1621        // Query index only for the remaining size.1622        Req.Limit = Limit - Results.References.size();1623      }1624    }1625    LookupRequest ContainerLookup;1626    llvm::DenseMap<SymbolID, std::vector<size_t>> RefIndicesForContainer;1627    Results.HasMore |= Index->refs(Req, [&](const Ref &R) {1628      auto LSPLoc = toLSPLocation(R.Location, MainFilePath);1629      // Avoid indexed results for the main file - the AST is authoritative.1630      if (!LSPLoc ||1631          (!AllowMainFileSymbols && LSPLoc->uri.file() == MainFilePath))1632        return;1633      ReferencesResult::Reference Result;1634      Result.Loc = {std::move(*LSPLoc), std::nullopt};1635      if (AllowAttributes) {1636        if ((R.Kind & RefKind::Declaration) == RefKind::Declaration)1637          Result.Attributes |= ReferencesResult::Declaration;1638        // FIXME: our index should definitely store def | decl separately!1639        if ((R.Kind & RefKind::Definition) == RefKind::Definition)1640          Result.Attributes |=1641              ReferencesResult::Declaration | ReferencesResult::Definition;1642      }1643      if (AddContext) {1644        SymbolID Container = R.Container;1645        ContainerLookup.IDs.insert(Container);1646        RefIndicesForContainer[Container].push_back(Results.References.size());1647      }1648      Results.References.push_back(std::move(Result));1649    });1650 1651    if (!ContainerLookup.IDs.empty() && AddContext)1652      Index->lookup(ContainerLookup, [&](const Symbol &Container) {1653        auto Ref = RefIndicesForContainer.find(Container.ID);1654        assert(Ref != RefIndicesForContainer.end());1655        auto ContainerName = Container.Scope.str() + Container.Name.str();1656        for (auto I : Ref->getSecond()) {1657          Results.References[I].Loc.containerName = ContainerName;1658        }1659      });1660  };1661  QueryIndex(std::move(IDsToQuery), /*AllowAttributes=*/true,1662             /*AllowMainFileSymbols=*/false);1663  // For a virtual method: Occurrences of BaseMethod should be treated as refs1664  // and not as decl/def. Allow symbols from main file since AST does not report1665  // these.1666  QueryIndex(std::move(OverriddenMethods), /*AllowAttributes=*/false,1667             /*AllowMainFileSymbols=*/true);1668  return Results;1669}1670 1671std::vector<SymbolDetails> getSymbolInfo(ParsedAST &AST, Position Pos) {1672  const SourceManager &SM = AST.getSourceManager();1673  auto CurLoc = sourceLocationInMainFile(SM, Pos);1674  if (!CurLoc) {1675    llvm::consumeError(CurLoc.takeError());1676    return {};1677  }1678  auto MainFilePath = AST.tuPath();1679  std::vector<SymbolDetails> Results;1680 1681  // We also want the targets of using-decls, so we include1682  // DeclRelation::Underlying.1683  DeclRelationSet Relations = DeclRelation::TemplatePattern |1684                              DeclRelation::Alias | DeclRelation::Underlying;1685  for (const NamedDecl *D : getDeclAtPosition(AST, *CurLoc, Relations)) {1686    D = getPreferredDecl(D);1687 1688    SymbolDetails NewSymbol;1689    std::string QName = printQualifiedName(*D);1690    auto SplitQName = splitQualifiedName(QName);1691    NewSymbol.containerName = std::string(SplitQName.first);1692    NewSymbol.name = std::string(SplitQName.second);1693 1694    if (NewSymbol.containerName.empty()) {1695      if (const auto *ParentND =1696              dyn_cast_or_null<NamedDecl>(D->getDeclContext()))1697        NewSymbol.containerName = printQualifiedName(*ParentND);1698    }1699    llvm::SmallString<32> USR;1700    if (!index::generateUSRForDecl(D, USR)) {1701      NewSymbol.USR = std::string(USR);1702      NewSymbol.ID = SymbolID(NewSymbol.USR);1703    }1704    if (const NamedDecl *Def = getDefinition(D))1705      NewSymbol.definitionRange = makeLocation(1706          AST.getASTContext(), nameLocation(*Def, SM), MainFilePath);1707    NewSymbol.declarationRange =1708        makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath);1709 1710    Results.push_back(std::move(NewSymbol));1711  }1712 1713  const auto *IdentifierAtCursor =1714      syntax::spelledIdentifierTouching(*CurLoc, AST.getTokens());1715  if (!IdentifierAtCursor)1716    return Results;1717 1718  if (auto M = locateMacroAt(*IdentifierAtCursor, AST.getPreprocessor())) {1719    SymbolDetails NewMacro;1720    NewMacro.name = std::string(M->Name);1721    llvm::SmallString<32> USR;1722    if (!index::generateUSRForMacro(NewMacro.name, M->Info->getDefinitionLoc(),1723                                    SM, USR)) {1724      NewMacro.USR = std::string(USR);1725      NewMacro.ID = SymbolID(NewMacro.USR);1726    }1727    Results.push_back(std::move(NewMacro));1728  }1729 1730  return Results;1731}1732 1733llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const LocatedSymbol &S) {1734  OS << S.Name << ": " << S.PreferredDeclaration;1735  if (S.Definition)1736    OS << " def=" << *S.Definition;1737  return OS;1738}1739 1740llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,1741                              const ReferencesResult::Reference &R) {1742  OS << R.Loc;1743  if (R.Attributes & ReferencesResult::Declaration)1744    OS << " [decl]";1745  if (R.Attributes & ReferencesResult::Definition)1746    OS << " [def]";1747  if (R.Attributes & ReferencesResult::Override)1748    OS << " [override]";1749  return OS;1750}1751 1752template <typename HierarchyItem>1753static std::optional<HierarchyItem>1754declToHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {1755  ASTContext &Ctx = ND.getASTContext();1756  auto &SM = Ctx.getSourceManager();1757  SourceLocation NameLoc = nameLocation(ND, Ctx.getSourceManager());1758  SourceLocation BeginLoc = SM.getFileLoc(ND.getBeginLoc());1759  SourceLocation EndLoc = SM.getFileLoc(ND.getEndLoc());1760  const auto DeclRange =1761      toHalfOpenFileRange(SM, Ctx.getLangOpts(), {BeginLoc, EndLoc});1762  if (!DeclRange)1763    return std::nullopt;1764  const auto FE = SM.getFileEntryRefForID(SM.getFileID(NameLoc));1765  if (!FE)1766    return std::nullopt;1767  auto FilePath = getCanonicalPath(*FE, SM.getFileManager());1768  if (!FilePath)1769    return std::nullopt; // Not useful without a uri.1770 1771  Position NameBegin = sourceLocToPosition(SM, NameLoc);1772  Position NameEnd = sourceLocToPosition(1773      SM, Lexer::getLocForEndOfToken(NameLoc, 0, SM, Ctx.getLangOpts()));1774 1775  index::SymbolInfo SymInfo = index::getSymbolInfo(&ND);1776  // FIXME: This is not classifying constructors, destructors and operators1777  // correctly.1778  SymbolKind SK = indexSymbolKindToSymbolKind(SymInfo.Kind);1779 1780  HierarchyItem HI;1781  HI.name = printName(Ctx, ND);1782  // FIXME: Populate HI.detail the way we do in symbolToHierarchyItem?1783  HI.kind = SK;1784  HI.range = Range{sourceLocToPosition(SM, DeclRange->getBegin()),1785                   sourceLocToPosition(SM, DeclRange->getEnd())};1786  HI.selectionRange = Range{NameBegin, NameEnd};1787  if (!HI.range.contains(HI.selectionRange)) {1788    // 'selectionRange' must be contained in 'range', so in cases where clang1789    // reports unrelated ranges we need to reconcile somehow.1790    HI.range = HI.selectionRange;1791  }1792 1793  HI.uri = URIForFile::canonicalize(*FilePath, TUPath);1794 1795  return HI;1796}1797 1798static std::optional<TypeHierarchyItem>1799declToTypeHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {1800  auto Result = declToHierarchyItem<TypeHierarchyItem>(ND, TUPath);1801  if (Result) {1802    Result->deprecated = ND.isDeprecated();1803    // Compute the SymbolID and store it in the 'data' field.1804    // This allows typeHierarchy/resolve to be used to1805    // resolve children of items returned in a previous request1806    // for parents.1807    Result->data.symbolID = getSymbolID(&ND);1808  }1809  return Result;1810}1811 1812static std::optional<CallHierarchyItem>1813declToCallHierarchyItem(const NamedDecl &ND, llvm::StringRef TUPath) {1814  auto Result = declToHierarchyItem<CallHierarchyItem>(ND, TUPath);1815  if (!Result)1816    return Result;1817  if (ND.isDeprecated())1818    Result->tags.push_back(SymbolTag::Deprecated);1819  if (auto ID = getSymbolID(&ND))1820    Result->data = ID.str();1821  return Result;1822}1823 1824template <typename HierarchyItem>1825static std::optional<HierarchyItem> symbolToHierarchyItem(const Symbol &S,1826                                                          PathRef TUPath) {1827  auto Loc = symbolToLocation(S, TUPath);1828  if (!Loc) {1829    elog("Failed to convert symbol to hierarchy item: {0}", Loc.takeError());1830    return std::nullopt;1831  }1832  HierarchyItem HI;1833  HI.name = std::string(S.Name);1834  HI.detail = (S.Scope + S.Name).str();1835  HI.kind = indexSymbolKindToSymbolKind(S.SymInfo.Kind);1836  HI.selectionRange = Loc->range;1837  // FIXME: Populate 'range' correctly1838  // (https://github.com/clangd/clangd/issues/59).1839  HI.range = HI.selectionRange;1840  HI.uri = Loc->uri;1841 1842  return HI;1843}1844 1845static std::optional<TypeHierarchyItem>1846symbolToTypeHierarchyItem(const Symbol &S, PathRef TUPath) {1847  auto Result = symbolToHierarchyItem<TypeHierarchyItem>(S, TUPath);1848  if (Result) {1849    Result->deprecated = (S.Flags & Symbol::Deprecated);1850    Result->data.symbolID = S.ID;1851  }1852  return Result;1853}1854 1855static std::optional<CallHierarchyItem>1856symbolToCallHierarchyItem(const Symbol &S, PathRef TUPath) {1857  auto Result = symbolToHierarchyItem<CallHierarchyItem>(S, TUPath);1858  if (!Result)1859    return Result;1860  Result->data = S.ID.str();1861  if (S.Flags & Symbol::Deprecated)1862    Result->tags.push_back(SymbolTag::Deprecated);1863  return Result;1864}1865 1866static void fillSubTypes(const SymbolID &ID,1867                         std::vector<TypeHierarchyItem> &SubTypes,1868                         const SymbolIndex *Index, int Levels, PathRef TUPath) {1869  RelationsRequest Req;1870  Req.Subjects.insert(ID);1871  Req.Predicate = RelationKind::BaseOf;1872  Index->relations(Req, [&](const SymbolID &Subject, const Symbol &Object) {1873    if (std::optional<TypeHierarchyItem> ChildSym =1874            symbolToTypeHierarchyItem(Object, TUPath)) {1875      if (Levels > 1) {1876        ChildSym->children.emplace();1877        fillSubTypes(Object.ID, *ChildSym->children, Index, Levels - 1, TUPath);1878      }1879      SubTypes.emplace_back(std::move(*ChildSym));1880    }1881  });1882}1883 1884using RecursionProtectionSet = llvm::SmallPtrSet<const CXXRecordDecl *, 4>;1885 1886// Extracts parents from AST and populates the type hierarchy item.1887static void fillSuperTypes(const CXXRecordDecl &CXXRD, llvm::StringRef TUPath,1888                           TypeHierarchyItem &Item,1889                           RecursionProtectionSet &RPSet) {1890  Item.parents.emplace();1891  Item.data.parents.emplace();1892  // typeParents() will replace dependent template specializations1893  // with their class template, so to avoid infinite recursion for1894  // certain types of hierarchies, keep the templates encountered1895  // along the parent chain in a set, and stop the recursion if one1896  // starts to repeat.1897  auto *Pattern = CXXRD.getDescribedTemplate() ? &CXXRD : nullptr;1898  if (Pattern) {1899    if (!RPSet.insert(Pattern).second) {1900      return;1901    }1902  }1903 1904  for (const CXXRecordDecl *ParentDecl : typeParents(&CXXRD)) {1905    if (std::optional<TypeHierarchyItem> ParentSym =1906            declToTypeHierarchyItem(*ParentDecl, TUPath)) {1907      fillSuperTypes(*ParentDecl, TUPath, *ParentSym, RPSet);1908      Item.data.parents->emplace_back(ParentSym->data);1909      Item.parents->emplace_back(std::move(*ParentSym));1910    }1911  }1912 1913  if (Pattern) {1914    RPSet.erase(Pattern);1915  }1916}1917 1918std::vector<const CXXRecordDecl *> findRecordTypeAt(ParsedAST &AST,1919                                                    Position Pos) {1920  auto RecordFromNode = [&AST](const SelectionTree::Node *N) {1921    std::vector<const CXXRecordDecl *> Records;1922    if (!N)1923      return Records;1924 1925    // Note: explicitReferenceTargets() will search for both template1926    // instantiations and template patterns, and prefer the former if available1927    // (generally, one will be available for non-dependent specializations of a1928    // class template).1929    auto Decls = explicitReferenceTargets(N->ASTNode, DeclRelation::Underlying,1930                                          AST.getHeuristicResolver());1931    for (const NamedDecl *D : Decls) {1932 1933      if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {1934        // If this is a variable, use the type of the variable.1935        if (const auto *RD = VD->getType().getTypePtr()->getAsCXXRecordDecl())1936          Records.push_back(RD);1937        continue;1938      }1939 1940      if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {1941        // If this is a method, use the type of the class.1942        Records.push_back(Method->getParent());1943        continue;1944      }1945 1946      // We don't handle FieldDecl because it's not clear what behaviour1947      // the user would expect: the enclosing class type (as with a1948      // method), or the field's type (as with a variable).1949 1950      if (auto *RD = dyn_cast<CXXRecordDecl>(D))1951        Records.push_back(RD);1952    }1953    return Records;1954  };1955 1956  const SourceManager &SM = AST.getSourceManager();1957  std::vector<const CXXRecordDecl *> Result;1958  auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);1959  if (!Offset) {1960    llvm::consumeError(Offset.takeError());1961    return Result;1962  }1963  SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *Offset,1964                            *Offset, [&](SelectionTree ST) {1965                              Result = RecordFromNode(ST.commonAncestor());1966                              return !Result.empty();1967                            });1968  return Result;1969}1970 1971// Return the type most associated with an AST node.1972// This isn't precisely defined: we want "go to type" to do something useful.1973static QualType typeForNode(const ASTContext &Ctx, const HeuristicResolver *H,1974                            const SelectionTree::Node *N) {1975  // If we're looking at a namespace qualifier, walk up to what it's qualifying.1976  // (If we're pointing at a *class* inside a NNS, N will be a TypeLoc).1977  while (N && N->ASTNode.get<NestedNameSpecifierLoc>())1978    N = N->Parent;1979  if (!N)1980    return QualType();1981 1982  // If we're pointing at a type => return it.1983  if (const TypeLoc *TL = N->ASTNode.get<TypeLoc>()) {1984    if (llvm::isa<DeducedType>(TL->getTypePtr()))1985      if (auto Deduced = getDeducedType(1986              N->getDeclContext().getParentASTContext(), H, TL->getBeginLoc()))1987        return *Deduced;1988    // Exception: an alias => underlying type.1989    if (llvm::isa<TypedefType>(TL->getTypePtr()))1990      return TL->getTypePtr()->getLocallyUnqualifiedSingleStepDesugaredType();1991    return TL->getType();1992  }1993 1994  // Constructor initializers => the type of thing being initialized.1995  if (const auto *CCI = N->ASTNode.get<CXXCtorInitializer>()) {1996    if (const FieldDecl *FD = CCI->getAnyMember())1997      return FD->getType();1998    if (const Type *Base = CCI->getBaseClass())1999      return QualType(Base, 0);2000  }2001 2002  // Base specifier => the base type.2003  if (const auto *CBS = N->ASTNode.get<CXXBaseSpecifier>())2004    return CBS->getType();2005 2006  if (const Decl *D = N->ASTNode.get<Decl>()) {2007    struct Visitor : ConstDeclVisitor<Visitor, QualType> {2008      const ASTContext &Ctx;2009      Visitor(const ASTContext &Ctx) : Ctx(Ctx) {}2010 2011      QualType VisitValueDecl(const ValueDecl *D) { return D->getType(); }2012      // Declaration of a type => that type.2013      QualType VisitTypeDecl(const TypeDecl *D) {2014        return Ctx.getTypeDeclType(D);2015      }2016      // Exception: alias declaration => the underlying type, not the alias.2017      QualType VisitTypedefNameDecl(const TypedefNameDecl *D) {2018        return D->getUnderlyingType();2019      }2020      // Look inside templates.2021      QualType VisitTemplateDecl(const TemplateDecl *D) {2022        return Visit(D->getTemplatedDecl());2023      }2024    } V(Ctx);2025    return V.Visit(D);2026  }2027 2028  if (const Stmt *S = N->ASTNode.get<Stmt>()) {2029    struct Visitor : ConstStmtVisitor<Visitor, QualType> {2030      // Null-safe version of visit simplifies recursive calls below.2031      QualType type(const Stmt *S) { return S ? Visit(S) : QualType(); }2032 2033      // In general, expressions => type of expression.2034      QualType VisitExpr(const Expr *S) {2035        return S->IgnoreImplicitAsWritten()->getType();2036      }2037      QualType VisitMemberExpr(const MemberExpr *S) {2038        // The `foo` in `s.foo()` pretends not to have a real type!2039        if (S->getType()->isSpecificBuiltinType(BuiltinType::BoundMember))2040          return Expr::findBoundMemberType(S);2041        return VisitExpr(S);2042      }2043      // Exceptions for void expressions that operate on a type in some way.2044      QualType VisitCXXDeleteExpr(const CXXDeleteExpr *S) {2045        return S->getDestroyedType();2046      }2047      QualType VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) {2048        return S->getDestroyedType();2049      }2050      QualType VisitCXXThrowExpr(const CXXThrowExpr *S) {2051        return S->getSubExpr()->getType();2052      }2053      QualType VisitCoyieldExpr(const CoyieldExpr *S) {2054        return type(S->getOperand());2055      }2056      // Treat a designated initializer like a reference to the field.2057      QualType VisitDesignatedInitExpr(const DesignatedInitExpr *S) {2058        // In .foo.bar we want to jump to bar's type, so find *last* field.2059        for (auto &D : llvm::reverse(S->designators()))2060          if (D.isFieldDesignator())2061            if (const auto *FD = D.getFieldDecl())2062              return FD->getType();2063        return QualType();2064      }2065 2066      // Control flow statements that operate on data: use the data type.2067      QualType VisitSwitchStmt(const SwitchStmt *S) {2068        return type(S->getCond());2069      }2070      QualType VisitWhileStmt(const WhileStmt *S) { return type(S->getCond()); }2071      QualType VisitDoStmt(const DoStmt *S) { return type(S->getCond()); }2072      QualType VisitIfStmt(const IfStmt *S) { return type(S->getCond()); }2073      QualType VisitCaseStmt(const CaseStmt *S) { return type(S->getLHS()); }2074      QualType VisitCXXForRangeStmt(const CXXForRangeStmt *S) {2075        return S->getLoopVariable()->getType();2076      }2077      QualType VisitReturnStmt(const ReturnStmt *S) {2078        return type(S->getRetValue());2079      }2080      QualType VisitCoreturnStmt(const CoreturnStmt *S) {2081        return type(S->getOperand());2082      }2083      QualType VisitCXXCatchStmt(const CXXCatchStmt *S) {2084        return S->getCaughtType();2085      }2086      QualType VisitObjCAtThrowStmt(const ObjCAtThrowStmt *S) {2087        return type(S->getThrowExpr());2088      }2089      QualType VisitObjCAtCatchStmt(const ObjCAtCatchStmt *S) {2090        return S->getCatchParamDecl() ? S->getCatchParamDecl()->getType()2091                                      : QualType();2092      }2093    } V;2094    return V.Visit(S);2095  }2096 2097  return QualType();2098}2099 2100// Given a type targeted by the cursor, return one or more types that are more interesting2101// to target.2102static void unwrapFindType(2103    QualType T, const HeuristicResolver* H, llvm::SmallVector<QualType>& Out) {2104  if (T.isNull())2105    return;2106 2107  // If there's a specific type alias, point at that rather than unwrapping.2108  if (const auto* TDT = T->getAs<TypedefType>())2109    return Out.push_back(QualType(TDT, 0));2110 2111  // Pointers etc => pointee type.2112  if (const auto *PT = T->getAs<PointerType>())2113    return unwrapFindType(PT->getPointeeType(), H, Out);2114  if (const auto *RT = T->getAs<ReferenceType>())2115    return unwrapFindType(RT->getPointeeType(), H, Out);2116  if (const auto *AT = T->getAsArrayTypeUnsafe())2117    return unwrapFindType(AT->getElementType(), H, Out);2118 2119  // Function type => return type.2120  if (auto *FT = T->getAs<FunctionType>())2121    return unwrapFindType(FT->getReturnType(), H, Out);2122  if (auto *CRD = T->getAsCXXRecordDecl()) {2123    if (CRD->isLambda())2124      return unwrapFindType(CRD->getLambdaCallOperator()->getReturnType(), H,2125                            Out);2126    // FIXME: more cases we'd prefer the return type of the call operator?2127    //        std::function etc?2128  }2129 2130  // For smart pointer types, add the underlying type2131  if (H)2132    if (auto PointeeType = H->getPointeeType(T.getNonReferenceType());2133        !PointeeType.isNull()) {2134      unwrapFindType(PointeeType, H, Out);2135      return Out.push_back(T);2136    }2137 2138  return Out.push_back(T);2139}2140 2141// Convenience overload, to allow calling this without the out-parameter2142static llvm::SmallVector<QualType> unwrapFindType(2143    QualType T, const HeuristicResolver* H) {2144  llvm::SmallVector<QualType> Result;2145  unwrapFindType(T, H, Result);2146  return Result;2147}2148 2149std::vector<LocatedSymbol> findType(ParsedAST &AST, Position Pos,2150                                    const SymbolIndex *Index) {2151  const SourceManager &SM = AST.getSourceManager();2152  auto Offset = positionToOffset(SM.getBufferData(SM.getMainFileID()), Pos);2153  std::vector<LocatedSymbol> Result;2154  if (!Offset) {2155    elog("failed to convert position {0} for findTypes: {1}", Pos,2156         Offset.takeError());2157    return Result;2158  }2159  // The general scheme is: position -> AST node -> type -> declaration.2160  auto SymbolsFromNode =2161      [&](const SelectionTree::Node *N) -> std::vector<LocatedSymbol> {2162    std::vector<LocatedSymbol> LocatedSymbols;2163 2164    // NOTE: unwrapFindType might return duplicates for something like2165    // unique_ptr<unique_ptr<T>>. Let's *not* remove them, because it gives you some2166    // information about the type you may have not known before2167    // (since unique_ptr<unique_ptr<T>> != unique_ptr<T>).2168    for (const QualType &Type : unwrapFindType(2169             typeForNode(AST.getASTContext(), AST.getHeuristicResolver(), N),2170             AST.getHeuristicResolver()))2171      llvm::copy(locateSymbolForType(AST, Type, Index),2172                 std::back_inserter(LocatedSymbols));2173 2174    return LocatedSymbols;2175  };2176  SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), *Offset,2177                            *Offset, [&](SelectionTree ST) {2178                              Result = SymbolsFromNode(ST.commonAncestor());2179                              return !Result.empty();2180                            });2181  return Result;2182}2183 2184std::vector<const CXXRecordDecl *> typeParents(const CXXRecordDecl *CXXRD) {2185  std::vector<const CXXRecordDecl *> Result;2186 2187  // If this is an invalid instantiation, instantiation of the bases2188  // may not have succeeded, so fall back to the template pattern.2189  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD)) {2190    if (CTSD->isInvalidDecl())2191      CXXRD = CTSD->getSpecializedTemplate()->getTemplatedDecl();2192  }2193 2194  // Can't query bases without a definition.2195  if (!CXXRD->hasDefinition())2196    return Result;2197 2198  for (auto Base : CXXRD->bases()) {2199    const CXXRecordDecl *ParentDecl = nullptr;2200 2201    const Type *Type = Base.getType().getTypePtr();2202    if (const RecordType *RT = Type->getAs<RecordType>()) {2203      ParentDecl = RT->getAsCXXRecordDecl();2204    }2205 2206    if (!ParentDecl) {2207      // Handle a dependent base such as "Base<T>" by using the primary2208      // template.2209      if (const TemplateSpecializationType *TS =2210              Type->getAs<TemplateSpecializationType>()) {2211        TemplateName TN = TS->getTemplateName();2212        if (TemplateDecl *TD = TN.getAsTemplateDecl()) {2213          ParentDecl = dyn_cast<CXXRecordDecl>(TD->getTemplatedDecl());2214        }2215      }2216    }2217 2218    if (ParentDecl)2219      Result.push_back(ParentDecl);2220  }2221 2222  return Result;2223}2224 2225std::vector<TypeHierarchyItem>2226getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels,2227                 TypeHierarchyDirection Direction, const SymbolIndex *Index,2228                 PathRef TUPath) {2229  std::vector<TypeHierarchyItem> Results;2230  for (const auto *CXXRD : findRecordTypeAt(AST, Pos)) {2231 2232    bool WantChildren = Direction == TypeHierarchyDirection::Children ||2233                        Direction == TypeHierarchyDirection::Both;2234 2235    // If we're looking for children, we're doing the lookup in the index.2236    // The index does not store relationships between implicit2237    // specializations, so if we have one, use the template pattern instead.2238    // Note that this needs to be done before the declToTypeHierarchyItem(),2239    // otherwise the type hierarchy item would misleadingly contain the2240    // specialization parameters, while the children would involve classes2241    // that derive from other specializations of the template.2242    if (WantChildren) {2243      if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(CXXRD))2244        CXXRD = CTSD->getTemplateInstantiationPattern();2245    }2246 2247    std::optional<TypeHierarchyItem> Result =2248        declToTypeHierarchyItem(*CXXRD, AST.tuPath());2249    if (!Result)2250      continue;2251 2252    RecursionProtectionSet RPSet;2253    fillSuperTypes(*CXXRD, AST.tuPath(), *Result, RPSet);2254 2255    if (WantChildren && ResolveLevels > 0) {2256      Result->children.emplace();2257 2258      if (Index) {2259        if (auto ID = getSymbolID(CXXRD))2260          fillSubTypes(ID, *Result->children, Index, ResolveLevels, TUPath);2261      }2262    }2263    Results.emplace_back(std::move(*Result));2264  }2265 2266  return Results;2267}2268 2269std::optional<std::vector<TypeHierarchyItem>>2270superTypes(const TypeHierarchyItem &Item, const SymbolIndex *Index) {2271  std::vector<TypeHierarchyItem> Results;2272  if (!Item.data.parents)2273    return std::nullopt;2274  if (Item.data.parents->empty())2275    return Results;2276  LookupRequest Req;2277  llvm::DenseMap<SymbolID, const TypeHierarchyItem::ResolveParams *> IDToData;2278  for (const auto &Parent : *Item.data.parents) {2279    Req.IDs.insert(Parent.symbolID);2280    IDToData[Parent.symbolID] = &Parent;2281  }2282  Index->lookup(Req, [&Item, &Results, &IDToData](const Symbol &S) {2283    if (auto THI = symbolToTypeHierarchyItem(S, Item.uri.file())) {2284      THI->data = *IDToData.lookup(S.ID);2285      Results.emplace_back(std::move(*THI));2286    }2287  });2288  return Results;2289}2290 2291std::vector<TypeHierarchyItem> subTypes(const TypeHierarchyItem &Item,2292                                        const SymbolIndex *Index) {2293  std::vector<TypeHierarchyItem> Results;2294  fillSubTypes(Item.data.symbolID, Results, Index, 1, Item.uri.file());2295  for (auto &ChildSym : Results)2296    ChildSym.data.parents = {Item.data};2297  return Results;2298}2299 2300void resolveTypeHierarchy(TypeHierarchyItem &Item, int ResolveLevels,2301                          TypeHierarchyDirection Direction,2302                          const SymbolIndex *Index) {2303  // We only support typeHierarchy/resolve for children, because for parents2304  // we ignore ResolveLevels and return all levels of parents eagerly.2305  if (!Index || Direction == TypeHierarchyDirection::Parents ||2306      ResolveLevels == 0)2307    return;2308 2309  Item.children.emplace();2310  fillSubTypes(Item.data.symbolID, *Item.children, Index, ResolveLevels,2311               Item.uri.file());2312}2313 2314std::vector<CallHierarchyItem>2315prepareCallHierarchy(ParsedAST &AST, Position Pos, PathRef TUPath) {2316  std::vector<CallHierarchyItem> Result;2317  const auto &SM = AST.getSourceManager();2318  auto Loc = sourceLocationInMainFile(SM, Pos);2319  if (!Loc) {2320    elog("prepareCallHierarchy failed to convert position to source location: "2321         "{0}",2322         Loc.takeError());2323    return Result;2324  }2325  for (const NamedDecl *Decl : getDeclAtPosition(AST, *Loc, {})) {2326    if (!(isa<DeclContext>(Decl) &&2327          cast<DeclContext>(Decl)->isFunctionOrMethod()) &&2328        Decl->getKind() != Decl::Kind::FunctionTemplate &&2329        !(Decl->getKind() == Decl::Kind::Var &&2330          !cast<VarDecl>(Decl)->isLocalVarDecl()) &&2331        Decl->getKind() != Decl::Kind::Field &&2332        Decl->getKind() != Decl::Kind::EnumConstant)2333      continue;2334    if (auto CHI = declToCallHierarchyItem(*Decl, AST.tuPath()))2335      Result.emplace_back(std::move(*CHI));2336  }2337  return Result;2338}2339 2340std::vector<CallHierarchyIncomingCall>2341incomingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {2342  std::vector<CallHierarchyIncomingCall> Results;2343  if (!Index || Item.data.empty())2344    return Results;2345  auto ID = SymbolID::fromStr(Item.data);2346  if (!ID) {2347    elog("incomingCalls failed to find symbol: {0}", ID.takeError());2348    return Results;2349  }2350  // In this function, we find incoming calls based on the index only.2351  // In principle, the AST could have more up-to-date information about2352  // occurrences within the current file. However, going from a SymbolID2353  // to an AST node isn't cheap, particularly when the declaration isn't2354  // in the main file.2355  // FIXME: Consider also using AST information when feasible.2356  auto QueryIndex = [&](llvm::DenseSet<SymbolID> IDs, bool MightNeverCall) {2357    RefsRequest Request;2358    Request.IDs = std::move(IDs);2359    Request.WantContainer = true;2360    // We could restrict more specifically to calls by introducing a new2361    // RefKind, but non-call references (such as address-of-function) can still2362    // be interesting as they can indicate indirect calls.2363    Request.Filter = RefKind::Reference;2364    // Initially store the ranges in a map keyed by SymbolID of the caller.2365    // This allows us to group different calls with the same caller2366    // into the same CallHierarchyIncomingCall.2367    llvm::DenseMap<SymbolID, std::vector<Location>> CallsIn;2368    // We can populate the ranges based on a refs request only. As we do so, we2369    // also accumulate the container IDs into a lookup request.2370    LookupRequest ContainerLookup;2371    Index->refs(Request, [&](const Ref &R) {2372      auto Loc = indexToLSPLocation(R.Location, Item.uri.file());2373      if (!Loc) {2374        elog("incomingCalls failed to convert location: {0}", Loc.takeError());2375        return;2376      }2377      CallsIn[R.Container].push_back(*Loc);2378 2379      ContainerLookup.IDs.insert(R.Container);2380    });2381    // Perform the lookup request and combine its results with CallsIn to2382    // get complete CallHierarchyIncomingCall objects.2383    Index->lookup(ContainerLookup, [&](const Symbol &Caller) {2384      auto It = CallsIn.find(Caller.ID);2385      assert(It != CallsIn.end());2386      if (auto CHI = symbolToCallHierarchyItem(Caller, Item.uri.file())) {2387        std::vector<Range> FromRanges;2388        for (const Location &L : It->second) {2389          if (L.uri != CHI->uri) {2390            // Call location not in same file as caller.2391            // This can happen in some edge cases. There's not much we can do,2392            // since the protocol only allows returning ranges interpreted as2393            // being in the caller's file.2394            continue;2395          }2396          FromRanges.push_back(L.range);2397        }2398        Results.push_back(CallHierarchyIncomingCall{2399            std::move(*CHI), std::move(FromRanges), MightNeverCall});2400      }2401    });2402  };2403  QueryIndex({ID.get()}, false);2404  // In the case of being a virtual function we also want to return2405  // potential calls through the base function.2406  if (Item.kind == SymbolKind::Method) {2407    llvm::DenseSet<SymbolID> IDs;2408    RelationsRequest Req{{ID.get()}, RelationKind::OverriddenBy, std::nullopt};2409    Index->reverseRelations(Req, [&](const SymbolID &, const Symbol &Caller) {2410      IDs.insert(Caller.ID);2411    });2412    QueryIndex(std::move(IDs), true);2413  }2414  // Sort results by name of container.2415  llvm::sort(Results, [](const CallHierarchyIncomingCall &A,2416                         const CallHierarchyIncomingCall &B) {2417    return A.from.name < B.from.name;2418  });2419  return Results;2420}2421 2422std::vector<CallHierarchyOutgoingCall>2423outgoingCalls(const CallHierarchyItem &Item, const SymbolIndex *Index) {2424  std::vector<CallHierarchyOutgoingCall> Results;2425  if (!Index || Item.data.empty())2426    return Results;2427  auto ID = SymbolID::fromStr(Item.data);2428  if (!ID) {2429    elog("outgoingCalls failed to find symbol: {0}", ID.takeError());2430    return Results;2431  }2432  // In this function, we find outgoing calls based on the index only.2433  ContainedRefsRequest Request;2434  Request.ID = *ID;2435  // Initially store the ranges in a map keyed by SymbolID of the callee.2436  // This allows us to group different calls to the same function2437  // into the same CallHierarchyOutgoingCall.2438  llvm::DenseMap<SymbolID, std::vector<Location>> CallsOut;2439  // We can populate the ranges based on a refs request only. As we do so, we2440  // also accumulate the callee IDs into a lookup request.2441  LookupRequest CallsOutLookup;2442  Index->containedRefs(Request, [&](const auto &R) {2443    auto Loc = indexToLSPLocation(R.Location, Item.uri.file());2444    if (!Loc) {2445      elog("outgoingCalls failed to convert location: {0}", Loc.takeError());2446      return;2447    }2448    auto It = CallsOut.try_emplace(R.Symbol, std::vector<Location>{}).first;2449    It->second.push_back(*Loc);2450 2451    CallsOutLookup.IDs.insert(R.Symbol);2452  });2453  // Perform the lookup request and combine its results with CallsOut to2454  // get complete CallHierarchyOutgoingCall objects.2455  Index->lookup(CallsOutLookup, [&](const Symbol &Callee) {2456    // The containedRefs request should only return symbols which are2457    // function-like, i.e. symbols for which references to them can be "calls".2458    using SK = index::SymbolKind;2459    auto Kind = Callee.SymInfo.Kind;2460    assert(Kind == SK::Function || Kind == SK::InstanceMethod ||2461           Kind == SK::ClassMethod || Kind == SK::StaticMethod ||2462           Kind == SK::Constructor || Kind == SK::Destructor ||2463           Kind == SK::ConversionFunction);2464    (void)Kind;2465    (void)SK::Function;2466 2467    auto It = CallsOut.find(Callee.ID);2468    assert(It != CallsOut.end());2469    if (auto CHI = symbolToCallHierarchyItem(Callee, Item.uri.file())) {2470      std::vector<Range> FromRanges;2471      for (const Location &L : It->second) {2472        if (L.uri != Item.uri) {2473          // Call location not in same file as the item that outgoingCalls was2474          // requested for. This can happen when Item is a declaration separate2475          // from the implementation. There's not much we can do, since the2476          // protocol only allows returning ranges interpreted as being in2477          // Item's file.2478          continue;2479        }2480        FromRanges.push_back(L.range);2481      }2482      Results.push_back(2483          CallHierarchyOutgoingCall{std::move(*CHI), std::move(FromRanges)});2484    }2485  });2486  // Sort results by name of the callee.2487  llvm::sort(Results, [](const CallHierarchyOutgoingCall &A,2488                         const CallHierarchyOutgoingCall &B) {2489    return A.to.name < B.to.name;2490  });2491  return Results;2492}2493 2494llvm::DenseSet<const Decl *> getNonLocalDeclRefs(ParsedAST &AST,2495                                                 const FunctionDecl *FD) {2496  if (!FD->hasBody())2497    return {};2498  llvm::DenseSet<const Decl *> DeclRefs;2499  findExplicitReferences(2500      FD,2501      [&](ReferenceLoc Ref) {2502        for (const Decl *D : Ref.Targets) {2503          if (!index::isFunctionLocalSymbol(D) && !D->isTemplateParameter() &&2504              !Ref.IsDecl)2505            DeclRefs.insert(D);2506        }2507      },2508      AST.getHeuristicResolver());2509  return DeclRefs;2510}2511 2512} // namespace clangd2513} // namespace clang2514