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,
93 const Module *SuggestedModule,
bool ModuleImported,
94 SrcMgr::CharacteristicKind FileType)
override {
95 auto IncludeURI = toURI(
File);
99 auto IncludingURI = toURI(SM.getFileEntryRefForID(SM.getFileID(HashLoc)));
103 auto NodeForInclude = IG.try_emplace(*IncludeURI).first->getKey();
104 auto NodeForIncluding = IG.try_emplace(*IncludingURI);
106 NodeForIncluding.first->getValue().DirectIncludes.push_back(NodeForInclude);
110 void FileSkipped(
const FileEntryRef &SkippedFile,
const Token &FilenameTok,
111 SrcMgr::CharacteristicKind FileType)
override {
113 auto URI = toURI(SkippedFile);
116 auto I = IG.try_emplace(*URI);
117 assert(!I.second &&
"File inserted for the first time on skip.");
118 assert(I.first->getKeyData() == I.first->getValue().URI.data() &&
119 "Node have not been populated yet");
124 const SourceManager &SM;
129class IndexAction :
public ASTFrontendAction {
131 IndexAction(std::shared_ptr<SymbolCollector>
C,
132 std::unique_ptr<include_cleaner::PragmaIncludes> PI,
133 const index::IndexingOptions &Opts,
134 std::function<
void(SymbolSlab)> SymbolsCallback,
135 std::function<
void(RefSlab)> RefsCallback,
136 std::function<
void(RelationSlab)> RelationsCallback,
138 : SymbolsCallback(SymbolsCallback), RefsCallback(RefsCallback),
139 RelationsCallback(RelationsCallback),
140 IncludeGraphCallback(IncludeGraphCallback), Collector(
C),
141 PI(std::move(PI)), Opts(Opts) {
142 this->Opts.ShouldTraverseDecl = [
this](
const Decl *D) {
149 auto &SM = D->getASTContext().getSourceManager();
150 auto FID = SM.getFileID(SM.getExpansionLoc(D->getLocation()));
153 return Collector->shouldIndexFile(FID);
157 std::unique_ptr<ASTConsumer>
158 CreateASTConsumer(CompilerInstance &
CI, llvm::StringRef InFile)
override {
159 PI->record(
CI.getPreprocessor());
160 if (IncludeGraphCallback !=
nullptr)
161 CI.getPreprocessor().addPPCallbacks(
162 std::make_unique<IncludeGraphCollector>(
CI.getSourceManager(), IG));
164 return index::createIndexingASTConsumer(Collector, Opts,
165 CI.getPreprocessorPtr());
168 bool BeginInvocation(CompilerInstance &
CI)
override {
170 CI.getLangOpts().CommentOpts.ParseAllComments =
true;
171 CI.getLangOpts().RetainCommentsFromSystemHeaders =
true;
174 CI.getDiagnosticOpts().IgnoreWarnings =
true;
175 CI.getDiagnostics().setIgnoreAllWarnings(
true);
179 CI.getFrontendOpts().SkipFunctionBodies =
true;
183 void EndSourceFileAction()
override {
184 SymbolsCallback(Collector->takeSymbols());
185 if (RefsCallback !=
nullptr)
186 RefsCallback(Collector->takeRefs());
187 if (RelationsCallback !=
nullptr)
188 RelationsCallback(Collector->takeRelations());
189 if (IncludeGraphCallback !=
nullptr) {
192 for (
const auto &Node : IG)
193 assert(
Node.getKeyData() ==
Node.getValue().URI.data());
195 IncludeGraphCallback(std::move(IG));
200 std::function<void(SymbolSlab)> SymbolsCallback;
201 std::function<void(RefSlab)> RefsCallback;
202 std::function<void(RelationSlab)> RelationsCallback;
204 std::shared_ptr<SymbolCollector> Collector;
205 std::unique_ptr<include_cleaner::PragmaIncludes> PI;
206 index::IndexingOptions Opts;
214 std::function<
void(
SymbolSlab)> SymbolsCallback,
215 std::function<
void(
RefSlab)> RefsCallback,
217 std::function<
void(
IncludeGraph)> IncludeGraphCallback) {
218 index::IndexingOptions IndexOpts;
219 IndexOpts.SystemSymbolFilter =
220 index::IndexingOptions::SystemSymbolFilterKind::All;
222 IndexOpts.IndexFunctionLocals =
true;
223 Opts.CollectIncludePath =
true;
226 Opts.StoreAllDocumentation =
false;
227 if (RefsCallback !=
nullptr) {
229 Opts.RefsInHeaders =
true;
231 auto PragmaIncludes = std::make_unique<include_cleaner::PragmaIncludes>();
232 Opts.PragmaIncludes = PragmaIncludes.get();
233 return std::make_unique<IndexAction>(std::make_shared<SymbolCollector>(Opts),
234 std::move(PragmaIncludes), IndexOpts,
235 SymbolsCallback, RefsCallback,
236 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++ -*-===//