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