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