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"
34std::optional<std::string> toURI(OptionalFileEntryRef
File) {
37 auto AbsolutePath =
File->getFileEntry().tryGetRealPathName();
38 if (AbsolutePath.empty())
48 IncludeGraphCollector(
const SourceManager &SM,
IncludeGraph &IG)
55 void FileChanged(SourceLocation
Loc, FileChangeReason Reason,
56 SrcMgr::CharacteristicKind FileType,
57 FileID PrevFID)
override {
60 if (Reason != FileChangeReason::EnterFile)
63 const auto FileID = SM.getFileID(
Loc);
64 auto File = SM.getFileEntryRefForID(FileID);
65 auto URI = toURI(
File);
68 auto I = IG.try_emplace(*URI).first;
70 auto &Node = I->getValue();
72 if (
Node.URI.data() == I->getKeyData()) {
75 assert(Digest &&
Node.Digest == *Digest &&
76 "Same file, different digest?");
81 Node.Digest = std::move(*Digest);
82 if (FileID == SM.getMainFileID())
84 Node.URI = I->getKey();
88 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
90 CharSourceRange FilenameRange,
91 OptionalFileEntryRef
File, llvm::StringRef SearchPath,
92 llvm::StringRef RelativePath,
const Module *Imported,
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) {
148 auto &SM = D->getASTContext().getSourceManager();
149 auto FID = SM.getFileID(SM.getExpansionLoc(D->getLocation()));
152 return Collector->shouldIndexFile(FID);
156 std::unique_ptr<ASTConsumer>
157 CreateASTConsumer(CompilerInstance &
CI, llvm::StringRef InFile)
override {
158 PI->record(
CI.getPreprocessor());
159 if (IncludeGraphCallback !=
nullptr)
160 CI.getPreprocessor().addPPCallbacks(
161 std::make_unique<IncludeGraphCollector>(
CI.getSourceManager(), IG));
163 return index::createIndexingASTConsumer(Collector, Opts,
164 CI.getPreprocessorPtr());
167 bool BeginInvocation(CompilerInstance &
CI)
override {
169 CI.getLangOpts().CommentOpts.ParseAllComments =
true;
170 CI.getLangOpts().RetainCommentsFromSystemHeaders =
true;
173 CI.getDiagnosticOpts().IgnoreWarnings =
true;
174 CI.getDiagnostics().setIgnoreAllWarnings(
true);
178 CI.getFrontendOpts().SkipFunctionBodies =
true;
182 void EndSourceFileAction()
override {
183 SymbolsCallback(Collector->takeSymbols());
184 if (RefsCallback !=
nullptr)
185 RefsCallback(Collector->takeRefs());
186 if (RelationsCallback !=
nullptr)
187 RelationsCallback(Collector->takeRelations());
188 if (IncludeGraphCallback !=
nullptr) {
191 for (
const auto &Node : IG)
192 assert(
Node.getKeyData() ==
Node.getValue().URI.data());
194 IncludeGraphCallback(std::move(IG));
199 std::function<void(SymbolSlab)> SymbolsCallback;
200 std::function<void(RefSlab)> RefsCallback;
201 std::function<void(RelationSlab)> RelationsCallback;
203 std::shared_ptr<SymbolCollector> Collector;
204 std::unique_ptr<include_cleaner::PragmaIncludes> PI;
205 index::IndexingOptions Opts;
213 std::function<
void(
SymbolSlab)> SymbolsCallback,
214 std::function<
void(
RefSlab)> RefsCallback,
216 std::function<
void(
IncludeGraph)> IncludeGraphCallback) {
217 index::IndexingOptions IndexOpts;
218 IndexOpts.SystemSymbolFilter =
219 index::IndexingOptions::SystemSymbolFilterKind::All;
221 IndexOpts.IndexFunctionLocals =
true;
222 Opts.CollectIncludePath =
true;
225 Opts.StoreAllDocumentation =
false;
226 if (RefsCallback !=
nullptr) {
228 Opts.RefsInHeaders =
true;
230 auto PragmaIncludes = std::make_unique<include_cleaner::PragmaIncludes>();
231 Opts.PragmaIncludes = PragmaIncludes.get();
232 return std::make_unique<IndexAction>(std::make_shared<SymbolCollector>(Opts),
233 std::move(PragmaIncludes), IndexOpts,
234 SymbolsCallback, RefsCallback,
235 RelationsCallback, IncludeGraphCallback);
const FunctionDecl * Decl
bool IsAngled
true if this was an include with angle brackets
::clang::DynTypedNode Node
std::unique_ptr< CompilerInvocation > CI
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.
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++ -*-===//