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"
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/ErrorHandling.h"
45#include "llvm/Support/FileSystem.h"
46#include "llvm/Support/Path.h"
59const NamedDecl &getTemplateOrThis(
const NamedDecl &ND) {
60 if (
auto *T = ND.getDescribedTemplate())
69bool isPrivateProtoDecl(
const NamedDecl &ND) {
70 const auto &SM = ND.getASTContext().getSourceManager();
75 if (ND.getIdentifier() ==
nullptr)
77 auto Name = ND.getIdentifier()->getName();
78 if (!
Name.contains(
'_'))
89 return (ND.getKind() != Decl::EnumConstant) || llvm::any_of(
Name, islower);
96 using SK = index::SymbolKind;
107 case SK::EnumConstant:
118std::pair<SymbolLocation::Position, SymbolLocation::Position>
119getTokenRange(SourceLocation TokLoc,
const SourceManager &SM,
120 const LangOptions &LangOpts) {
121 auto CreatePosition = [&SM](SourceLocation
Loc) {
123 SymbolLocation::Position
Pos;
124 Pos.setLine(LSPLoc.line);
125 Pos.setColumn(LSPLoc.character);
129 auto TokenLength = clang::Lexer::MeasureTokenLength(TokLoc, SM, LangOpts);
130 return {CreatePosition(TokLoc),
131 CreatePosition(TokLoc.getLocWithOffset(TokenLength))};
139bool isPreferredDeclaration(
const NamedDecl &ND, index::SymbolRoleSet Roles) {
140 const auto &SM = ND.getASTContext().getSourceManager();
141 if (isa<TagDecl>(ND))
142 return (Roles &
static_cast<unsigned>(index::SymbolRole::Definition)) &&
144 if (
const auto *
ID = dyn_cast<ObjCInterfaceDecl>(&ND))
145 return ID->isThisDeclarationADefinition();
146 if (
const auto *PD = dyn_cast<ObjCProtocolDecl>(&ND))
147 return PD->isThisDeclarationADefinition();
151RefKind toRefKind(index::SymbolRoleSet Roles,
bool Spelled =
false) {
153 if (Roles &
static_cast<unsigned>(index::SymbolRole::Declaration))
155 if (Roles &
static_cast<unsigned>(index::SymbolRole::Definition))
157 if (Roles &
static_cast<unsigned>(index::SymbolRole::Reference))
164std::optional<RelationKind> indexableRelation(
const index::SymbolRelation &R) {
165 if (R.Roles &
static_cast<unsigned>(index::SymbolRole::RelationBaseOf))
167 if (R.Roles &
static_cast<unsigned>(index::SymbolRole::RelationOverrideOf))
173bool isSpelled(SourceLocation
Loc,
const NamedDecl &ND) {
174 auto Name = ND.getDeclName();
175 const auto NameKind =
Name.getNameKind();
176 if (NameKind != DeclarationName::Identifier &&
177 NameKind != DeclarationName::CXXConstructorName)
179 const auto &
AST = ND.getASTContext();
180 const auto &SM =
AST.getSourceManager();
181 const auto &LO =
AST.getLangOpts();
183 if (clang::Lexer::getRawToken(
Loc, Tok, SM, LO))
185 auto StrName =
Name.getAsString();
186 return clang::Lexer::getSpelling(Tok, SM, LO) == StrName;
194 struct FrameworkUmbrellaSpelling {
196 std::optional<std::string> PublicHeader;
199 std::optional<std::string> PrivateHeader;
205 const SourceManager &SM;
206 const include_cleaner::PragmaIncludes *PI;
207 llvm::StringRef FallbackDir;
208 llvm::DenseMap<const FileEntry *, const std::string *> CacheFEToURI;
209 llvm::StringMap<std::string> CachePathToURI;
210 llvm::DenseMap<FileID, llvm::StringRef> CacheFIDToInclude;
211 llvm::StringMap<std::string> CachePathToFrameworkSpelling;
212 llvm::StringMap<FrameworkUmbrellaSpelling>
213 CacheFrameworkToUmbrellaHeaderSpelling;
218 : PP(PP), SM(SM), PI(Opts.PragmaIncludes), FallbackDir(Opts.FallbackDir) {
223 const std::string &
toURI(
const FileEntryRef FE) {
224 auto R = CacheFEToURI.try_emplace(FE);
227 R.first->second = &toURIInternal(CanonPath ? *CanonPath : FE.getName());
229 return *R.first->second;
236 if (
auto File = SM.getFileManager().getFileRef(
Path))
238 return toURIInternal(
Path);
246 auto R = CacheFIDToInclude.try_emplace(FID);
248 R.first->second = getIncludeHeaderUncached(FID);
249 return R.first->second;
261 auto Canonical = SysHeaderMapping.
mapHeader(HeaderPath);
262 if (Canonical.empty())
265 assert(Canonical.startswith(
"<") || Canonical.startswith(
"\""));
272 const std::string &toURIInternal(llvm::StringRef
Path) {
273 auto R = CachePathToURI.try_emplace(
Path);
275 llvm::SmallString<256> AbsPath =
Path;
276 if (!llvm::sys::path::is_absolute(AbsPath) && !FallbackDir.empty())
277 llvm::sys::fs::make_absolute(FallbackDir, AbsPath);
278 assert(llvm::sys::path::is_absolute(AbsPath) &&
279 "If the VFS can't make paths absolute, a FallbackDir must be "
281 llvm::sys::path::remove_dots(AbsPath,
true);
284 return R.first->second;
287 struct FrameworkHeaderPath {
290 llvm::StringRef HeadersParentDir;
293 llvm::StringRef HeaderSubpath;
295 bool IsPrivateHeader;
298 std::optional<FrameworkHeaderPath>
299 splitFrameworkHeaderPath(llvm::StringRef
Path) {
300 using namespace llvm::sys;
301 path::reverse_iterator I = path::rbegin(
Path);
302 path::reverse_iterator Prev = I;
303 path::reverse_iterator
E = path::rend(
Path);
305 if (*I ==
"Headers") {
306 FrameworkHeaderPath HeaderPath;
307 HeaderPath.HeadersParentDir =
Path.substr(0, I -
E);
308 HeaderPath.HeaderSubpath =
Path.substr(Prev -
E);
309 HeaderPath.IsPrivateHeader =
false;
312 if (*I ==
"PrivateHeaders") {
313 FrameworkHeaderPath HeaderPath;
314 HeaderPath.HeadersParentDir =
Path.substr(0, I -
E);
315 HeaderPath.HeaderSubpath =
Path.substr(Prev -
E);
316 HeaderPath.IsPrivateHeader =
true;
331 std::optional<std::string>
332 getFrameworkUmbrellaSpelling(llvm::StringRef Framework,
333 const HeaderSearch &HS,
334 FrameworkHeaderPath &HeaderPath) {
335 auto Res = CacheFrameworkToUmbrellaHeaderSpelling.try_emplace(Framework);
336 auto *CachedSpelling = &Res.first->second;
338 return HeaderPath.IsPrivateHeader ? CachedSpelling->PrivateHeader
339 : CachedSpelling->PublicHeader;
341 SmallString<256> UmbrellaPath(HeaderPath.HeadersParentDir);
342 llvm::sys::path::append(UmbrellaPath,
"Headers", Framework +
".h");
344 llvm::vfs::Status Status;
345 auto StatErr = HS.getFileMgr().getNoncachedStatValue(UmbrellaPath, Status);
347 CachedSpelling->PublicHeader = llvm::formatv(
"<{0}/{0}.h>", Framework);
349 UmbrellaPath = HeaderPath.HeadersParentDir;
350 llvm::sys::path::append(UmbrellaPath,
"PrivateHeaders",
351 Framework +
"_Private.h");
353 StatErr = HS.getFileMgr().getNoncachedStatValue(UmbrellaPath, Status);
355 CachedSpelling->PrivateHeader =
356 llvm::formatv(
"<{0}/{0}_Private.h>", Framework);
358 return HeaderPath.IsPrivateHeader ? CachedSpelling->PrivateHeader
359 : CachedSpelling->PublicHeader;
366 std::optional<llvm::StringRef>
367 getFrameworkHeaderIncludeSpelling(FileEntryRef FE, llvm::StringRef Framework,
369 auto Res = CachePathToFrameworkSpelling.try_emplace(FE.getName());
370 auto *CachedHeaderSpelling = &Res.first->second;
372 return llvm::StringRef(*CachedHeaderSpelling);
374 auto HeaderPath = splitFrameworkHeaderPath(FE.getName());
378 CachePathToFrameworkSpelling.erase(Res.first);
381 if (
auto UmbrellaSpelling =
382 getFrameworkUmbrellaSpelling(Framework, HS, *HeaderPath)) {
383 *CachedHeaderSpelling = *UmbrellaSpelling;
384 return llvm::StringRef(*CachedHeaderSpelling);
387 *CachedHeaderSpelling =
388 llvm::formatv(
"<{0}/{1}>", Framework, HeaderPath->HeaderSubpath).str();
389 return llvm::StringRef(*CachedHeaderSpelling);
392 llvm::StringRef getIncludeHeaderUncached(FileID FID) {
393 const auto FE = SM.getFileEntryRefForID(FID);
394 if (!FE || FE->getName().empty())
397 if (
auto Verbatim = PI->getPublic(*FE); !Verbatim.empty())
400 llvm::StringRef
Filename = FE->getName();
406 auto &HS = PP->getHeaderSearchInfo();
407 if (
const auto *HFI = HS.getExistingFileInfo(*FE,
false))
408 if (!HFI->Framework.empty())
410 getFrameworkHeaderIncludeSpelling(*FE, HFI->Framework, HS))
413 if (!tooling::isSelfContainedHeader(*FE, PP->getSourceManager(),
414 PP->getHeaderSearchInfo())) {
419 return getIncludeHeaderUncached(SM.getFileID(SM.getIncludeLoc(FID)));
429std::optional<SymbolLocation>
430SymbolCollector::getTokenLocation(SourceLocation TokLoc) {
431 const auto &SM = ASTCtx->getSourceManager();
432 const auto FE = SM.getFileEntryRefForID(SM.getFileID(TokLoc));
436 SymbolLocation Result;
437 Result.FileURI = HeaderFileURIs->toURI(*FE).c_str();
438 auto Range = getTokenRange(TokLoc, SM, ASTCtx->getLangOpts());
439 Result.Start =
Range.first;
440 Result.End =
Range.second;
450 HeaderFileURIs = std::make_unique<HeaderFileURICache>(
451 this->PP, ASTCtx->getSourceManager(), Opts);
452 CompletionAllocator = std::make_shared<GlobalCodeCompletionAllocator>();
454 std::make_unique<CodeCompletionTUInfo>(CompletionAllocator);
458 const ASTContext &ASTCtx,
460 bool IsMainFileOnly) {
462 if (ND.getDeclName().isEmpty())
466 if (IsMainFileOnly && !Opts.CollectMainFileSymbols)
470 if (!IsMainFileOnly && ND.isInAnonymousNamespace())
474 if (index::isFunctionLocalSymbol(&ND))
475 return isa<RecordDecl>(ND) ||
476 (ND.isCXXInstanceMember() && ND.isFunctionOrFunctionTemplate());
482 const auto *DeclCtx = ND.getDeclContext();
483 switch (DeclCtx->getDeclKind()) {
484 case Decl::TranslationUnit:
485 case Decl::Namespace:
486 case Decl::LinkageSpec:
488 case Decl::ObjCProtocol:
489 case Decl::ObjCInterface:
490 case Decl::ObjCCategory:
491 case Decl::ObjCCategoryImpl:
492 case Decl::ObjCImplementation:
497 if (!isa<RecordDecl>(DeclCtx))
502 if (isPrivateProtoDecl(ND))
504 if (!Opts.CollectReserved &&
506 ASTCtx.getSourceManager().isInSystemHeader(ND.getLocation()))
516 const auto *ND = dyn_cast<NamedDecl>(Enclosing);
520 Enclosing = dyn_cast_or_null<Decl>(Enclosing->getDeclContext());
527 const Decl *D, index::SymbolRoleSet Roles,
528 llvm::ArrayRef<index::SymbolRelation> Relations, SourceLocation
Loc,
529 index::IndexDataConsumer::ASTNodeInfo
ASTNode) {
530 assert(ASTCtx && PP && HeaderFileURIs);
531 assert(CompletionAllocator && CompletionTUInfo);
536 if (D->getLocation().isInvalid())
541 if ((
ASTNode.OrigD->getFriendObjectKind() !=
542 Decl::FriendObjectKind::FOK_None) &&
543 !(Roles &
static_cast<unsigned>(index::SymbolRole::Definition)))
548 if (D->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None)
549 D = CanonicalDecls.try_emplace(D,
ASTNode.OrigD).first->second;
552 bool DeclIsCanonical =
false;
555 if (
const auto *IID = dyn_cast<ObjCImplementationDecl>(D)) {
556 DeclIsCanonical =
true;
557 if (
const auto *CID = IID->getClassInterface())
558 if (
const auto *DD = CID->getDefinition())
559 if (!DD->isImplicitInterfaceDecl())
564 if (
const auto *CID = dyn_cast<ObjCCategoryImplDecl>(D)) {
565 DeclIsCanonical =
true;
566 if (
const auto *CD = CID->getCategoryDecl())
569 const NamedDecl *ND = dyn_cast<NamedDecl>(D);
573 auto ID = getSymbolIDCached(ND);
579 auto &SM = ASTCtx->getSourceManager();
581 (Roles &
static_cast<unsigned>(index::SymbolRole::Reference)) &&
582 SM.getFileID(SM.getSpellingLoc(
Loc)) == SM.getMainFileID())
583 ReferencedSymbols.insert(
ID);
588 bool IsMainFileOnly =
589 SM.isWrittenInMainFile(SM.getExpansionLoc(ND->getBeginLoc())) &&
590 !
isHeaderFile(SM.getFileEntryRefForID(SM.getMainFileID())->getName(),
591 ASTCtx->getLangOpts());
593 if (
ASTNode.OrigD->isImplicit() ||
601 processRelations(*ND,
ID, Relations);
603 bool CollectRef =
static_cast<bool>(Opts.
RefFilter & toRefKind(Roles));
610 ND->isExternallyVisible()) &&
611 !isa<NamespaceDecl>(ND)) {
612 auto FileLoc = SM.getFileLoc(
Loc);
613 auto FID = SM.getFileID(FileLoc);
615 addRef(
ID, SymbolRef{FileLoc, FID, Roles,
617 isSpelled(FileLoc, *ND)});
621 if (!(Roles & (
static_cast<unsigned>(index::SymbolRole::Declaration) |
622 static_cast<unsigned>(index::SymbolRole::Definition))))
628 auto *OriginalDecl = dyn_cast<NamedDecl>(
ASTNode.OrigD);
633 if (isPreferredDeclaration(*OriginalDecl, Roles))
638 BasicSymbol = addDeclaration(*OriginalDecl, std::move(
ID), IsMainFileOnly);
639 else if (!BasicSymbol || DeclIsCanonical)
640 BasicSymbol = addDeclaration(*ND, std::move(
ID), IsMainFileOnly);
642 if (Roles &
static_cast<unsigned>(index::SymbolRole::Definition))
643 addDefinition(*OriginalDecl, *BasicSymbol);
649 assert(HeaderFileURIs && PP);
650 const auto &SM = PP->getSourceManager();
651 const auto MainFileEntryRef = SM.getFileEntryRefForID(SM.getMainFileID());
652 assert(MainFileEntryRef);
654 const std::string &MainFileURI = HeaderFileURIs->toURI(*MainFileEntryRef);
656 for (
const auto &IDToRefs : MacroRefsToIndex.
MacroRefs) {
657 for (
const auto &MacroRef : IDToRefs.second) {
658 const auto &
Range = MacroRef.toRange(SM);
659 bool IsDefinition = MacroRef.IsDefinition;
667 Refs.
insert(IDToRefs.first, R);
670 S.ID = IDToRefs.first;
673 S.Name =
toSourceCode(SM, SourceRange(StartLoc, EndLoc));
674 S.SymInfo.Kind = index::SymbolKind::Macro;
675 S.SymInfo.SubKind = index::SymbolSubKind::None;
676 S.SymInfo.Properties = index::SymbolPropertySet();
677 S.SymInfo.Lang = index::SymbolLanguage::C;
679 S.CanonicalDeclaration = R.
Location;
682 if (!HeaderFileURIs->getIncludeHeader(SM.getMainFileID()).empty()) {
694 index::SymbolRoleSet Roles,
695 SourceLocation
Loc) {
698 if (MI->isBuiltinMacro())
701 const auto &SM = PP->getSourceManager();
702 auto DefLoc = MI->getDefinitionLoc();
705 if (SM.isWrittenInBuiltinFile(DefLoc) ||
706 SM.isWrittenInCommandLineFile(DefLoc) ||
707 Name->getName() ==
"__GCC_HAVE_DWARF2_CFI_ASM")
710 auto ID = getSymbolIDCached(
Name->getName(), MI, SM);
714 auto SpellingLoc = SM.getSpellingLoc(
Loc);
715 bool IsMainFileOnly =
716 SM.isInMainFile(SM.getExpansionLoc(DefLoc)) &&
717 !
isHeaderFile(SM.getFileEntryRefForID(SM.getMainFileID())->getName(),
718 ASTCtx->getLangOpts());
720 if ((
static_cast<unsigned>(Opts.
RefFilter) & Roles) && !IsMainFileOnly &&
721 (Opts.
RefsInHeaders || SM.getFileID(SpellingLoc) == SM.getMainFileID())) {
725 addRef(
ID, SymbolRef{
Loc, SM.getFileID(
Loc), Roles,
nullptr,
741 (Roles &
static_cast<unsigned>(index::SymbolRole::Reference)) &&
742 SM.getFileID(SpellingLoc) == SM.getMainFileID())
743 ReferencedSymbols.insert(
ID);
747 if (!(Roles &
static_cast<unsigned>(index::SymbolRole::Declaration) ||
748 Roles &
static_cast<unsigned>(index::SymbolRole::Definition)))
752 if (Symbols.
find(
ID) !=
nullptr)
756 S.ID = std::move(
ID);
757 S.Name =
Name->getName();
758 if (!IsMainFileOnly) {
762 S.SymInfo = index::getSymbolInfoForMacro(*MI);
766 if (
auto DeclLoc = getTokenLocation(DefLoc))
767 S.CanonicalDeclaration = *DeclLoc;
769 CodeCompletionResult SymbolCompletion(
Name);
770 const auto *CCS = SymbolCompletion.CreateCodeCompletionStringForMacro(
771 *PP, *CompletionAllocator, *CompletionTUInfo);
775 SymbolCompletion.CursorKind);
779 IndexedMacros.insert(
Name);
781 setIncludeLocation(S, DefLoc, include_cleaner::Macro{
Name, DefLoc});
786void SymbolCollector::processRelations(
788 ArrayRef<index::SymbolRelation> Relations) {
789 for (
const auto &R : Relations) {
790 auto RKind = indexableRelation(R);
795 auto ObjectID = getSymbolIDCached(
Object);
809 this->Relations.insert({
ID, *RKind, ObjectID});
811 this->Relations.insert({ObjectID, *RKind,
ID});
815void SymbolCollector::setIncludeLocation(
const Symbol &S, SourceLocation DefLoc,
816 const include_cleaner::Symbol &Sym) {
817 const auto &SM = PP->getSourceManager();
824 IncludeFiles[S.ID] = SM.getDecomposedExpansionLoc(DefLoc).first;
829 auto [It, Inserted] = SymbolProviders.try_emplace(S.ID);
835 auto *HeadersIter = Headers.begin();
836 include_cleaner::Header H = *HeadersIter;
837 while (HeadersIter != Headers.end() &&
838 H.kind() == include_cleaner::Header::Physical &&
839 !tooling::isSelfContainedHeader(H.physical(), SM,
840 PP->getHeaderSearchInfo())) {
848 tooling::stdlib::Lang
Lang = tooling::stdlib::Lang::CXX;
850 Lang = tooling::stdlib::Lang::C;
851 else if(!LangOpts.CPlusPlus)
854 if (S->Scope ==
"std::" && S->Name ==
"move") {
855 if (!S->Signature.contains(
','))
857 return "<algorithm>";
860 if (
auto StdSym = tooling::stdlib::Symbol::named(S->Scope, S->Name,
Lang))
861 if (
auto Header = StdSym->header())
862 return Header->name();
868 for (
const auto &
ID : ReferencedSymbols) {
869 if (
const auto *S = Symbols.
find(
ID)) {
880 for (
const IdentifierInfo *II : IndexedMacros) {
881 if (
const auto *MI = PP->getMacroDefinition(II).getMacroInfo())
883 getSymbolIDCached(II->getName(), MI, PP->getSourceManager()))
884 if (MI->isUsedForHeaderGuard())
888 llvm::DenseMap<FileID, bool> FileToContainsImportsOrObjC;
889 llvm::DenseMap<include_cleaner::Header, std::string> HeaderSpelling;
892 for (
const auto &[SID, OptionalProvider] : SymbolProviders) {
896 assert(IncludeFiles.contains(SID));
898 const auto FID = IncludeFiles.at(SID);
901 auto CollectDirectives = shouldCollectIncludePath(S->SymInfo.Kind);
906 auto [It, Inserted] = FileToContainsImportsOrObjC.try_emplace(FID);
908 It->second = FilesWithObjCConstructs.contains(FID) ||
909 tooling::codeContainsImports(
910 ASTCtx->getSourceManager().getBufferData(FID));
920 llvm::StringRef IncludeHeader =
getStdHeader(S, ASTCtx->getLangOpts());
921 if (IncludeHeader.empty())
922 IncludeHeader = HeaderFileURIs->getIncludeHeader(FID);
924 if (!IncludeHeader.empty()) {
926 NewSym.IncludeHeaders.push_back({IncludeHeader, 1, Directives});
937 if (!OptionalProvider)
939 const auto &H = *OptionalProvider;
940 const auto [SpellingIt, Inserted] = HeaderSpelling.try_emplace(H);
942 auto &SM = ASTCtx->getSourceManager();
943 if (H.kind() == include_cleaner::Header::Kind::Physical) {
947 HeaderFileURIs->mapCanonical(H.physical().getName());
949 SpellingIt->second = Canonical;
952 else if (tooling::isSelfContainedHeader(H.physical(), SM,
953 PP->getHeaderSearchInfo()))
955 HeaderFileURIs->toURI(H.physical());
957 SpellingIt->second = include_cleaner::spellHeader(
958 {H, PP->getHeaderSearchInfo(),
959 SM.getFileEntryForID(SM.getMainFileID())});
963 if (!SpellingIt->second.empty()) {
965 NewSym.IncludeHeaders.push_back({SpellingIt->second, 1, Directives});
970 ReferencedSymbols.clear();
971 IncludeFiles.clear();
972 SymbolProviders.clear();
973 FilesWithObjCConstructs.clear();
976const Symbol *SymbolCollector::addDeclaration(
const NamedDecl &ND,
SymbolID ID,
977 bool IsMainFileOnly) {
978 auto &Ctx = ND.getASTContext();
979 auto &SM = Ctx.getSourceManager();
982 S.ID = std::move(
ID);
988 S.TemplateSpecializationArgs = TemplateSpecializationArgs;
997 S.SymInfo = index::getSymbolInfo(&ND);
999 assert(
Loc.isValid() &&
"Invalid source location for NamedDecl");
1001 auto FID = SM.getFileID(
Loc);
1003 if (
auto DeclLoc = getTokenLocation(
Loc))
1004 S.CanonicalDeclaration = *DeclLoc;
1007 if (ND.getAvailability() == AR_Deprecated)
1012 assert(ASTCtx && PP &&
"ASTContext and Preprocessor must be set.");
1014 CodeCompletionResult SymbolCompletion(&getTemplateOrThis(ND), 0);
1015 const auto *CCS = SymbolCompletion.CreateCodeCompletionString(
1016 *ASTCtx, *PP, CodeCompletionContext::CCC_Symbol, *CompletionAllocator,
1019 std::string Documentation =
1024 S.Documentation = Documentation;
1026 return Symbols.
find(S.ID);
1028 S.Documentation = Documentation;
1032 SymbolCompletion.CursorKind);
1038 std::optional<OpaqueType> TypeStorage;
1042 S.Type = TypeStorage->raw();
1046 setIncludeLocation(S, ND.getLocation(), include_cleaner::Symbol{ND});
1047 if (S.SymInfo.Lang == index::SymbolLanguage::ObjC)
1048 FilesWithObjCConstructs.insert(FID);
1049 return Symbols.
find(S.ID);
1052void SymbolCollector::addDefinition(
const NamedDecl &ND,
1053 const Symbol &DeclSym) {
1054 if (DeclSym.Definition)
1056 const auto &SM = ND.getASTContext().getSourceManager();
1059 auto DefLoc = getTokenLocation(
Loc);
1067 S.Definition = *DefLoc;
1074 auto I = FilesToIndexCache.try_emplace(FID);
1076 I.first->second = Opts.
FileFilter(ASTCtx->getSourceManager(), FID);
1077 return I.first->second;
1080void SymbolCollector::addRef(
SymbolID ID,
const SymbolRef &SR) {
1081 const auto &SM = ASTCtx->getSourceManager();
1084 if (
const auto FE = SM.getFileEntryRefForID(SR.FID)) {
1085 auto Range = getTokenRange(SR.Loc, SM, ASTCtx->getLangOpts());
1090 R.
Kind = toRefKind(SR.Roles, SR.Spelled);
1091 R.
Container = getSymbolIDCached(SR.Container);
1096SymbolID SymbolCollector::getSymbolIDCached(
const Decl *D) {
1097 auto It = DeclToIDCache.try_emplace(D, SymbolID{});
1100 return It.first->second;
1104 const MacroInfo *MI,
1105 const SourceManager &SM) {
1106 auto It = MacroToIDCache.try_emplace(MI, SymbolID{});
1109 return It.first->second;
const FunctionDecl * Decl
std::string SnippetSuffix
CharSourceRange Range
SourceRange for the file name.
std::string Filename
Filename as a string.
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.
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)
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
const Symbol * find(const SymbolID &ID)
Returns the symbol with an ID, if it exists. Valid until insert/remove.
void erase(const SymbolID &ID)
Removes the symbol with an ID, if it exists.
void insert(const Symbol &S)
Adds a symbol, overwriting any existing one with the same ID.
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
std::string printTemplateSpecializationArgs(const NamedDecl &ND)
Prints template arguments of a decl as written in the source code, including enclosing '<' and '>',...
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
std::string formatDocumentation(const CodeCompletionString &CCS, llvm::StringRef DocComment)
Assembles formatted documentation for a completion result.
std::string Path
A typedef to represent a file path.
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.
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.
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.
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.
llvm::Expected< SourceLocation > sourceLocationInMainFile(const SourceManager &SM, Position P)
Return the file location, corresponding to P.
bool isImplementationDetail(const Decl *D)
Returns true if the declaration is considered implementation detail based on heuristics.
bool hasReservedScope(const DeclContext &DC)
Returns true if this scope would be written with a reserved name.
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
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).
bool isIndexedForCodeCompletion(const NamedDecl &ND, ASTContext &ASTCtx)
std::array< uint8_t, 20 > SymbolID
@ Canonical
The two mix because the types refer to the same CanonicalType, but we do not elaborate as to how.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Simplified description of a clang AST node.
llvm::DenseMap< SymbolID, std::vector< MacroOccurrence > > MacroRefs
int line
Line position in a document (zero-based).
int character
Character offset on a line in a document (zero-based).
Position start
The range's start position.
Position end
The range's end position.
Represents a symbol occurrence in the source file.
SymbolID Container
The ID of the symbol whose definition contains this reference.
SymbolLocation Location
The source location where the symbol is named.
bool CollectMacro
Collect macros.
RefKind RefFilter
The symbol ref kinds that will be collected.
bool CollectMainFileSymbols
Collect symbols local to main-files, such as static functions, symbols inside an anonymous namespace,...
bool StoreAllDocumentation
If set to true, SymbolCollector will collect doc for all symbols.
bool CollectMainFileRefs
Collect references to main-file symbols.
bool RefsInHeaders
If set to true, SymbolCollector will collect all refs (from main file and included headers); otherwis...
const include_cleaner::PragmaIncludes * PragmaIncludes
If set, this is used to map symbol #include path to a potentially different #include path specified b...
std::function< bool(const SourceManager &, FileID)> FileFilter
If this is set, only collect symbols/references from a file if FileFilter(SM, FID) is true.
void setColumn(uint32_t Column)
void setLine(uint32_t Line)
Position Start
The symbol range, using half-open range [Start, End).
The class presents a C++ symbol, e.g.
@ IndexedForCodeCompletion
Whether or not this symbol is meant to be used for the code completion.
@ Deprecated
Indicates if the symbol is deprecated.
@ ImplementationDetail
Symbol is an implementation detail.
@ VisibleOutsideFile
Symbol is visible to other files (not e.g. a static helper function).
@ Include
#include "header.h"
@ Import
#import "header.h"