12 #include "clang/Basic/SourceLocation.h" 13 #include "clang/Lex/PPCallbacks.h" 14 #include "clang/Lex/PreprocessorOptions.h" 20 bool compileCommandsAreEqual(
const tooling::CompileCommand &LHS,
21 const tooling::CompileCommand &RHS) {
23 return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
24 llvm::makeArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
27 class CppFilePreambleCallbacks :
public PreambleCallbacks {
30 : File(File), ParsedCallback(ParsedCallback) {}
32 IncludeStructure takeIncludes() {
return std::move(Includes); }
34 MainFileMacros takeMacros() {
return std::move(Macros); }
36 CanonicalIncludes takeCanonicalIncludes() {
return std::move(CanonIncludes); }
38 void AfterExecute(CompilerInstance &CI)
override {
41 trace::Span Tracer(
"Running PreambleCallback");
42 ParsedCallback(CI.getASTContext(), CI.getPreprocessorPtr(), CanonIncludes);
45 void BeforeExecute(CompilerInstance &CI)
override {
46 CanonIncludes.addSystemHeadersMapping(CI.getLangOpts());
47 LangOpts = &CI.getLangOpts();
48 SourceMgr = &CI.getSourceManager();
51 std::unique_ptr<PPCallbacks> createPPCallbacks()
override {
52 assert(SourceMgr && LangOpts &&
53 "SourceMgr and LangOpts must be set at this point");
55 return std::make_unique<PPChainedCallbacks>(
57 std::make_unique<CollectMainFileMacros>(*SourceMgr, *LangOpts, Macros));
60 CommentHandler *getCommentHandler()
override {
62 return IWYUHandler.get();
68 IncludeStructure Includes;
69 CanonicalIncludes CanonIncludes;
70 MainFileMacros Macros;
71 std::unique_ptr<CommentHandler> IWYUHandler =
nullptr;
72 const clang::LangOptions *LangOpts =
nullptr;
73 const SourceManager *SourceMgr =
nullptr;
81 std::unique_ptr<PreambleFileStatusCache> StatCache,
83 : Preamble(std::move(Preamble)), Diags(std::move(Diags)),
84 Includes(std::move(Includes)), Macros(std::move(Macros)),
85 StatCache(std::move(StatCache)), CanonIncludes(std::move(CanonIncludes)) {
88 std::shared_ptr<const PreambleData>
90 std::shared_ptr<const PreambleData> OldPreamble,
91 const tooling::CompileCommand &OldCompileCommand,
97 llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents, FileName);
99 ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0);
102 compileCommandsAreEqual(Inputs.
CompileCommand, OldCompileCommand) &&
103 OldPreamble->Preamble.CanReuse(CI, ContentsBuffer.get(), Bounds,
105 vlog(
"Reusing preamble for {0}", FileName);
108 vlog(OldPreamble ?
"Rebuilding invalidated preamble for {0}" 109 :
"Building first preamble for {0}",
115 llvm::IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
116 CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(),
117 &PreambleDiagnostics,
false);
121 assert(!CI.getFrontendOpts().SkipFunctionBodies);
122 CI.getFrontendOpts().SkipFunctionBodies =
true;
125 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
127 CppFilePreambleCallbacks SerializedDeclsCollector(FileName, PreambleCallback);
128 if (Inputs.
FS->setCurrentWorkingDirectory(Inputs.
CompileCommand.Directory)) {
129 log(
"Couldn't set working directory when building the preamble.");
134 llvm::SmallString<32> AbsFileName(FileName);
135 Inputs.
FS->makeAbsolute(AbsFileName);
136 auto StatCache = std::make_unique<PreambleFileStatusCache>(AbsFileName);
137 auto BuiltPreamble = PrecompiledPreamble::Build(
138 CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine,
140 std::make_shared<PCHContainerOperations>(), StoreInMemory,
141 SerializedDeclsCollector);
145 CI.getFrontendOpts().SkipFunctionBodies =
false;
148 vlog(
"Built preamble of size {0} for file {1}", BuiltPreamble->getSize(),
150 std::vector<Diag>
Diags = PreambleDiagnostics.
take();
151 return std::make_shared<PreambleData>(
152 std::move(*BuiltPreamble), std::move(Diags),
153 SerializedDeclsCollector.takeIncludes(),
154 SerializedDeclsCollector.takeMacros(), std::move(
StatCache),
155 SerializedDeclsCollector.takeCanonicalIncludes());
157 elog(
"Could not build a preamble for file {0}", FileName);
std::unique_ptr< CommentHandler > collectIWYUHeaderMaps(CanonicalIncludes *Includes)
Returns a CommentHandler that parses pragma comment on include files to determine when we should incl...
PreambleData(PrecompiledPreamble Preamble, std::vector< Diag > Diags, IncludeStructure Includes, MainFileMacros Macros, std::unique_ptr< PreambleFileStatusCache > StatCache, CanonicalIncludes CanonIncludes)
StoreDiags collects the diagnostics that can later be reported by clangd.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
void vlog(const char *Fmt, Ts &&... Vals)
void elog(const char *Fmt, Ts &&... Vals)
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation &CI, std::shared_ptr< const PreambleData > OldPreamble, const tooling::CompileCommand &OldCompileCommand, const ParseInputs &Inputs, bool StoreInMemory, PreambleParsedCallback PreambleCallback)
Build a preamble for the new inputs unless an old one can be reused.
Maps a definition location onto an #include file, based on a set of filename rules.
std::unique_ptr< PreambleFileStatusCache > StatCache
void log(const char *Fmt, Ts &&... Vals)
std::function< void(ASTContext &, std::shared_ptr< clang::Preprocessor >, const CanonicalIncludes &)> PreambleParsedCallback
const PreambleData * Preamble
std::unique_ptr< PPCallbacks > collectIncludeStructureCallback(const SourceManager &SM, IncludeStructure *Out)
Returns a PPCallback that visits all inclusions in the main file.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::vector< Diag > Diags
Records an event whose duration is the lifetime of the Span object.
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
std::vector< Diag > take(const clang::tidy::ClangTidyContext *Tidy=nullptr)