brintos

brintos / llvm-project-archived public Read only

0
0
Text · 46.3 KiB · 39c479b Raw
1220 lines · cpp
1//===--- SymbolCollector.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 9#include "SymbolCollector.h"10#include "AST.h"11#include "CodeComplete.h"12#include "CodeCompletionStrings.h"13#include "ExpectedTypes.h"14#include "SourceCode.h"15#include "URI.h"16#include "clang-include-cleaner/Analysis.h"17#include "clang-include-cleaner/IncludeSpeller.h"18#include "clang-include-cleaner/Record.h"19#include "clang-include-cleaner/Types.h"20#include "index/CanonicalIncludes.h"21#include "index/Ref.h"22#include "index/Relation.h"23#include "index/Symbol.h"24#include "index/SymbolID.h"25#include "index/SymbolLocation.h"26#include "clang/AST/Decl.h"27#include "clang/AST/DeclBase.h"28#include "clang/AST/DeclObjC.h"29#include "clang/AST/DeclTemplate.h"30#include "clang/AST/DeclarationName.h"31#include "clang/AST/Expr.h"32#include "clang/Basic/FileEntry.h"33#include "clang/Basic/LangOptions.h"34#include "clang/Basic/SourceLocation.h"35#include "clang/Basic/SourceManager.h"36#include "clang/Index/IndexSymbol.h"37#include "clang/Lex/Preprocessor.h"38#include "clang/Lex/Token.h"39#include "clang/Tooling/Inclusions/HeaderAnalysis.h"40#include "clang/Tooling/Inclusions/StandardLibrary.h"41#include "llvm/ADT/ArrayRef.h"42#include "llvm/ADT/DenseMap.h"43#include "llvm/ADT/SmallVector.h"44#include "llvm/ADT/StringRef.h"45#include "llvm/Support/Casting.h"46#include "llvm/Support/ErrorHandling.h"47#include "llvm/Support/FileSystem.h"48#include "llvm/Support/Path.h"49#include <cassert>50#include <memory>51#include <optional>52#include <string>53#include <utility>54 55namespace clang {56namespace clangd {57namespace {58 59/// If \p ND is a template specialization, returns the described template.60/// Otherwise, returns \p ND.61const NamedDecl &getTemplateOrThis(const NamedDecl &ND) {62  if (auto *T = ND.getDescribedTemplate())63    return *T;64  return ND;65}66 67// Checks whether the decl is a private symbol in a header generated by68// protobuf compiler.69// FIXME: make filtering extensible when there are more use cases for symbol70// filters.71bool isPrivateProtoDecl(const NamedDecl &ND) {72  const auto &SM = ND.getASTContext().getSourceManager();73  if (!isProtoFile(nameLocation(ND, SM), SM))74    return false;75 76  // ND without identifier can be operators.77  if (ND.getIdentifier() == nullptr)78    return false;79  auto Name = ND.getIdentifier()->getName();80  // There are some internal helpers like _internal_set_foo();81  if (Name.contains("_internal_"))82    return true;83 84  // https://protobuf.dev/reference/cpp/cpp-generated/#nested-types85  // Nested entities (messages/enums) has two names, one at the top-level scope,86  // with a mangled name created by prepending all the outer types. These names87  // are almost never preferred by the developers, so exclude them from index.88  // e.g.89  //   message Foo {90  //    message Bar {}91  //    enum E { A }92  //   }93  //94  // yields:95  //   class Foo_Bar {};96  //   enum Foo_E { Foo_E_A };97  //   class Foo {98  //    using Bar = Foo_Bar;99  //    static constexpr Foo_E A = Foo_E_A;100  //   };101 102  // We get rid of Foo_Bar and Foo_E by discarding any top-level entries with103  // `_` in the name. This relies on original message/enum not having `_` in the104  // name. Hence might go wrong in certain cases.105  if (ND.getDeclContext()->isNamespace()) {106    // Strip off some known public suffix helpers for enums, rest of the helpers107    // are generated inside record decls so we don't care.108    // https://protobuf.dev/reference/cpp/cpp-generated/#enum109    Name.consume_back("_descriptor");110    Name.consume_back("_IsValid");111    Name.consume_back("_Name");112    Name.consume_back("_Parse");113    Name.consume_back("_MIN");114    Name.consume_back("_MAX");115    Name.consume_back("_ARRAYSIZE");116    return Name.contains('_');117  }118 119  // EnumConstantDecls need some special attention, despite being nested in a120  // TagDecl, they might still have mangled names. We filter those by checking121  // if it has parent's name as a prefix.122  // This might go wrong if a nested entity has a name that starts with parent's123  // name, e.g: enum Foo { Foo_X }.124  if (llvm::isa<EnumConstantDecl>(&ND)) {125    auto *DC = llvm::cast<EnumDecl>(ND.getDeclContext());126    if (!DC || !DC->getIdentifier())127      return false;128    auto CtxName = DC->getIdentifier()->getName();129    return !CtxName.empty() && Name.consume_front(CtxName) &&130           Name.consume_front("_");131  }132 133  // Now we're only left with fields/methods without an `_internal_` in the134  // name, they're intended for public use.135  return false;136}137 138// We only collect #include paths for symbols that are suitable for global code139// completion, except for namespaces since #include path for a namespace is hard140// to define.141Symbol::IncludeDirective shouldCollectIncludePath(index::SymbolKind Kind) {142  using SK = index::SymbolKind;143  switch (Kind) {144  case SK::Macro:145  case SK::Enum:146  case SK::Struct:147  case SK::Class:148  case SK::Union:149  case SK::TypeAlias:150  case SK::Using:151  case SK::Function:152  case SK::Variable:153  case SK::EnumConstant:154  case SK::Concept:155    return Symbol::Include | Symbol::Import;156  case SK::Protocol:157    return Symbol::Import;158  default:159    return Symbol::Invalid;160  }161}162 163// Return the symbol range of the token at \p TokLoc.164std::pair<SymbolLocation::Position, SymbolLocation::Position>165getTokenRange(SourceLocation TokLoc, const SourceManager &SM,166              const LangOptions &LangOpts) {167  auto CreatePosition = [&SM](SourceLocation Loc) {168    auto LSPLoc = sourceLocToPosition(SM, Loc);169    SymbolLocation::Position Pos;170    Pos.setLine(LSPLoc.line);171    Pos.setColumn(LSPLoc.character);172    return Pos;173  };174 175  auto TokenLength = clang::Lexer::MeasureTokenLength(TokLoc, SM, LangOpts);176  return {CreatePosition(TokLoc),177          CreatePosition(TokLoc.getLocWithOffset(TokenLength))};178}179 180// Checks whether \p ND is a good candidate to be the *canonical* declaration of181// its symbol (e.g. a go-to-declaration target). This overrides the default of182// using Clang's canonical declaration, which is the first in the TU.183//184// Example: preferring a class declaration over its forward declaration.185bool isPreferredDeclaration(const NamedDecl &ND, index::SymbolRoleSet Roles) {186  const auto &SM = ND.getASTContext().getSourceManager();187  if (isa<TagDecl>(ND))188    return (Roles & static_cast<unsigned>(index::SymbolRole::Definition)) &&189           !isInsideMainFile(ND.getLocation(), SM);190  if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(&ND))191    return ID->isThisDeclarationADefinition();192  if (const auto *PD = dyn_cast<ObjCProtocolDecl>(&ND))193    return PD->isThisDeclarationADefinition();194  return false;195}196 197RefKind toRefKind(index::SymbolRoleSet Roles, bool Spelled = false) {198  RefKind Result = RefKind::Unknown;199  if (Roles & static_cast<unsigned>(index::SymbolRole::Declaration))200    Result |= RefKind::Declaration;201  if (Roles & static_cast<unsigned>(index::SymbolRole::Definition))202    Result |= RefKind::Definition;203  if (Roles & static_cast<unsigned>(index::SymbolRole::Reference))204    Result |= RefKind::Reference;205  if (Spelled)206    Result |= RefKind::Spelled;207  return Result;208}209 210std::optional<RelationKind> indexableRelation(const index::SymbolRelation &R) {211  if (R.Roles & static_cast<unsigned>(index::SymbolRole::RelationBaseOf))212    return RelationKind::BaseOf;213  if (R.Roles & static_cast<unsigned>(index::SymbolRole::RelationOverrideOf))214    return RelationKind::OverriddenBy;215  return std::nullopt;216}217 218// Check if there is an exact spelling of \p ND at \p Loc.219bool isSpelled(SourceLocation Loc, const NamedDecl &ND) {220  auto Name = ND.getDeclName();221  const auto NameKind = Name.getNameKind();222  if (NameKind != DeclarationName::Identifier &&223      NameKind != DeclarationName::CXXConstructorName &&224      NameKind != DeclarationName::ObjCZeroArgSelector &&225      NameKind != DeclarationName::ObjCOneArgSelector &&226      NameKind != DeclarationName::ObjCMultiArgSelector)227    return false;228  const auto &AST = ND.getASTContext();229  const auto &SM = AST.getSourceManager();230  const auto &LO = AST.getLangOpts();231  clang::Token Tok;232  if (clang::Lexer::getRawToken(Loc, Tok, SM, LO))233    return false;234  auto TokSpelling = clang::Lexer::getSpelling(Tok, SM, LO);235  if (const auto *MD = dyn_cast<ObjCMethodDecl>(&ND))236    return TokSpelling == MD->getSelector().getNameForSlot(0);237  return TokSpelling == Name.getAsString();238}239} // namespace240 241// Encapsulates decisions about how to record header paths in the index,242// including filename normalization, URI conversion etc.243// Expensive checks are cached internally.244class SymbolCollector::HeaderFileURICache {245  struct FrameworkUmbrellaSpelling {246    // Spelling for the public umbrella header, e.g. <Foundation/Foundation.h>247    std::optional<std::string> PublicHeader;248    // Spelling for the private umbrella header, e.g.249    // <Foundation/Foundation_Private.h>250    std::optional<std::string> PrivateHeader;251  };252  // Weird double-indirect access to PP, which might not be ready yet when253  // HeaderFiles is created but will be by the time it's used.254  // (IndexDataConsumer::setPreprocessor can happen before or after initialize)255  Preprocessor *&PP;256  const SourceManager &SM;257  const include_cleaner::PragmaIncludes *PI;258  llvm::StringRef FallbackDir;259  llvm::DenseMap<const FileEntry *, const std::string *> CacheFEToURI;260  llvm::StringMap<std::string> CachePathToURI;261  llvm::DenseMap<FileID, llvm::StringRef> CacheFIDToInclude;262  llvm::StringMap<std::string> CachePathToFrameworkSpelling;263  llvm::StringMap<FrameworkUmbrellaSpelling>264      CacheFrameworkToUmbrellaHeaderSpelling;265 266public:267  HeaderFileURICache(Preprocessor *&PP, const SourceManager &SM,268                     const SymbolCollector::Options &Opts)269      : PP(PP), SM(SM), PI(Opts.PragmaIncludes), FallbackDir(Opts.FallbackDir) {270  }271 272  // Returns a canonical URI for the file \p FE.273  // We attempt to make the path absolute first.274  const std::string &toURI(const FileEntryRef FE) {275    auto R = CacheFEToURI.try_emplace(FE);276    if (R.second) {277      auto CanonPath = getCanonicalPath(FE, SM.getFileManager());278      R.first->second = &toURIInternal(CanonPath ? *CanonPath : FE.getName());279    }280    return *R.first->second;281  }282 283  // Returns a canonical URI for \p Path.284  // If the file is in the FileManager, use that to canonicalize the path.285  // We attempt to make the path absolute in any case.286  const std::string &toURI(llvm::StringRef Path) {287    if (auto File = SM.getFileManager().getFileRef(Path))288      return toURI(*File);289    return toURIInternal(Path);290  }291 292  // Gets a canonical include (URI of the header or <header> or "header") for293  // header of \p FID (which should usually be the *expansion* file).294  // This does not account for any per-symbol overrides!295  // Returns "" if includes should not be inserted for this file.296  llvm::StringRef getIncludeHeader(FileID FID) {297    auto R = CacheFIDToInclude.try_emplace(FID);298    if (R.second)299      R.first->second = getIncludeHeaderUncached(FID);300    return R.first->second;301  }302 303  // If a file is mapped by canonical headers, use that mapping, regardless304  // of whether it's an otherwise-good header (header guards etc).305  llvm::StringRef mapCanonical(llvm::StringRef HeaderPath) {306    if (!PP)307      return "";308    // Populate the system header mapping as late as possible to309    // ensure the preprocessor has been set already.310    CanonicalIncludes SysHeaderMapping;311    SysHeaderMapping.addSystemHeadersMapping(PP->getLangOpts());312    auto Canonical = SysHeaderMapping.mapHeader(HeaderPath);313    if (Canonical.empty())314      return "";315    // If we had a mapping, always use it.316    assert(Canonical.starts_with("<") || Canonical.starts_with("\""));317    return Canonical;318  }319 320private:321  // This takes care of making paths absolute and path->URI caching, but no322  // FileManager-based canonicalization.323  const std::string &toURIInternal(llvm::StringRef Path) {324    auto R = CachePathToURI.try_emplace(Path);325    if (R.second) {326      llvm::SmallString<256> AbsPath = Path;327      if (!llvm::sys::path::is_absolute(AbsPath) && !FallbackDir.empty())328        llvm::sys::path::make_absolute(FallbackDir, AbsPath);329      assert(llvm::sys::path::is_absolute(AbsPath) &&330             "If the VFS can't make paths absolute, a FallbackDir must be "331             "provided");332      llvm::sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true);333      R.first->second = URI::create(AbsPath).toString();334    }335    return R.first->second;336  }337 338  struct FrameworkHeaderPath {339    // Path to the frameworks directory containing the .framework directory.340    llvm::StringRef FrameworkParentDir;341    // Name of the framework.342    llvm::StringRef FrameworkName;343    // Subpath relative to the Headers or PrivateHeaders dir, e.g. NSObject.h344    // Note: This is NOT relative to the `HeadersParentDir`.345    llvm::StringRef HeaderSubpath;346    // Whether this header is under the PrivateHeaders dir347    bool IsPrivateHeader;348  };349 350  std::optional<FrameworkHeaderPath>351  splitFrameworkHeaderPath(llvm::StringRef Path) {352    using namespace llvm::sys;353    path::reverse_iterator I = path::rbegin(Path);354    path::reverse_iterator Prev = I;355    path::reverse_iterator E = path::rend(Path);356    FrameworkHeaderPath HeaderPath;357    while (I != E) {358      if (*I == "Headers" || *I == "PrivateHeaders") {359        HeaderPath.HeaderSubpath = Path.substr(Prev - E);360        HeaderPath.IsPrivateHeader = *I == "PrivateHeaders";361        if (++I == E)362          break;363        HeaderPath.FrameworkName = *I;364        if (!HeaderPath.FrameworkName.consume_back(".framework"))365          break;366        HeaderPath.FrameworkParentDir = Path.substr(0, I - E);367        return HeaderPath;368      }369      Prev = I;370      ++I;371    }372    // Unexpected, must not be a framework header.373    return std::nullopt;374  }375 376  // Frameworks typically have an umbrella header of the same name, e.g.377  // <Foundation/Foundation.h> instead of <Foundation/NSObject.h> or378  // <Foundation/Foundation_Private.h> instead of379  // <Foundation/NSObject_Private.h> which should be used instead of directly380  // importing the header.381  std::optional<std::string>382  getFrameworkUmbrellaSpelling(const HeaderSearch &HS,383                               FrameworkHeaderPath &HeaderPath) {384    StringRef Framework = HeaderPath.FrameworkName;385    auto Res = CacheFrameworkToUmbrellaHeaderSpelling.try_emplace(Framework);386    auto *CachedSpelling = &Res.first->second;387    if (!Res.second) {388      return HeaderPath.IsPrivateHeader ? CachedSpelling->PrivateHeader389                                        : CachedSpelling->PublicHeader;390    }391    SmallString<256> UmbrellaPath(HeaderPath.FrameworkParentDir);392    llvm::sys::path::append(UmbrellaPath, Framework + ".framework", "Headers",393                            Framework + ".h");394 395    llvm::vfs::Status Status;396    auto StatErr = HS.getFileMgr().getNoncachedStatValue(UmbrellaPath, Status);397    if (!StatErr)398      CachedSpelling->PublicHeader = llvm::formatv("<{0}/{0}.h>", Framework);399 400    UmbrellaPath = HeaderPath.FrameworkParentDir;401    llvm::sys::path::append(UmbrellaPath, Framework + ".framework",402                            "PrivateHeaders", Framework + "_Private.h");403 404    StatErr = HS.getFileMgr().getNoncachedStatValue(UmbrellaPath, Status);405    if (!StatErr)406      CachedSpelling->PrivateHeader =407          llvm::formatv("<{0}/{0}_Private.h>", Framework);408 409    return HeaderPath.IsPrivateHeader ? CachedSpelling->PrivateHeader410                                      : CachedSpelling->PublicHeader;411  }412 413  // Compute the framework include spelling for `FE` which is in a framework414  // named `Framework`, e.g. `NSObject.h` in framework `Foundation` would415  // give <Foundation/Foundation.h> if the umbrella header exists, otherwise416  // <Foundation/NSObject.h>.417  std::optional<llvm::StringRef>418  getFrameworkHeaderIncludeSpelling(FileEntryRef FE, HeaderSearch &HS) {419    auto Res = CachePathToFrameworkSpelling.try_emplace(FE.getName());420    auto *CachedHeaderSpelling = &Res.first->second;421    if (!Res.second)422      return llvm::StringRef(*CachedHeaderSpelling);423 424    auto HeaderPath = splitFrameworkHeaderPath(FE.getName());425    if (!HeaderPath) {426      // Unexpected: must not be a proper framework header, don't cache the427      // failure.428      CachePathToFrameworkSpelling.erase(Res.first);429      return std::nullopt;430    }431    if (auto UmbrellaSpelling =432            getFrameworkUmbrellaSpelling(HS, *HeaderPath)) {433      *CachedHeaderSpelling = *UmbrellaSpelling;434      return llvm::StringRef(*CachedHeaderSpelling);435    }436 437    *CachedHeaderSpelling =438        llvm::formatv("<{0}/{1}>", HeaderPath->FrameworkName,439                      HeaderPath->HeaderSubpath)440            .str();441    return llvm::StringRef(*CachedHeaderSpelling);442  }443 444  llvm::StringRef getIncludeHeaderUncached(FileID FID) {445    const auto FE = SM.getFileEntryRefForID(FID);446    if (!FE || FE->getName().empty())447      return "";448 449    if (auto Verbatim = PI->getPublic(*FE); !Verbatim.empty())450      return Verbatim;451 452    llvm::StringRef Filename = FE->getName();453    if (auto Canonical = mapCanonical(Filename); !Canonical.empty())454      return Canonical;455 456    // Framework headers are spelled as <FrameworkName/Foo.h>, not457    // "path/FrameworkName.framework/Headers/Foo.h".458    auto &HS = PP->getHeaderSearchInfo();459    if (auto Spelling = getFrameworkHeaderIncludeSpelling(*FE, HS))460      return *Spelling;461 462    if (!tooling::isSelfContainedHeader(*FE, PP->getSourceManager(),463                                        PP->getHeaderSearchInfo())) {464      // A .inc or .def file is often included into a real header to define465      // symbols (e.g. LLVM tablegen files).466      if (Filename.ends_with(".inc") || Filename.ends_with(".def"))467        // Don't use cache reentrantly due to iterator invalidation.468        return getIncludeHeaderUncached(SM.getFileID(SM.getIncludeLoc(FID)));469      // Conservatively refuse to insert #includes to files without guards.470      return "";471    }472    // Standard case: just insert the file itself.473    return toURI(*FE);474  }475};476 477// Return the symbol location of the token at \p TokLoc.478std::optional<SymbolLocation>479SymbolCollector::getTokenLocation(SourceLocation TokLoc) {480  const auto &SM = ASTCtx->getSourceManager();481  const auto FE = SM.getFileEntryRefForID(SM.getFileID(TokLoc));482  if (!FE)483    return std::nullopt;484 485  SymbolLocation Result;486  Result.FileURI = HeaderFileURIs->toURI(*FE).c_str();487  auto Range = getTokenRange(TokLoc, SM, ASTCtx->getLangOpts());488  Result.Start = Range.first;489  Result.End = Range.second;490 491  return Result;492}493 494SymbolCollector::SymbolCollector(Options Opts) : Opts(std::move(Opts)) {}495SymbolCollector::~SymbolCollector() = default;496 497void SymbolCollector::initialize(ASTContext &Ctx) {498  ASTCtx = &Ctx;499  HeaderFileURIs = std::make_unique<HeaderFileURICache>(500      this->PP, ASTCtx->getSourceManager(), Opts);501  CompletionAllocator = std::make_shared<GlobalCodeCompletionAllocator>();502  CompletionTUInfo =503      std::make_unique<CodeCompletionTUInfo>(CompletionAllocator);504}505 506bool SymbolCollector::shouldCollectSymbol(const NamedDecl &ND,507                                          const ASTContext &ASTCtx,508                                          const Options &Opts,509                                          bool IsMainFileOnly) {510  // Skip anonymous declarations, e.g (anonymous enum/class/struct).511  if (ND.getDeclName().isEmpty())512    return false;513 514  // Skip main-file symbols if we are not collecting them.515  if (IsMainFileOnly && !Opts.CollectMainFileSymbols)516    return false;517 518  // Skip symbols in anonymous namespaces in header files.519  if (!IsMainFileOnly && ND.isInAnonymousNamespace())520    return false;521 522  // For function local symbols, index only classes and its member functions.523  if (index::isFunctionLocalSymbol(&ND))524    return isa<RecordDecl>(ND) ||525           (ND.isCXXInstanceMember() && ND.isFunctionOrFunctionTemplate());526 527  // We want most things but not "local" symbols such as symbols inside528  // FunctionDecl, BlockDecl, ObjCMethodDecl and OMPDeclareReductionDecl.529  // FIXME: Need a matcher for ExportDecl in order to include symbols declared530  // within an export.531  const auto *DeclCtx = ND.getDeclContext();532  switch (DeclCtx->getDeclKind()) {533  case Decl::TranslationUnit:534  case Decl::Namespace:535  case Decl::LinkageSpec:536  case Decl::Enum:537  case Decl::ObjCProtocol:538  case Decl::ObjCInterface:539  case Decl::ObjCCategory:540  case Decl::ObjCCategoryImpl:541  case Decl::ObjCImplementation:542    break;543  default:544    // Record has a few derivations (e.g. CXXRecord, Class specialization), it's545    // easier to cast.546    if (!isa<RecordDecl>(DeclCtx))547      return false;548  }549 550  // Avoid indexing internal symbols in protobuf generated headers.551  if (isPrivateProtoDecl(ND))552    return false;553 554  // System headers that end with `intrin.h` likely contain useful symbols.555  if (!Opts.CollectReserved &&556      (hasReservedName(ND) || hasReservedScope(*ND.getDeclContext())) &&557      ASTCtx.getSourceManager().isInSystemHeader(ND.getLocation()) &&558      !ASTCtx.getSourceManager()559           .getFilename(ND.getLocation())560           .ends_with("intrin.h"))561    return false;562 563  return true;564}565 566const Decl *567SymbolCollector::getRefContainer(const Decl *Enclosing,568                                 const SymbolCollector::Options &Opts) {569  while (Enclosing) {570    const auto *ND = dyn_cast<NamedDecl>(Enclosing);571    if (ND && shouldCollectSymbol(*ND, ND->getASTContext(), Opts, true)) {572      break;573    }574    Enclosing = dyn_cast_or_null<Decl>(Enclosing->getDeclContext());575  }576  return Enclosing;577}578 579// Always return true to continue indexing.580bool SymbolCollector::handleDeclOccurrence(581    const Decl *D, index::SymbolRoleSet Roles,582    llvm::ArrayRef<index::SymbolRelation> Relations, SourceLocation Loc,583    index::IndexDataConsumer::ASTNodeInfo ASTNode) {584  assert(ASTCtx && PP && HeaderFileURIs);585  assert(CompletionAllocator && CompletionTUInfo);586  assert(ASTNode.OrigD);587  // Indexing API puts canonical decl into D, which might not have a valid588  // source location for implicit/built-in decls. Fallback to original decl in589  // such cases.590  if (D->getLocation().isInvalid())591    D = ASTNode.OrigD;592  // If OrigD is an declaration associated with a friend declaration and it's593  // not a definition, skip it. Note that OrigD is the occurrence that the594  // collector is currently visiting.595  if ((ASTNode.OrigD->getFriendObjectKind() !=596       Decl::FriendObjectKind::FOK_None) &&597      !(Roles & static_cast<unsigned>(index::SymbolRole::Definition)))598    return true;599  // A declaration created for a friend declaration should not be used as the600  // canonical declaration in the index. Use OrigD instead, unless we've already601  // picked a replacement for D602  if (D->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None)603    D = CanonicalDecls.try_emplace(D, ASTNode.OrigD).first->second;604  // Flag to mark that D should be considered canonical meaning its declaration605  // will override any previous declaration for the Symbol.606  bool DeclIsCanonical = false;607  // Avoid treating ObjCImplementationDecl as a canonical declaration if it has608  // a corresponding non-implicit and non-forward declared ObjcInterfaceDecl.609  if (const auto *IID = dyn_cast<ObjCImplementationDecl>(D)) {610    DeclIsCanonical = true;611    if (const auto *CID = IID->getClassInterface())612      if (const auto *DD = CID->getDefinition())613        if (!DD->isImplicitInterfaceDecl())614          D = DD;615  }616  // Avoid treating ObjCCategoryImplDecl as a canonical declaration in favor of617  // its ObjCCategoryDecl if it has one.618  if (const auto *CID = dyn_cast<ObjCCategoryImplDecl>(D)) {619    DeclIsCanonical = true;620    if (const auto *CD = CID->getCategoryDecl())621      D = CD;622  }623  const NamedDecl *ND = dyn_cast<NamedDecl>(D);624  if (!ND)625    return true;626 627  auto ID = getSymbolIDCached(ND);628  if (!ID)629    return true;630 631  // Mark D as referenced if this is a reference coming from the main file.632  // D may not be an interesting symbol, but it's cheaper to check at the end.633  auto &SM = ASTCtx->getSourceManager();634  if (Opts.CountReferences &&635      (Roles & static_cast<unsigned>(index::SymbolRole::Reference)) &&636      SM.getFileID(SM.getSpellingLoc(Loc)) == SM.getMainFileID())637    ReferencedSymbols.insert(ID);638 639  // ND is the canonical (i.e. first) declaration. If it's in the main file640  // (which is not a header), then no public declaration was visible, so assume641  // it's main-file only.642  bool IsMainFileOnly =643      SM.isWrittenInMainFile(SM.getExpansionLoc(ND->getBeginLoc())) &&644      !isHeaderFile(SM.getFileEntryRefForID(SM.getMainFileID())->getName(),645                    ASTCtx->getLangOpts());646  // In C, printf is a redecl of an implicit builtin! So check OrigD instead.647  if (ASTNode.OrigD->isImplicit() ||648      !shouldCollectSymbol(*ND, *ASTCtx, Opts, IsMainFileOnly))649    return true;650 651  // Note: we need to process relations for all decl occurrences, including652  // refs, because the indexing code only populates relations for specific653  // occurrences. For example, RelationBaseOf is only populated for the654  // occurrence inside the base-specifier.655  processRelations(*ND, ID, Relations);656 657  bool CollectRef = static_cast<bool>(Opts.RefFilter & toRefKind(Roles));658  // Unlike other fields, e.g. Symbols (which use spelling locations), we use659  // file locations for references (as it aligns the behavior of clangd's660  // AST-based xref).661  // FIXME: we should try to use the file locations for other fields.662  if (CollectRef &&663      (!IsMainFileOnly || Opts.CollectMainFileRefs ||664       ND->isExternallyVisible()) &&665      !isa<NamespaceDecl>(ND)) {666    auto FileLoc = SM.getFileLoc(Loc);667    auto FID = SM.getFileID(FileLoc);668    if (Opts.RefsInHeaders || FID == SM.getMainFileID()) {669      addRef(ID, SymbolRef{FileLoc, FID, Roles, index::getSymbolInfo(ND).Kind,670                           getRefContainer(ASTNode.Parent, Opts),671                           isSpelled(FileLoc, *ND)});672    }673  }674  // Don't continue indexing if this is a mere reference.675  if (!(Roles & (static_cast<unsigned>(index::SymbolRole::Declaration) |676                 static_cast<unsigned>(index::SymbolRole::Definition))))677    return true;678 679  // FIXME: ObjCPropertyDecl are not properly indexed here:680  // - ObjCPropertyDecl may have an OrigD of ObjCPropertyImplDecl, which is681  // not a NamedDecl.682  auto *OriginalDecl = dyn_cast<NamedDecl>(ASTNode.OrigD);683  if (!OriginalDecl)684    return true;685 686  const Symbol *BasicSymbol = Symbols.find(ID);687  bool SkipDocCheckInDef = false;688  if (isPreferredDeclaration(*OriginalDecl, Roles)) {689    // If OriginalDecl is preferred, replace/create the existing canonical690    // declaration (e.g. a class forward declaration). There should be at most691    // one duplicate as we expect to see only one preferred declaration per692    // TU, because in practice they are definitions.693    BasicSymbol = addDeclaration(*OriginalDecl, std::move(ID), IsMainFileOnly);694    SkipDocCheckInDef = true;695  } else if (!BasicSymbol || DeclIsCanonical) {696    BasicSymbol = addDeclaration(*ND, std::move(ID), IsMainFileOnly);697    SkipDocCheckInDef = true;698  }699 700  if (Roles & static_cast<unsigned>(index::SymbolRole::Definition))701    addDefinition(*OriginalDecl, *BasicSymbol, SkipDocCheckInDef);702 703  return true;704}705 706void SymbolCollector::handleMacros(const MainFileMacros &MacroRefsToIndex) {707  assert(HeaderFileURIs && PP);708  const auto &SM = PP->getSourceManager();709  const auto MainFileEntryRef = SM.getFileEntryRefForID(SM.getMainFileID());710  assert(MainFileEntryRef);711 712  const std::string &MainFileURI = HeaderFileURIs->toURI(*MainFileEntryRef);713  // Add macro references.714  for (const auto &IDToRefs : MacroRefsToIndex.MacroRefs) {715    for (const auto &MacroRef : IDToRefs.second) {716      const auto &SR = MacroRef.toSourceRange(SM);717      auto Range = halfOpenToRange(SM, SR);718      bool IsDefinition = MacroRef.IsDefinition;719      Ref R;720      R.Location.Start.setLine(Range.start.line);721      R.Location.Start.setColumn(Range.start.character);722      R.Location.End.setLine(Range.end.line);723      R.Location.End.setColumn(Range.end.character);724      R.Location.FileURI = MainFileURI.c_str();725      R.Kind = IsDefinition ? RefKind::Definition : RefKind::Reference;726      Refs.insert(IDToRefs.first, R);727      if (IsDefinition) {728        Symbol S;729        S.ID = IDToRefs.first;730        S.Name = toSourceCode(SM, SR.getAsRange());731        S.SymInfo.Kind = index::SymbolKind::Macro;732        S.SymInfo.SubKind = index::SymbolSubKind::None;733        S.SymInfo.Properties = index::SymbolPropertySet();734        S.SymInfo.Lang = index::SymbolLanguage::C;735        S.Origin = Opts.Origin;736        S.CanonicalDeclaration = R.Location;737        // Make the macro visible for code completion if main file is an738        // include-able header.739        if (!HeaderFileURIs->getIncludeHeader(SM.getMainFileID()).empty()) {740          S.Flags |= Symbol::IndexedForCodeCompletion;741          S.Flags |= Symbol::VisibleOutsideFile;742        }743        Symbols.insert(S);744      }745    }746  }747}748 749bool SymbolCollector::handleMacroOccurrence(const IdentifierInfo *Name,750                                            const MacroInfo *MI,751                                            index::SymbolRoleSet Roles,752                                            SourceLocation Loc) {753  assert(PP);754  // Builtin macros don't have useful locations and aren't needed in completion.755  if (MI->isBuiltinMacro())756    return true;757 758  const auto &SM = PP->getSourceManager();759  auto DefLoc = MI->getDefinitionLoc();760  // Also avoid storing macros that aren't defined in any file, i.e. predefined761  // macros like __DBL_MIN__ and those defined on the command line.762  if (SM.isWrittenInBuiltinFile(DefLoc) ||763      SM.isWrittenInCommandLineFile(DefLoc) ||764      Name->getName() == "__GCC_HAVE_DWARF2_CFI_ASM")765    return true;766 767  auto ID = getSymbolIDCached(Name->getName(), MI, SM);768  if (!ID)769    return true;770 771  auto SpellingLoc = SM.getSpellingLoc(Loc);772  bool IsMainFileOnly =773      SM.isInMainFile(SM.getExpansionLoc(DefLoc)) &&774      !isHeaderFile(SM.getFileEntryRefForID(SM.getMainFileID())->getName(),775                    ASTCtx->getLangOpts());776  // Do not store references to main-file macros.777  if ((static_cast<unsigned>(Opts.RefFilter) & Roles) && !IsMainFileOnly &&778      (Opts.RefsInHeaders || SM.getFileID(SpellingLoc) == SM.getMainFileID())) {779    // FIXME: Populate container information for macro references.780    // FIXME: All MacroRefs are marked as Spelled now, but this should be781    // checked.782    addRef(ID,783           SymbolRef{Loc, SM.getFileID(Loc), Roles, index::SymbolKind::Macro,784                     /*Container=*/nullptr,785                     /*Spelled=*/true});786  }787 788  // Collect symbols.789  if (!Opts.CollectMacro)790    return true;791 792  // Skip main-file macros if we are not collecting them.793  if (IsMainFileOnly && !Opts.CollectMainFileSymbols)794    return false;795 796  // Mark the macro as referenced if this is a reference coming from the main797  // file. The macro may not be an interesting symbol, but it's cheaper to check798  // at the end.799  if (Opts.CountReferences &&800      (Roles & static_cast<unsigned>(index::SymbolRole::Reference)) &&801      SM.getFileID(SpellingLoc) == SM.getMainFileID())802    ReferencedSymbols.insert(ID);803 804  // Don't continue indexing if this is a mere reference.805  // FIXME: remove macro with ID if it is undefined.806  if (!(Roles & static_cast<unsigned>(index::SymbolRole::Declaration) ||807        Roles & static_cast<unsigned>(index::SymbolRole::Definition)))808    return true;809 810  // Only collect one instance in case there are multiple.811  if (Symbols.find(ID) != nullptr)812    return true;813 814  Symbol S;815  S.ID = std::move(ID);816  S.Name = Name->getName();817  if (!IsMainFileOnly) {818    S.Flags |= Symbol::IndexedForCodeCompletion;819    S.Flags |= Symbol::VisibleOutsideFile;820  }821  S.SymInfo = index::getSymbolInfoForMacro(*MI);822  S.Origin = Opts.Origin;823  // FIXME: use the result to filter out symbols.824  shouldIndexFile(SM.getFileID(Loc));825  if (auto DeclLoc = getTokenLocation(DefLoc))826    S.CanonicalDeclaration = *DeclLoc;827 828  CodeCompletionResult SymbolCompletion(Name);829  const auto *CCS = SymbolCompletion.CreateCodeCompletionStringForMacro(830      *PP, *CompletionAllocator, *CompletionTUInfo);831  std::string Signature;832  std::string SnippetSuffix;833  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,834               SymbolCompletion.CursorKind);835  S.Signature = Signature;836  S.CompletionSnippetSuffix = SnippetSuffix;837 838  IndexedMacros.insert(Name);839 840  setIncludeLocation(S, DefLoc, include_cleaner::Macro{Name, DefLoc});841  Symbols.insert(S);842  return true;843}844 845void SymbolCollector::processRelations(846    const NamedDecl &ND, const SymbolID &ID,847    ArrayRef<index::SymbolRelation> Relations) {848  for (const auto &R : Relations) {849    auto RKind = indexableRelation(R);850    if (!RKind)851      continue;852    const Decl *Object = R.RelatedSymbol;853 854    auto ObjectID = getSymbolIDCached(Object);855    if (!ObjectID)856      continue;857 858    // Record the relation.859    // TODO: There may be cases where the object decl is not indexed for some860    // reason. Those cases should probably be removed in due course, but for861    // now there are two possible ways to handle it:862    //   (A) Avoid storing the relation in such cases.863    //   (B) Store it anyways. Clients will likely lookup() the SymbolID864    //       in the index and find nothing, but that's a situation they865    //       probably need to handle for other reasons anyways.866    // We currently do (B) because it's simpler.867    if (*RKind == RelationKind::BaseOf)868      this->Relations.insert({ID, *RKind, ObjectID});869    else if (*RKind == RelationKind::OverriddenBy)870      this->Relations.insert({ObjectID, *RKind, ID});871  }872}873 874void SymbolCollector::setIncludeLocation(const Symbol &S, SourceLocation DefLoc,875                                         const include_cleaner::Symbol &Sym) {876  const auto &SM = PP->getSourceManager();877  if (!Opts.CollectIncludePath ||878      shouldCollectIncludePath(S.SymInfo.Kind) == Symbol::Invalid)879    return;880 881  // Use the expansion location to get the #include header since this is882  // where the symbol is exposed.883  if (FileID FID = SM.getDecomposedExpansionLoc(DefLoc).first; FID.isValid())884    IncludeFiles[S.ID] = FID;885 886  // We update providers for a symbol with each occurence, as SymbolCollector887  // might run while parsing, rather than at the end of a translation unit.888  // Hence we see more and more redecls over time.889  SymbolProviders[S.ID] =890      include_cleaner::headersForSymbol(Sym, *PP, Opts.PragmaIncludes);891}892 893llvm::StringRef getStdHeader(const Symbol *S, const LangOptions &LangOpts) {894  tooling::stdlib::Lang Lang = tooling::stdlib::Lang::CXX;895  if (LangOpts.C11)896    Lang = tooling::stdlib::Lang::C;897  else if(!LangOpts.CPlusPlus)898    return "";899 900  if (S->Scope == "std::" && S->Name == "move") {901    if (!S->Signature.contains(','))902      return "<utility>";903    return "<algorithm>";904  }905 906  if (auto StdSym = tooling::stdlib::Symbol::named(S->Scope, S->Name, Lang))907    if (auto Header = StdSym->header())908      return Header->name();909  return "";910}911 912void SymbolCollector::finish() {913  // At the end of the TU, add 1 to the refcount of all referenced symbols.914  for (const auto &ID : ReferencedSymbols) {915    if (const auto *S = Symbols.find(ID)) {916      // SymbolSlab::Builder returns const symbols because strings are interned917      // and modifying returned symbols without inserting again wouldn't go918      // well. const_cast is safe here as we're modifying a data owned by the919      // Symbol. This reduces time spent in SymbolCollector by ~1%.920      ++const_cast<Symbol *>(S)->References;921    }922  }923  if (Opts.CollectMacro) {924    assert(PP);925    // First, drop header guards. We can't identify these until EOF.926    for (const IdentifierInfo *II : IndexedMacros) {927      if (const auto *MI = PP->getMacroDefinition(II).getMacroInfo())928        if (auto ID =929                getSymbolIDCached(II->getName(), MI, PP->getSourceManager()))930          if (MI->isUsedForHeaderGuard())931            Symbols.erase(ID);932    }933  }934  llvm::DenseMap<FileID, bool> FileToContainsImportsOrObjC;935  llvm::DenseMap<include_cleaner::Header, std::string> HeaderSpelling;936  // Fill in IncludeHeaders.937  // We delay this until end of TU so header guards are all resolved.938  for (const auto &[SID, Providers] : SymbolProviders) {939    const Symbol *S = Symbols.find(SID);940    if (!S)941      continue;942 943    FileID FID = IncludeFiles.lookup(SID);944    // Determine if the FID is #include'd or #import'ed.945    Symbol::IncludeDirective Directives = Symbol::Invalid;946    auto CollectDirectives = shouldCollectIncludePath(S->SymInfo.Kind);947    if ((CollectDirectives & Symbol::Include) != 0)948      Directives |= Symbol::Include;949    // Only allow #import for symbols from ObjC-like files.950    if ((CollectDirectives & Symbol::Import) != 0 && FID.isValid()) {951      auto [It, Inserted] = FileToContainsImportsOrObjC.try_emplace(FID);952      if (Inserted)953        It->second = FilesWithObjCConstructs.contains(FID) ||954                     tooling::codeContainsImports(955                         ASTCtx->getSourceManager().getBufferData(FID));956      if (It->second)957        Directives |= Symbol::Import;958    }959 960    if (Directives == Symbol::Invalid)961      continue;962 963    // Use the include location-based logic for Objective-C symbols.964    if (Directives & Symbol::Import) {965      llvm::StringRef IncludeHeader = getStdHeader(S, ASTCtx->getLangOpts());966      if (IncludeHeader.empty())967        IncludeHeader = HeaderFileURIs->getIncludeHeader(FID);968 969      if (!IncludeHeader.empty()) {970        auto NewSym = *S;971        NewSym.IncludeHeaders.push_back({IncludeHeader, 1, Directives});972        Symbols.insert(NewSym);973      }974      // FIXME: use providers from include-cleaner library once it's polished975      // for Objective-C.976      continue;977    }978 979    // For #include's, use the providers computed by the include-cleaner980    // library.981    assert(Directives == Symbol::Include);982    // Ignore providers that are not self-contained, this is especially983    // important for symbols defined in the main-file. We want to prefer the984    // header, if possible.985    // TODO: Limit this to specifically ignore main file, when we're indexing a986    // non-header file?987    auto SelfContainedProvider =988        [this](llvm::ArrayRef<include_cleaner::Header> Providers)989        -> std::optional<include_cleaner::Header> {990      for (const auto &H : Providers) {991        if (H.kind() != include_cleaner::Header::Physical)992          return H;993        if (tooling::isSelfContainedHeader(H.physical(), PP->getSourceManager(),994                                           PP->getHeaderSearchInfo()))995          return H;996      }997      return std::nullopt;998    };999    const auto OptionalProvider = SelfContainedProvider(Providers);1000    if (!OptionalProvider)1001      continue;1002    const auto &H = *OptionalProvider;1003    const auto [SpellingIt, Inserted] = HeaderSpelling.try_emplace(H);1004    if (Inserted) {1005      auto &SM = ASTCtx->getSourceManager();1006      if (H.kind() == include_cleaner::Header::Kind::Physical) {1007        // FIXME: Get rid of this once include-cleaner has support for system1008        // headers.1009        if (auto Canonical =1010                HeaderFileURIs->mapCanonical(H.physical().getName());1011            !Canonical.empty())1012          SpellingIt->second = Canonical;1013        // For physical files, prefer URIs as spellings might change1014        // depending on the translation unit.1015        else if (tooling::isSelfContainedHeader(H.physical(), SM,1016                                                PP->getHeaderSearchInfo()))1017          SpellingIt->second =1018              HeaderFileURIs->toURI(H.physical());1019      } else {1020        SpellingIt->second = include_cleaner::spellHeader(1021            {H, PP->getHeaderSearchInfo(),1022             SM.getFileEntryForID(SM.getMainFileID())});1023      }1024    }1025 1026    if (!SpellingIt->second.empty()) {1027      auto NewSym = *S;1028      NewSym.IncludeHeaders.push_back({SpellingIt->second, 1, Directives});1029      Symbols.insert(NewSym);1030    }1031  }1032 1033  ReferencedSymbols.clear();1034  IncludeFiles.clear();1035  SymbolProviders.clear();1036  FilesWithObjCConstructs.clear();1037}1038 1039const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND, SymbolID ID,1040                                              bool IsMainFileOnly) {1041  auto &Ctx = ND.getASTContext();1042  auto &SM = Ctx.getSourceManager();1043 1044  Symbol S;1045  S.ID = std::move(ID);1046  std::string QName = printQualifiedName(ND);1047  // FIXME: this returns foo:bar: for objective-C methods, we prefer only foo:1048  // for consistency with CodeCompletionString and a clean name/signature split.1049  std::tie(S.Scope, S.Name) = splitQualifiedName(QName);1050  std::string TemplateSpecializationArgs = printTemplateSpecializationArgs(ND);1051  S.TemplateSpecializationArgs = TemplateSpecializationArgs;1052 1053  // We collect main-file symbols, but do not use them for code completion.1054  if (!IsMainFileOnly && isIndexedForCodeCompletion(ND, Ctx))1055    S.Flags |= Symbol::IndexedForCodeCompletion;1056  if (isImplementationDetail(&ND))1057    S.Flags |= Symbol::ImplementationDetail;1058  if (!IsMainFileOnly)1059    S.Flags |= Symbol::VisibleOutsideFile;1060  S.SymInfo = index::getSymbolInfo(&ND);1061  auto Loc = nameLocation(ND, SM);1062  assert(Loc.isValid() && "Invalid source location for NamedDecl");1063  // FIXME: use the result to filter out symbols.1064  auto FID = SM.getFileID(Loc);1065  shouldIndexFile(FID);1066  if (auto DeclLoc = getTokenLocation(Loc))1067    S.CanonicalDeclaration = *DeclLoc;1068 1069  S.Origin = Opts.Origin;1070  if (ND.getAvailability() == AR_Deprecated)1071    S.Flags |= Symbol::Deprecated;1072 1073  // Add completion info.1074  // FIXME: we may want to choose a different redecl, or combine from several.1075  assert(ASTCtx && PP && "ASTContext and Preprocessor must be set.");1076  // We use the primary template, as clang does during code completion.1077  CodeCompletionResult SymbolCompletion(&getTemplateOrThis(ND), 0);1078  const auto *CCS = SymbolCompletion.CreateCodeCompletionString(1079      *ASTCtx, *PP, CodeCompletionContext::CCC_Symbol, *CompletionAllocator,1080      *CompletionTUInfo,1081      /*IncludeBriefComments*/ false);1082  std::string DocComment;1083  std::string Documentation;1084  bool AlreadyHasDoc = S.Flags & Symbol::HasDocComment;1085  if (!AlreadyHasDoc) {1086    DocComment = getDocComment(Ctx, SymbolCompletion,1087                               /*CommentsFromHeaders=*/true);1088    Documentation = formatDocumentation(*CCS, DocComment);1089  }1090  const auto UpdateDoc = [&] {1091    if (!AlreadyHasDoc) {1092      if (!DocComment.empty())1093        S.Flags |= Symbol::HasDocComment;1094      S.Documentation = Documentation;1095    }1096  };1097  if (!(S.Flags & Symbol::IndexedForCodeCompletion)) {1098    if (Opts.StoreAllDocumentation)1099      UpdateDoc();1100    Symbols.insert(S);1101    return Symbols.find(S.ID);1102  }1103  UpdateDoc();1104  std::string Signature;1105  std::string SnippetSuffix;1106  getSignature(*CCS, &Signature, &SnippetSuffix, SymbolCompletion.Kind,1107               SymbolCompletion.CursorKind);1108  S.Signature = Signature;1109  S.CompletionSnippetSuffix = SnippetSuffix;1110  std::string ReturnType = getReturnType(*CCS);1111  S.ReturnType = ReturnType;1112 1113  std::optional<OpaqueType> TypeStorage;1114  if (S.Flags & Symbol::IndexedForCodeCompletion) {1115    TypeStorage = OpaqueType::fromCompletionResult(*ASTCtx, SymbolCompletion);1116    if (TypeStorage)1117      S.Type = TypeStorage->raw();1118  }1119 1120  Symbols.insert(S);1121  setIncludeLocation(S, ND.getLocation(), include_cleaner::Symbol{ND});1122  if (S.SymInfo.Lang == index::SymbolLanguage::ObjC)1123    FilesWithObjCConstructs.insert(FID);1124  return Symbols.find(S.ID);1125}1126 1127void SymbolCollector::addDefinition(const NamedDecl &ND, const Symbol &DeclSym,1128                                    bool SkipDocCheck) {1129  if (DeclSym.Definition)1130    return;1131  const auto &SM = ND.getASTContext().getSourceManager();1132  auto Loc = nameLocation(ND, SM);1133  shouldIndexFile(SM.getFileID(Loc));1134  auto DefLoc = getTokenLocation(Loc);1135  // If we saw some forward declaration, we end up copying the symbol.1136  // This is not ideal, but avoids duplicating the "is this a definition" check1137  // in clang::index. We should only see one definition.1138  if (!DefLoc)1139    return;1140  Symbol S = DeclSym;1141  // FIXME: use the result to filter out symbols.1142  S.Definition = *DefLoc;1143 1144  std::string DocComment;1145  std::string Documentation;1146  if (!SkipDocCheck && !(S.Flags & Symbol::HasDocComment) &&1147      (llvm::isa<FunctionDecl>(ND) || llvm::isa<CXXMethodDecl>(ND))) {1148    CodeCompletionResult SymbolCompletion(&getTemplateOrThis(ND), 0);1149    const auto *CCS = SymbolCompletion.CreateCodeCompletionString(1150        *ASTCtx, *PP, CodeCompletionContext::CCC_Symbol, *CompletionAllocator,1151        *CompletionTUInfo,1152        /*IncludeBriefComments*/ false);1153    DocComment = getDocComment(ND.getASTContext(), SymbolCompletion,1154                               /*CommentsFromHeaders=*/true);1155    if (!S.Documentation.empty())1156      Documentation = S.Documentation.str() + '\n' + DocComment;1157    else1158      Documentation = formatDocumentation(*CCS, DocComment);1159    if (!DocComment.empty())1160      S.Flags |= Symbol::HasDocComment;1161    S.Documentation = Documentation;1162  }1163 1164  Symbols.insert(S);1165}1166 1167bool SymbolCollector::shouldIndexFile(FileID FID) {1168  if (!Opts.FileFilter)1169    return true;1170  auto I = FilesToIndexCache.try_emplace(FID);1171  if (I.second)1172    I.first->second = Opts.FileFilter(ASTCtx->getSourceManager(), FID);1173  return I.first->second;1174}1175 1176static bool refIsCall(index::SymbolKind Kind) {1177  using SK = index::SymbolKind;1178  return Kind == SK::Function || Kind == SK::InstanceMethod ||1179         Kind == SK::ClassMethod || Kind == SK::StaticMethod ||1180         Kind == SK::Constructor || Kind == SK::Destructor ||1181         Kind == SK::ConversionFunction;1182}1183 1184void SymbolCollector::addRef(SymbolID ID, const SymbolRef &SR) {1185  const auto &SM = ASTCtx->getSourceManager();1186  // FIXME: use the result to filter out references.1187  shouldIndexFile(SR.FID);1188  if (const auto FE = SM.getFileEntryRefForID(SR.FID)) {1189    auto Range = getTokenRange(SR.Loc, SM, ASTCtx->getLangOpts());1190    Ref R;1191    R.Location.Start = Range.first;1192    R.Location.End = Range.second;1193    R.Location.FileURI = HeaderFileURIs->toURI(*FE).c_str();1194    R.Kind = toRefKind(SR.Roles, SR.Spelled);1195    if (refIsCall(SR.Kind)) {1196      R.Kind |= RefKind::Call;1197    }1198    R.Container = getSymbolIDCached(SR.Container);1199    Refs.insert(ID, R);1200  }1201}1202 1203SymbolID SymbolCollector::getSymbolIDCached(const Decl *D) {1204  auto It = DeclToIDCache.try_emplace(D);1205  if (It.second)1206    It.first->second = getSymbolID(D);1207  return It.first->second;1208}1209 1210SymbolID SymbolCollector::getSymbolIDCached(const llvm::StringRef MacroName,1211                                            const MacroInfo *MI,1212                                            const SourceManager &SM) {1213  auto It = MacroToIDCache.try_emplace(MI);1214  if (It.second)1215    It.first->second = getSymbolID(MacroName, MI, SM);1216  return It.first->second;1217}1218} // namespace clangd1219} // namespace clang1220