12#include "clang-include-cleaner/Record.h"
17#include "clang/AST/ASTConsumer.h"
18#include "clang/AST/ASTContext.h"
19#include "clang/Basic/SourceLocation.h"
20#include "clang/Basic/SourceManager.h"
21#include "clang/Frontend/CompilerInstance.h"
22#include "clang/Frontend/FrontendAction.h"
23#include "clang/Index/IndexingAction.h"
24#include "clang/Index/IndexingOptions.h"
34std::optional<std::string> toURI(OptionalFileEntryRef
File) {
37 auto AbsolutePath =
File->getFileEntry().tryGetRealPathName();
38 if (AbsolutePath.empty())
46struct IncludeGraphCollector :
public PPCallbacks {
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,
89 llvm::StringRef FileName,
bool IsAngled,
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(IndexFileIn)> IndexContentsCallback)
135 : IndexContentsCallback(IndexContentsCallback), Collector(
C),
136 PI(std::move(PI)), Opts(Opts) {
137 this->Opts.ShouldTraverseDecl = [
this](
const Decl *
D) {
146 if (
auto *FT = llvm::dyn_cast<clang::FunctionTemplateDecl>(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 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 {
184 Result.Symbols = Collector->takeSymbols();
185 Result.Refs = Collector->takeRefs();
186 Result.Relations = Collector->takeRelations();
189 for (
const auto &Node : IG)
190 assert(Node.getKeyData() == Node.getValue().URI.data());
192 Result.Sources = std::move(IG);
193 IndexContentsCallback(std::move(Result));
197 std::function<void(IndexFileIn)> IndexContentsCallback;
198 std::shared_ptr<SymbolCollector> Collector;
199 std::unique_ptr<include_cleaner::PragmaIncludes> PI;
200 index::IndexingOptions Opts;
208 std::function<
void(
IndexFileIn)> IndexContentsCallback) {
209 index::IndexingOptions IndexOpts;
210 IndexOpts.SystemSymbolFilter =
211 index::IndexingOptions::SystemSymbolFilterKind::All;
213 IndexOpts.IndexFunctionLocals =
true;
216 IndexOpts.DeferIndexingToEndOfTranslationUnit =
true;
223 auto PragmaIncludes = std::make_unique<include_cleaner::PragmaIncludes>();
225 return std::make_unique<IndexAction>(std::make_shared<SymbolCollector>(Opts),
226 std::move(PragmaIncludes), IndexOpts,
227 IndexContentsCallback);
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(IndexFileIn)> IndexContentsCallback)
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 ...