12#include "clang-include-cleaner/Record.h"
16#include "clang/AST/ASTConsumer.h"
17#include "clang/AST/ASTContext.h"
18#include "clang/Basic/SourceLocation.h"
19#include "clang/Basic/SourceManager.h"
20#include "clang/Frontend/CompilerInstance.h"
21#include "clang/Frontend/FrontendAction.h"
22#include "clang/Index/IndexingAction.h"
23#include "clang/Index/IndexingOptions.h"
33std::optional<std::string> toURI(OptionalFileEntryRef
File) {
36 auto AbsolutePath =
File->getFileEntry().tryGetRealPathName();
37 if (AbsolutePath.empty())
45struct IncludeGraphCollector :
public PPCallbacks {
47 IncludeGraphCollector(
const SourceManager &SM,
IncludeGraph &IG)
54 void FileChanged(SourceLocation Loc, FileChangeReason Reason,
55 SrcMgr::CharacteristicKind FileType,
56 FileID PrevFID)
override {
59 if (Reason != FileChangeReason::EnterFile)
62 const auto FileID = SM.getFileID(Loc);
63 auto File = SM.getFileEntryRefForID(FileID);
64 auto URI = toURI(
File);
67 auto I = IG.try_emplace(*URI).first;
69 auto &Node = I->getValue();
71 if (Node.URI.data() == I->getKeyData()) {
74 assert(Digest && Node.Digest == *Digest &&
75 "Same file, different digest?");
80 Node.Digest = std::move(*Digest);
81 if (FileID == SM.getMainFileID())
83 Node.URI = I->getKey();
87 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
88 llvm::StringRef FileName,
bool IsAngled,
89 CharSourceRange FilenameRange,
90 OptionalFileEntryRef
File, llvm::StringRef SearchPath,
91 llvm::StringRef RelativePath,
92 const Module *SuggestedModule,
bool ModuleImported,
93 SrcMgr::CharacteristicKind FileType)
override {
94 auto IncludeURI = toURI(
File);
98 auto IncludingURI = toURI(SM.getFileEntryRefForID(SM.getFileID(HashLoc)));
102 auto NodeForInclude = IG.try_emplace(*IncludeURI).first->getKey();
103 auto NodeForIncluding = IG.try_emplace(*IncludingURI);
105 NodeForIncluding.first->getValue().DirectIncludes.push_back(NodeForInclude);
109 void FileSkipped(
const FileEntryRef &SkippedFile,
const Token &FilenameTok,
110 SrcMgr::CharacteristicKind FileType)
override {
112 auto URI = toURI(SkippedFile);
115 auto I = IG.try_emplace(*URI);
116 assert(!I.second &&
"File inserted for the first time on skip.");
117 assert(I.first->getKeyData() == I.first->getValue().URI.data() &&
118 "Node have not been populated yet");
123 const SourceManager &SM;
128class IndexAction :
public ASTFrontendAction {
130 IndexAction(std::shared_ptr<SymbolCollector> C,
131 std::unique_ptr<include_cleaner::PragmaIncludes> PI,
132 const index::IndexingOptions &Opts,
133 std::function<
void(SymbolSlab)> SymbolsCallback,
134 std::function<
void(RefSlab)> RefsCallback,
135 std::function<
void(RelationSlab)> RelationsCallback,
137 : SymbolsCallback(SymbolsCallback), RefsCallback(RefsCallback),
138 RelationsCallback(RelationsCallback),
139 IncludeGraphCallback(IncludeGraphCallback), Collector(
C),
140 PI(std::move(PI)), Opts(Opts) {
141 this->Opts.ShouldTraverseDecl = [
this](
const Decl *
D) {
150 if (
auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(D);
153 auto &SM =
D->getASTContext().getSourceManager();
154 auto FID = SM.getFileID(SM.getExpansionLoc(
D->getLocation()));
157 return Collector->shouldIndexFile(FID);
161 std::unique_ptr<ASTConsumer>
162 CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile)
override {
163 PI->record(CI.getPreprocessor());
164 if (IncludeGraphCallback !=
nullptr)
165 CI.getPreprocessor().addPPCallbacks(
166 std::make_unique<IncludeGraphCollector>(CI.getSourceManager(), IG));
168 return index::createIndexingASTConsumer(Collector, Opts,
169 CI.getPreprocessorPtr());
172 bool BeginInvocation(CompilerInstance &CI)
override {
174 CI.getLangOpts().CommentOpts.ParseAllComments =
true;
175 CI.getLangOpts().RetainCommentsFromSystemHeaders =
true;
178 CI.getDiagnosticOpts().IgnoreWarnings =
true;
179 CI.getDiagnostics().setIgnoreAllWarnings(
true);
183 CI.getFrontendOpts().SkipFunctionBodies =
true;
187 void EndSourceFileAction()
override {
188 SymbolsCallback(Collector->takeSymbols());
189 if (RefsCallback !=
nullptr)
190 RefsCallback(Collector->takeRefs());
191 if (RelationsCallback !=
nullptr)
192 RelationsCallback(Collector->takeRelations());
193 if (IncludeGraphCallback !=
nullptr) {
196 for (
const auto &Node : IG)
197 assert(Node.getKeyData() == Node.getValue().URI.data());
199 IncludeGraphCallback(std::move(IG));
204 std::function<void(SymbolSlab)> SymbolsCallback;
205 std::function<void(RefSlab)> RefsCallback;
206 std::function<void(RelationSlab)> RelationsCallback;
208 std::shared_ptr<SymbolCollector> Collector;
209 std::unique_ptr<include_cleaner::PragmaIncludes> PI;
210 index::IndexingOptions Opts;
218 std::function<
void(
SymbolSlab)> SymbolsCallback,
219 std::function<
void(
RefSlab)> RefsCallback,
221 std::function<
void(
IncludeGraph)> IncludeGraphCallback) {
222 index::IndexingOptions IndexOpts;
223 IndexOpts.SystemSymbolFilter =
224 index::IndexingOptions::SystemSymbolFilterKind::All;
226 IndexOpts.IndexFunctionLocals =
true;
229 IndexOpts.DeferIndexingToEndOfTranslationUnit =
true;
234 if (RefsCallback !=
nullptr) {
238 auto PragmaIncludes = std::make_unique<include_cleaner::PragmaIncludes>();
240 return std::make_unique<IndexAction>(std::make_shared<SymbolCollector>(Opts),
241 std::move(PragmaIncludes), IndexOpts,
242 SymbolsCallback, RefsCallback,
243 RelationsCallback, IncludeGraphCallback);
An efficient structure of storing large set of symbol references in memory.
An immutable symbol container that stores a set of symbols.
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
bool isLikelyForwardingFunction(const FunctionTemplateDecl *FT)
Heuristic that checks if FT is likely to be forwarding a parameter pack to another function (e....
std::optional< FileDigest > digestFile(const SourceManager &SM, FileID FID)
llvm::StringMap< IncludeGraphNode > IncludeGraph
std::unique_ptr< FrontendAction > createStaticIndexingAction(SymbolCollector::Options Opts, std::function< void(SymbolSlab)> SymbolsCallback, std::function< void(RefSlab)> RefsCallback, std::function< void(RelationSlab)> RelationsCallback, std::function< void(IncludeGraph)> IncludeGraphCallback)
bool isDeeplyNested(const Decl *D, unsigned MaxDepth)
Checks whether D is more than MaxDepth away from translation unit scope.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
RefKind RefFilter
The symbol ref kinds that will be collected.
bool StoreAllDocumentation
If set to true, SymbolCollector will collect doc for all 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 by ...