14 #include "clang/AST/ASTConsumer.h" 15 #include "clang/AST/ASTContext.h" 16 #include "clang/Basic/SourceLocation.h" 17 #include "clang/Basic/SourceManager.h" 18 #include "clang/Frontend/CompilerInstance.h" 19 #include "clang/Frontend/MultiplexConsumer.h" 20 #include "clang/Index/IndexingAction.h" 21 #include "clang/Tooling/Tooling.h" 22 #include "llvm/ADT/STLExtras.h" 31 llvm::Optional<std::string> toURI(
const FileEntry *File) {
34 auto AbsolutePath = File->tryGetRealPathName();
35 if (AbsolutePath.empty())
45 IncludeGraphCollector(
const SourceManager &SM,
IncludeGraph &IG)
52 void FileChanged(SourceLocation
Loc, FileChangeReason Reason,
53 SrcMgr::CharacteristicKind FileType,
54 FileID PrevFID)
override {
57 if (Reason != FileChangeReason::EnterFile)
60 const auto FileID = SM.getFileID(Loc);
61 const auto File = SM.getFileEntryForID(FileID);
62 auto URI = toURI(File);
65 auto I = IG.try_emplace(*URI).first;
67 auto &Node = I->getValue();
69 if (Node.URI.data() == I->getKeyData()) {
72 assert(Digest && Node.Digest == *Digest &&
73 "Same file, different digest?");
78 Node.Digest = std::move(*Digest);
79 if (FileID == SM.getMainFileID())
81 Node.URI = I->getKey();
85 void InclusionDirective(SourceLocation HashLoc,
const Token &IncludeTok,
87 CharSourceRange FilenameRange,
const FileEntry *File,
88 llvm::StringRef SearchPath,
89 llvm::StringRef RelativePath,
const Module *Imported,
90 SrcMgr::CharacteristicKind FileType)
override {
91 auto IncludeURI = toURI(File);
95 auto IncludingURI = toURI(SM.getFileEntryForID(SM.getFileID(HashLoc)));
99 auto NodeForInclude = IG.try_emplace(*IncludeURI).first->getKey();
100 auto NodeForIncluding = IG.try_emplace(*IncludingURI);
102 NodeForIncluding.first->getValue().DirectIncludes.push_back(NodeForInclude);
106 void FileSkipped(
const FileEntry &SkippedFile,
const Token &FilenameTok,
107 SrcMgr::CharacteristicKind FileType)
override {
109 auto URI = toURI(&SkippedFile);
112 auto I = IG.try_emplace(*URI);
113 assert(!I.second &&
"File inserted for the first time on skip.");
114 assert(I.first->getKeyData() == I.first->getValue().URI.data() &&
115 "Node have not been populated yet");
120 const SourceManager &SM;
127 static std::unique_ptr<ASTConsumer>
128 skipProcessedFunctions(std::unique_ptr<ASTConsumer> Inner,
129 std::function<
bool(FileID)> ShouldIndexFile) {
130 class SkipProcessedFunctions :
public ASTConsumer {
132 SkipProcessedFunctions(std::function<
bool(FileID)> FileFilter)
133 : ShouldIndexFile(std::move(FileFilter)), Context(nullptr) {
134 assert(this->ShouldIndexFile);
137 void Initialize(ASTContext &Context)
override { this->Context = &Context; }
138 bool shouldSkipFunctionBody(Decl *
D)
override {
139 assert(Context &&
"Initialize() was never called.");
140 auto &SM = Context->getSourceManager();
141 auto FID = SM.getFileID(SM.getExpansionLoc(D->getLocation()));
144 return !ShouldIndexFile(FID);
148 std::function<bool(FileID)> ShouldIndexFile;
149 const ASTContext *Context;
151 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
153 llvm::make_unique<SkipProcessedFunctions>(ShouldIndexFile));
154 Consumers.push_back(std::move(Inner));
155 return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
159 class IndexAction :
public WrapperFrontendAction {
161 IndexAction(std::shared_ptr<SymbolCollector> C,
162 std::unique_ptr<CanonicalIncludes> Includes,
163 const index::IndexingOptions &Opts,
164 std::function<
void(SymbolSlab)> SymbolsCallback,
165 std::function<
void(RefSlab)> RefsCallback,
166 std::function<
void(RelationSlab)> RelationsCallback,
168 : WrapperFrontendAction(index::createIndexingAction(C, Opts, nullptr)),
169 SymbolsCallback(SymbolsCallback), RefsCallback(RefsCallback),
170 RelationsCallback(RelationsCallback),
171 IncludeGraphCallback(IncludeGraphCallback),
Collector(C),
172 Includes(std::move(Includes)),
175 std::unique_ptr<ASTConsumer>
176 CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile)
override {
179 if (IncludeGraphCallback !=
nullptr)
180 CI.getPreprocessor().addPPCallbacks(
181 llvm::make_unique<IncludeGraphCollector>(CI.getSourceManager(), IG));
182 return skipProcessedFunctions(
183 WrapperFrontendAction::CreateASTConsumer(CI, InFile),
184 [
this](FileID FID) {
return Collector->shouldIndexFile(FID); });
187 bool BeginInvocation(CompilerInstance &CI)
override {
189 CI.getLangOpts().CommentOpts.ParseAllComments =
true;
192 CI.getDiagnosticOpts().IgnoreWarnings =
true;
193 CI.getDiagnostics().setIgnoreAllWarnings(
true);
197 CI.getFrontendOpts().SkipFunctionBodies =
true;
199 return WrapperFrontendAction::BeginInvocation(CI);
202 void EndSourceFileAction()
override {
203 WrapperFrontendAction::EndSourceFileAction();
205 SymbolsCallback(
Collector->takeSymbols());
206 if (RefsCallback !=
nullptr)
208 if (RelationsCallback !=
nullptr)
209 RelationsCallback(
Collector->takeRelations());
210 if (IncludeGraphCallback !=
nullptr) {
213 for (
const auto &Node : IG)
214 assert(Node.getKeyData() == Node.getValue().URI.data());
216 IncludeGraphCallback(std::move(IG));
221 std::function<void(SymbolSlab)> SymbolsCallback;
222 std::function<void(RefSlab)> RefsCallback;
223 std::function<void(RelationSlab)> RelationsCallback;
224 std::function<void(IncludeGraph)> IncludeGraphCallback;
225 std::shared_ptr<SymbolCollector>
Collector;
226 std::unique_ptr<CanonicalIncludes> Includes;
235 std::function<
void(
SymbolSlab)> SymbolsCallback,
236 std::function<
void(
RefSlab)> RefsCallback,
238 std::function<
void(
IncludeGraph)> IncludeGraphCallback) {
239 index::IndexingOptions IndexOpts;
240 IndexOpts.SystemSymbolFilter =
241 index::IndexingOptions::SystemSymbolFilterKind::All;
246 if (RefsCallback !=
nullptr) {
250 auto Includes = llvm::make_unique<CanonicalIncludes>();
252 return llvm::make_unique<IndexAction>(
253 std::make_shared<SymbolCollector>(std::move(Opts)), std::move(Includes),
254 IndexOpts, SymbolsCallback, RefsCallback, RelationsCallback,
255 IncludeGraphCallback);
std::unique_ptr< CommentHandler > collectIWYUHeaderMaps(CanonicalIncludes *Includes)
Returns a CommentHandler that parses pragma comment on include files to determine when we should incl...
SourceLocation Loc
'#' location in the include directive
An immutable symbol container that stores a set of symbols.
An efficient structure of storing large set of symbol references in memory.
void addSystemHeadersMapping(CanonicalIncludes *Includes, const LangOptions &Language)
Adds mapping for system headers and some special symbols (e.g.
Documents should not be synced at all.
llvm::StringMap< IncludeGraphNode > IncludeGraph
bool StoreAllDocumentation
If set to true, SymbolCollector will collect doc for all symbols.
bool IsAngled
true if this was an include with angle brackets
std::shared_ptr< SymbolCollector > Collector
llvm::Optional< FileDigest > digestFile(const SourceManager &SM, FileID FID)
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
bool RefsInHeaders
If set to true, SymbolCollector will collect all refs (from main file and included headers); otherwis...
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
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)
const CanonicalIncludes * Includes
If set, this is used to map symbol #include path to a potentially different #include path...
RefKind RefFilter
The symbol ref kinds that will be collected.
CommentHandler * PragmaHandler