1 //===--- SymbolCollector.cpp -------------------------------------*- C++-*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "SymbolCollector.h"
11 #include "CodeComplete.h"
12 #include "CodeCompletionStrings.h"
13 #include "ExpectedTypes.h"
14 #include "SourceCode.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"
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())
66 // Checks whether the decl is a private symbol in a header generated by
68 // FIXME: make filtering extensible when there are more use cases for symbol
70 bool isPrivateProtoDecl(const NamedDecl
&ND
) {
71 const auto &SM
= ND
.getASTContext().getSourceManager();
72 if (!isProtoFile(nameLocation(ND
, SM
), SM
))
75 // ND without identifier can be operators.
76 if (ND
.getIdentifier() == nullptr)
78 auto Name
= ND
.getIdentifier()->getName();
79 // There are some internal helpers like _internal_set_foo();
80 if (Name
.contains("_internal_"))
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.
95 // enum Foo_E { Foo_E_A };
97 // using Bar = Foo_Bar;
98 // static constexpr Foo_E A = Foo_E_A;
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())
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.
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
140 Symbol::IncludeDirective
shouldCollectIncludePath(index::SymbolKind Kind
) {
141 using SK
= index::SymbolKind
;
152 case SK::EnumConstant
:
154 return Symbol::Include
| Symbol::Import
;
156 return Symbol::Import
;
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
);
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();
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
;
205 Result
|= RefKind::Spelled
;
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
;
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
)
227 const auto &AST
= ND
.getASTContext();
228 const auto &SM
= AST
.getSourceManager();
229 const auto &LO
= AST
.getLangOpts();
231 if (clang::Lexer::getRawToken(Loc
, Tok
, SM
, LO
))
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();
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)
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
;
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
);
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
))
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
);
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
) {
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())
314 // If we had a mapping, always use it.
315 assert(Canonical
.starts_with("<") || Canonical
.starts_with("\""));
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
);
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 "
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
;
357 if (*I
== "Headers" || *I
== "PrivateHeaders") {
358 HeaderPath
.HeaderSubpath
= Path
.substr(Prev
- E
);
359 HeaderPath
.IsPrivateHeader
= *I
== "PrivateHeaders";
362 HeaderPath
.FrameworkName
= *I
;
363 if (!HeaderPath
.FrameworkName
.consume_back(".framework"))
365 HeaderPath
.FrameworkParentDir
= Path
.substr(0, I
- E
);
371 // Unexpected, must not be a framework header.
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
;
387 return HeaderPath
.IsPrivateHeader
? CachedSpelling
->PrivateHeader
388 : CachedSpelling
->PublicHeader
;
390 SmallString
<256> UmbrellaPath(HeaderPath
.FrameworkParentDir
);
391 llvm::sys::path::append(UmbrellaPath
, Framework
+ ".framework", "Headers",
394 llvm::vfs::Status Status
;
395 auto StatErr
= HS
.getFileMgr().getNoncachedStatValue(UmbrellaPath
, Status
);
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
);
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
;
421 return llvm::StringRef(*CachedHeaderSpelling
);
423 auto HeaderPath
= splitFrameworkHeaderPath(FE
.getName());
425 // Unexpected: must not be a proper framework header, don't cache the
427 CachePathToFrameworkSpelling
.erase(Res
.first
);
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
)
440 return llvm::StringRef(*CachedHeaderSpelling
);
443 llvm::StringRef
getIncludeHeaderUncached(FileID FID
) {
444 const auto FE
= SM
.getFileEntryRefForID(FID
);
445 if (!FE
|| FE
->getName().empty())
448 if (auto Verbatim
= PI
->getPublic(*FE
); !Verbatim
.empty())
451 llvm::StringRef Filename
= FE
->getName();
452 if (auto Canonical
= mapCanonical(Filename
); !Canonical
.empty())
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
))
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.
471 // Standard case: just insert the file itself.
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
));
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
;
493 SymbolCollector::SymbolCollector(Options Opts
) : Opts(std::move(Opts
)) {}
494 SymbolCollector::~SymbolCollector() = default;
496 void SymbolCollector::initialize(ASTContext
&Ctx
) {
498 HeaderFileURIs
= std::make_unique
<HeaderFileURICache
>(
499 this->PP
, ASTCtx
->getSourceManager(), Opts
);
500 CompletionAllocator
= std::make_shared
<GlobalCodeCompletionAllocator
>();
502 std::make_unique
<CodeCompletionTUInfo
>(CompletionAllocator
);
505 bool SymbolCollector::shouldCollectSymbol(const NamedDecl
&ND
,
506 const ASTContext
&ASTCtx
,
508 bool IsMainFileOnly
) {
509 // Skip anonymous declarations, e.g (anonymous enum/class/struct).
510 if (ND
.getDeclName().isEmpty())
513 // Skip main-file symbols if we are not collecting them.
514 if (IsMainFileOnly
&& !Opts
.CollectMainFileSymbols
)
517 // Skip symbols in anonymous namespaces in header files.
518 if (!IsMainFileOnly
&& ND
.isInAnonymousNamespace())
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
530 const auto *DeclCtx
= ND
.getDeclContext();
531 switch (DeclCtx
->getDeclKind()) {
532 case Decl::TranslationUnit
:
533 case Decl::Namespace
:
534 case Decl::LinkageSpec
:
536 case Decl::ObjCProtocol
:
537 case Decl::ObjCInterface
:
538 case Decl::ObjCCategory
:
539 case Decl::ObjCCategoryImpl
:
540 case Decl::ObjCImplementation
:
543 // Record has a few derivations (e.g. CXXRecord, Class specialization), it's
545 if (!isa
<RecordDecl
>(DeclCtx
))
549 // Avoid indexing internal symbols in protobuf generated headers.
550 if (isPrivateProtoDecl(ND
))
552 if (!Opts
.CollectReserved
&&
553 (hasReservedName(ND
) || hasReservedScope(*ND
.getDeclContext())) &&
554 ASTCtx
.getSourceManager().isInSystemHeader(ND
.getLocation()))
561 SymbolCollector::getRefContainer(const Decl
*Enclosing
,
562 const SymbolCollector::Options
&Opts
) {
564 const auto *ND
= dyn_cast
<NamedDecl
>(Enclosing
);
565 if (ND
&& shouldCollectSymbol(*ND
, ND
->getASTContext(), Opts
, true)) {
568 Enclosing
= dyn_cast_or_null
<Decl
>(Enclosing
->getDeclContext());
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
584 if (D
->getLocation().isInvalid())
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
)))
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())
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())
617 const NamedDecl
*ND
= dyn_cast
<NamedDecl
>(D
);
621 auto ID
= getSymbolIDCached(ND
);
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
))
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
655 // FIXME: we should try to use the file locations for other fields.
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
))))
673 // FIXME: ObjCPropertyDecl are not properly indexed here:
674 // - ObjCPropertyDecl may have an OrigD of ObjCPropertyImplDecl, which is
676 auto *OriginalDecl
= dyn_cast
<NamedDecl
>(ASTNode
.OrigD
);
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
);
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
;
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
);
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
;
744 bool SymbolCollector::handleMacroOccurrence(const IdentifierInfo
*Name
,
746 index::SymbolRoleSet Roles
,
747 SourceLocation Loc
) {
749 // Builtin macros don't have useful locations and aren't needed in completion.
750 if (MI
->isBuiltinMacro())
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")
762 auto ID
= getSymbolIDCached(Name
->getName(), MI
, SM
);
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
777 addRef(ID
, SymbolRef
{Loc
, SM
.getFileID(Loc
), Roles
, /*Container=*/nullptr,
782 if (!Opts
.CollectMacro
)
785 // Skip main-file macros if we are not collecting them.
786 if (IsMainFileOnly
&& !Opts
.CollectMainFileSymbols
)
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
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
)))
803 // Only collect one instance in case there are multiple.
804 if (Symbols
.find(ID
) != nullptr)
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
});
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
);
845 const Decl
*Object
= R
.RelatedSymbol
;
847 auto ObjectID
= getSymbolIDCached(Object
);
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
)
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
;
889 Lang
= tooling::stdlib::Lang::C
;
890 else if(!LangOpts
.CPlusPlus
)
893 if (S
->Scope
== "std::" && S
->Name
== "move") {
894 if (!S
->Signature
.contains(','))
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();
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
) {
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())
922 getSymbolIDCached(II
->getName(), MI
, PP
->getSourceManager()))
923 if (MI
->isUsedForHeaderGuard())
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
);
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
);
946 It
->second
= FilesWithObjCConstructs
.contains(FID
) ||
947 tooling::codeContainsImports(
948 ASTCtx
->getSourceManager().getBufferData(FID
));
950 Directives
|= Symbol::Import
;
953 if (Directives
== Symbol::Invalid
)
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()) {
964 NewSym
.IncludeHeaders
.push_back({IncludeHeader
, 1, Directives
});
965 Symbols
.insert(NewSym
);
967 // FIXME: use providers from include-cleaner library once it's polished
972 // For #include's, use the providers computed by the include-cleaner
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
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
)
986 if (tooling::isSelfContainedHeader(H
.physical(), PP
->getSourceManager(),
987 PP
->getHeaderSearchInfo()))
992 const auto OptionalProvider
= SelfContainedProvider(Providers
);
993 if (!OptionalProvider
)
995 const auto &H
= *OptionalProvider
;
996 const auto [SpellingIt
, Inserted
] = HeaderSpelling
.try_emplace(H
);
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
1002 if (auto Canonical
=
1003 HeaderFileURIs
->mapCanonical(H
.physical().getName());
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());
1013 SpellingIt
->second
= include_cleaner::spellHeader(
1014 {H
, PP
->getHeaderSearchInfo(),
1015 SM
.getFileEntryForID(SM
.getMainFileID())});
1019 if (!SpellingIt
->second
.empty()) {
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();
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
,
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
)
1094 return Symbols
.find(S
.ID
);
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
);
1110 S
.Type
= TypeStorage
->raw();
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
)
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.
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
,
1145 /*IncludeBriefComments*/ false);
1146 DocComment
= getDocComment(ND
.getASTContext(), SymbolCompletion
,
1147 /*CommentsFromHeaders=*/true);
1148 if (!S
.Documentation
.empty())
1149 Documentation
= S
.Documentation
.str() + '\n' + DocComment
;
1151 Documentation
= formatDocumentation(*CCS
, DocComment
);
1152 if (!DocComment
.empty())
1153 S
.Flags
|= Symbol::HasDocComment
;
1154 S
.Documentation
= Documentation
;
1160 bool SymbolCollector::shouldIndexFile(FileID FID
) {
1161 if (!Opts
.FileFilter
)
1163 auto I
= FilesToIndexCache
.try_emplace(FID
);
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());
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
);
1185 SymbolID
SymbolCollector::getSymbolIDCached(const Decl
*D
) {
1186 auto It
= DeclToIDCache
.try_emplace(D
, SymbolID
{});
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
{});
1197 It
.first
->second
= getSymbolID(MacroName
, MI
, SM
);
1198 return It
.first
->second
;
1200 } // namespace clangd
1201 } // namespace clang