20 #include "clang/AST/Decl.h"
21 #include "clang/AST/DeclBase.h"
22 #include "clang/AST/DeclCXX.h"
23 #include "clang/AST/DeclTemplate.h"
24 #include "clang/Basic/SourceLocation.h"
25 #include "clang/Basic/SourceManager.h"
26 #include "clang/Basic/Specifiers.h"
27 #include "clang/Index/IndexSymbol.h"
28 #include "clang/Index/IndexingAction.h"
29 #include "clang/Index/USRGeneration.h"
30 #include "clang/Lex/Preprocessor.h"
31 #include "clang/Tooling/Syntax/Tokens.h"
32 #include "llvm/Support/Casting.h"
33 #include "llvm/Support/FileSystem.h"
34 #include "llvm/Support/MemoryBuffer.h"
35 #include "llvm/Support/Path.h"
43 const NamedDecl &getTemplateOrThis(
const NamedDecl &ND) {
44 if (
auto T = ND.getDescribedTemplate())
58 std::string toURI(
const SourceManager &SM, llvm::StringRef
Path,
59 const SymbolCollector::Options &Opts) {
60 llvm::SmallString<128> AbsolutePath(
Path);
61 if (
auto File = SM.getFileManager().getFile(
Path)) {
63 AbsolutePath = *CanonPath;
68 if (!llvm::sys::path::is_absolute(AbsolutePath) && !Opts.FallbackDir.empty())
70 llvm::sys::path::remove_dots(AbsolutePath,
true);
78 bool isPrivateProtoDecl(
const NamedDecl &ND) {
79 const auto &SM = ND.getASTContext().getSourceManager();
84 if (ND.getIdentifier() ==
nullptr)
86 auto Name = ND.getIdentifier()->getName();
87 if (!
Name.contains(
'_'))
124 std::pair<SymbolLocation::Position, SymbolLocation::Position>
125 getTokenRange(SourceLocation TokLoc,
const SourceManager &SM,
126 const LangOptions &LangOpts) {
127 auto CreatePosition = [&SM](SourceLocation
Loc) {
129 SymbolLocation::Position
Pos;
130 Pos.setLine(LSPLoc.line);
131 Pos.setColumn(LSPLoc.character);
135 auto TokenLength = clang::Lexer::MeasureTokenLength(TokLoc, SM, LangOpts);
136 return {CreatePosition(TokLoc),
137 CreatePosition(TokLoc.getLocWithOffset(TokenLength))};
141 llvm::Optional<SymbolLocation>
142 getTokenLocation(SourceLocation TokLoc,
const SourceManager &SM,
143 const SymbolCollector::Options &Opts,
144 const clang::LangOptions &LangOpts,
145 std::string &FileURIStorage) {
146 auto Path = SM.getFilename(TokLoc);
149 FileURIStorage = toURI(SM,
Path, Opts);
150 SymbolLocation Result;
151 Result.FileURI = FileURIStorage.c_str();
152 auto Range = getTokenRange(TokLoc, SM, LangOpts);
153 Result.Start =
Range.first;
154 Result.End =
Range.second;
165 bool isPreferredDeclaration(
const NamedDecl &ND, index::SymbolRoleSet Roles) {
166 const auto &SM = ND.getASTContext().getSourceManager();
167 return (Roles & static_cast<unsigned>(index::SymbolRole::Definition)) &&
171 RefKind toRefKind(index::SymbolRoleSet Roles,
bool Spelled =
false) {
173 if (Roles & static_cast<unsigned>(index::SymbolRole::Declaration))
175 if (Roles & static_cast<unsigned>(index::SymbolRole::Definition))
177 if (Roles & static_cast<unsigned>(index::SymbolRole::Reference))
184 bool shouldIndexRelation(
const index::SymbolRelation &R) {
186 return R.Roles & static_cast<unsigned>(index::SymbolRole::RelationBaseOf);
195 CompletionAllocator = std::make_shared<GlobalCodeCompletionAllocator>();
197 std::make_unique<CodeCompletionTUInfo>(CompletionAllocator);
201 const ASTContext &ASTCtx,
203 bool IsMainFileOnly) {
205 if (ND.getDeclName().isEmpty())
209 if (IsMainFileOnly && !Opts.CollectMainFileSymbols)
213 if (!IsMainFileOnly && ND.isInAnonymousNamespace())
220 const auto *DeclCtx = ND.getDeclContext();
221 switch (DeclCtx->getDeclKind()) {
222 case Decl::TranslationUnit:
224 case Decl::LinkageSpec:
226 case Decl::ObjCProtocol:
227 case Decl::ObjCInterface:
228 case Decl::ObjCCategory:
229 case Decl::ObjCCategoryImpl:
230 case Decl::ObjCImplementation:
235 if (!isa<RecordDecl>(DeclCtx))
240 if (isPrivateProtoDecl(ND))
247 const Decl *D, index::SymbolRoleSet Roles,
248 llvm::ArrayRef<index::SymbolRelation> Relations, SourceLocation
Loc,
249 index::IndexDataConsumer::ASTNodeInfo ASTNode) {
250 assert(ASTCtx && PP.get() &&
"ASTContext and Preprocessor must be set.");
251 assert(CompletionAllocator && CompletionTUInfo);
252 assert(ASTNode.OrigD);
256 if (D->getLocation().isInvalid())
261 if ((ASTNode.OrigD->getFriendObjectKind() !=
262 Decl::FriendObjectKind::FOK_None) &&
263 !(Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
268 if (D->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None)
269 D = CanonicalDecls.try_emplace(D, ASTNode.OrigD).first->second;
270 const NamedDecl *ND = dyn_cast<NamedDecl>(D);
276 auto &SM = ASTCtx->getSourceManager();
277 if (Opts.CountReferences &&
278 (Roles & static_cast<unsigned>(index::SymbolRole::Reference)) &&
279 SM.getFileID(SM.getSpellingLoc(
Loc)) == SM.getMainFileID())
280 ReferencedDecls.insert(ND);
289 bool IsMainFileOnly =
290 SM.isWrittenInMainFile(SM.getExpansionLoc(ND->getBeginLoc())) &&
291 !
isHeaderFile(SM.getFileEntryForID(SM.getMainFileID())->getName(),
292 ASTCtx->getLangOpts());
294 if (ASTNode.OrigD->isImplicit() ||
302 processRelations(*ND, *ID, Relations);
304 bool CollectRef = static_cast<bool>(Opts.RefFilter & toRefKind(Roles));
306 !(Roles & (static_cast<unsigned>(index::SymbolRole::Declaration) |
307 static_cast<unsigned>(index::SymbolRole::Definition)));
309 if (IsOnlyRef && !CollectRef)
317 if (CollectRef && !IsMainFileOnly && !isa<NamespaceDecl>(ND) &&
318 (Opts.RefsInHeaders ||
319 SM.getFileID(SM.getFileLoc(
Loc)) == SM.getMainFileID()))
320 DeclRefs[ND].emplace_back(SM.getFileLoc(
Loc), Roles);
328 auto *OriginalDecl = dyn_cast<NamedDecl>(ASTNode.OrigD);
332 const Symbol *BasicSymbol = Symbols.
find(*ID);
334 BasicSymbol = addDeclaration(*ND, std::move(*ID), IsMainFileOnly);
335 else if (isPreferredDeclaration(*OriginalDecl, Roles))
340 BasicSymbol = addDeclaration(*OriginalDecl, std::move(*ID), IsMainFileOnly);
342 if (Roles & static_cast<unsigned>(index::SymbolRole::Definition))
343 addDefinition(*OriginalDecl, *BasicSymbol);
350 const auto &SM = PP->getSourceManager();
351 const auto *MainFileEntry = SM.getFileEntryForID(SM.getMainFileID());
352 assert(MainFileEntry);
354 const auto MainFileURI = toURI(SM, MainFileEntry->getName(), Opts);
356 for (
const auto &IDToRefs : MacroRefsToIndex.
MacroRefs) {
357 for (
const auto &
Range : IDToRefs.second) {
366 Refs.
insert(IDToRefs.first, R);
373 index::SymbolRoleSet Roles,
374 SourceLocation
Loc) {
377 const auto &SM = PP->getSourceManager();
378 auto DefLoc = MI->getDefinitionLoc();
379 auto SpellingLoc = SM.getSpellingLoc(
Loc);
380 bool IsMainFileSymbol = SM.isInMainFile(SM.getExpansionLoc(DefLoc));
383 if (MI->isBuiltinMacro())
387 if (SM.isWrittenInBuiltinFile(DefLoc))
395 if ((static_cast<unsigned>(Opts.RefFilter) & Roles) && !IsMainFileSymbol &&
396 (Opts.RefsInHeaders || SM.getFileID(SpellingLoc) == SM.getMainFileID()))
397 MacroRefs[*ID].push_back({
Loc, Roles});
400 if (!Opts.CollectMacro)
404 if (IsMainFileSymbol && !Opts.CollectMainFileSymbols)
410 if (Opts.CountReferences &&
411 (Roles & static_cast<unsigned>(index::SymbolRole::Reference)) &&
412 SM.getFileID(SpellingLoc) == SM.getMainFileID())
413 ReferencedMacros.insert(
Name);
417 if (!(Roles & static_cast<unsigned>(index::SymbolRole::Declaration) ||
418 Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
422 if (Symbols.
find(*ID) !=
nullptr)
426 S.
ID = std::move(*ID);
428 if (!IsMainFileSymbol) {
432 S.
SymInfo = index::getSymbolInfoForMacro(*MI);
437 getTokenLocation(DefLoc, SM, Opts, PP->getLangOpts(), FileURI))
440 CodeCompletionResult SymbolCompletion(
Name);
441 const auto *CCS = SymbolCompletion.CreateCodeCompletionStringForMacro(
442 *PP, *CompletionAllocator, *CompletionTUInfo);
449 IndexedMacros.insert(
Name);
450 setIncludeLocation(S, DefLoc);
455 void SymbolCollector::processRelations(
456 const NamedDecl &ND,
const SymbolID &ID,
457 ArrayRef<index::SymbolRelation> Relations) {
459 if (!dyn_cast<TagDecl>(&ND))
462 for (
const auto &R : Relations) {
463 if (!shouldIndexRelation(R))
485 void SymbolCollector::setIncludeLocation(
const Symbol &S, SourceLocation
Loc) {
486 if (Opts.CollectIncludePath)
487 if (shouldCollectIncludePath(S.SymInfo.Kind))
491 PP->getSourceManager().getDecomposedExpansionLoc(
Loc).first;
496 auto IncRef = [
this](
const SymbolID &ID) {
497 if (
const auto *S = Symbols.
find(ID)) {
503 for (
const NamedDecl *ND : ReferencedDecls) {
508 if (Opts.CollectMacro) {
511 for (
const IdentifierInfo *II : IndexedMacros) {
512 if (
const auto *MI = PP->getMacroDefinition(II).getMacroInfo())
513 if (
auto ID =
getSymbolID(II->getName(), MI, PP->getSourceManager()))
514 if (MI->isUsedForHeaderGuard())
518 for (
const IdentifierInfo *II : ReferencedMacros) {
519 if (
const auto *MI = PP->getMacroDefinition(II).getMacroInfo())
520 if (
auto ID =
getSymbolID(II->getName(), MI, PP->getSourceManager()))
528 llvm::SmallString<256> QName;
529 for (
const auto &
Entry : IncludeFiles)
532 QName.append(S->Name);
533 if (
auto Header = getIncludeHeader(QName,
Entry.second)) {
540 const auto &SM = ASTCtx->getSourceManager();
541 llvm::DenseMap<FileID, std::string> URICache;
542 auto GetURI = [&](FileID FID) -> llvm::Optional<std::string> {
543 auto Found = URICache.find(FID);
544 if (Found == URICache.end()) {
545 if (
auto *FileEntry = SM.getFileEntryForID(FID)) {
546 auto FileURI = toURI(SM, FileEntry->getName(), Opts);
547 Found = URICache.insert({FID, FileURI}).first;
554 return Found->second;
558 const std::pair<SourceLocation, index::SymbolRoleSet> &LocAndRole,
560 auto FileID = SM.getFileID(LocAndRole.first);
563 if (
auto FileURI = GetURI(FileID)) {
565 getTokenRange(LocAndRole.first, SM, ASTCtx->getLangOpts());
568 R.Location.End =
Range.second;
569 R.Location.FileURI = FileURI->c_str();
570 R.Kind = toRefKind(LocAndRole.second,
Spelled);
576 for (
const auto &IDAndRefs : MacroRefs)
577 for (
const auto &LocAndRole : IDAndRefs.second)
578 CollectRef(IDAndRefs.first, LocAndRole,
true);
580 llvm::DenseMap<FileID, std::vector<syntax::Token>> FilesToTokensCache;
581 for (
auto &DeclAndRef : DeclRefs) {
583 for (
auto &LocAndRole : DeclAndRef.second) {
584 const auto FileID = SM.getFileID(LocAndRole.first);
587 if (!FilesToTokensCache.count(FileID))
588 FilesToTokensCache[FileID] =
589 syntax::tokenize(FileID, SM, ASTCtx->getLangOpts());
590 llvm::ArrayRef<syntax::Token> Tokens = FilesToTokensCache[FileID];
593 const auto *IdentifierToken =
594 spelledIdentifierTouching(LocAndRole.first, Tokens);
595 DeclarationName
Name = DeclAndRef.first->getDeclName();
596 const auto NameKind =
Name.getNameKind();
598 NameKind == DeclarationName::CXXConstructorName;
599 bool Spelled = IdentifierToken && IsTargetKind &&
600 Name.getAsString() == IdentifierToken->text(SM);
601 CollectRef(*ID, LocAndRole,
Spelled);
606 ReferencedDecls.clear();
607 ReferencedMacros.clear();
609 FilesToIndexCache.clear();
610 HeaderIsSelfContainedCache.clear();
611 IncludeFiles.clear();
614 const Symbol *SymbolCollector::addDeclaration(
const NamedDecl &ND,
SymbolID ID,
615 bool IsMainFileOnly) {
616 auto &
Ctx = ND.getASTContext();
617 auto &SM =
Ctx.getSourceManager();
620 S.
ID = std::move(ID);
638 assert(
Loc.isValid() &&
"Invalid source location for NamedDecl");
642 getTokenLocation(
Loc, SM, Opts, ASTCtx->getLangOpts(), FileURI))
646 if (ND.getAvailability() == AR_Deprecated)
651 assert(ASTCtx && PP.get() &&
"ASTContext and Preprocessor must be set.");
653 CodeCompletionResult SymbolCompletion(&getTemplateOrThis(ND), 0);
654 const auto *CCS = SymbolCompletion.CreateCodeCompletionString(
655 *ASTCtx, *PP, CodeCompletionContext::CCC_Symbol, *CompletionAllocator,
658 std::string Documentation =
662 if (Opts.StoreAllDocumentation)
665 return Symbols.
find(S.
ID);
676 llvm::Optional<OpaqueType> TypeStorage;
680 S.
Type = TypeStorage->raw();
684 setIncludeLocation(S, ND.getLocation());
685 return Symbols.
find(S.
ID);
688 void SymbolCollector::addDefinition(
const NamedDecl &ND,
689 const Symbol &DeclSym) {
690 if (DeclSym.Definition)
697 const auto &SM = ND.getASTContext().getSourceManager();
702 getTokenLocation(
Loc, SM, Opts, ASTCtx->getLangOpts(), FileURI))
703 S.Definition = *DefLoc;
710 llvm::Optional<std::string>
711 SymbolCollector::getIncludeHeader(llvm::StringRef QName, FileID FID) {
712 const SourceManager &SM = ASTCtx->getSourceManager();
713 const FileEntry *FE = SM.getFileEntryForID(FID);
714 if (!FE || FE->getName().empty())
716 llvm::StringRef
Filename = FE->getName();
720 llvm::StringRef Canonical = Opts.Includes->mapHeader(
Filename, QName);
722 if (Canonical.startswith(
"<") || Canonical.startswith(
"\""))
723 return Canonical.str();
725 return toURI(SM, Canonical, Opts);
727 if (!isSelfContainedHeader(FID)) {
731 return getIncludeHeader(QName, SM.getFileID(SM.getIncludeLoc(FID)));
739 bool SymbolCollector::isSelfContainedHeader(FileID FID) {
742 const SourceManager &SM = ASTCtx->getSourceManager();
743 const FileEntry *FE = SM.getFileEntryForID(FID);
749 if (!PP->getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE) &&
750 !PP->getHeaderSearchInfo().hasFileBeenImported(FE))
754 if (isDontIncludeMeHeader(SM.getBufferData(FID)))
759 auto R = HeaderIsSelfContainedCache.try_emplace(FID,
false);
761 R.first->second = Compute();
762 return R.first->second;
768 if (!
Line.consume_front(
"#"))
771 return Line.startswith(
"if");
776 if (!
Line.consume_front(
"#"))
779 if (!
Line.startswith(
"error"))
781 return Line.contains_lower(
"includ");
784 bool SymbolCollector::isDontIncludeMeHeader(llvm::StringRef Content) {
785 llvm::StringRef
Line;
787 Content = Content.take_front(100 * 100);
788 for (
unsigned I = 0; I < 100 && !Content.empty(); ++I) {
789 std::tie(
Line, Content) = Content.split(
'\n');
797 if (!Opts.FileFilter)
799 auto I = FilesToIndexCache.try_emplace(FID);
801 I.first->second = Opts.FileFilter(ASTCtx->getSourceManager(), FID);
802 return I.first->second;