16 #include "clang/AST/ASTContext.h" 17 #include "clang/Basic/LangOptions.h" 18 #include "clang/Frontend/CompilerInstance.h" 19 #include "clang/Frontend/CompilerInvocation.h" 20 #include "clang/Frontend/FrontendActions.h" 21 #include "clang/Frontend/Utils.h" 22 #include "clang/Index/IndexDataConsumer.h" 23 #include "clang/Index/IndexingAction.h" 24 #include "clang/Lex/Lexer.h" 25 #include "clang/Lex/MacroInfo.h" 26 #include "clang/Lex/Preprocessor.h" 27 #include "clang/Lex/PreprocessorOptions.h" 28 #include "clang/Sema/Sema.h" 29 #include "clang/Serialization/ASTWriter.h" 30 #include "clang/Tooling/CompilationDatabase.h" 31 #include "llvm/ADT/ArrayRef.h" 32 #include "llvm/ADT/SmallVector.h" 33 #include "llvm/Support/CrashRecoveryContext.h" 34 #include "llvm/Support/raw_ostream.h" 38 using namespace clang;
42 bool compileCommandsAreEqual(
const tooling::CompileCommand &LHS,
43 const tooling::CompileCommand &RHS) {
45 return LHS.Directory == RHS.Directory && LHS.Filename == RHS.Filename &&
46 llvm::makeArrayRef(LHS.CommandLine).equals(RHS.CommandLine);
49 template <
class T> std::size_t getUsedBytes(
const std::vector<T> &Vec) {
50 return Vec.capacity() *
sizeof(T);
53 class DeclTrackingASTConsumer :
public ASTConsumer {
55 DeclTrackingASTConsumer(std::vector<Decl *> &TopLevelDecls)
56 : TopLevelDecls(TopLevelDecls) {}
58 bool HandleTopLevelDecl(DeclGroupRef DG)
override {
61 if (isa<ObjCMethodDecl>(D))
64 TopLevelDecls.push_back(D);
70 std::vector<Decl *> &TopLevelDecls;
75 std::vector<Decl *> takeTopLevelDecls() {
return std::move(TopLevelDecls); }
78 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
79 StringRef InFile)
override {
80 return llvm::make_unique<DeclTrackingASTConsumer>( TopLevelDecls);
84 std::vector<Decl *> TopLevelDecls;
87 class CppFilePreambleCallbacks :
public PreambleCallbacks {
90 : File(File), ParsedCallback(ParsedCallback) {}
94 void AfterExecute(CompilerInstance &CI)
override {
98 ParsedCallback(
File, CI.getASTContext(), CI.getPreprocessorPtr());
101 void BeforeExecute(CompilerInstance &CI)
override {
102 SourceMgr = &CI.getSourceManager();
105 std::unique_ptr<PPCallbacks> createPPCallbacks()
override {
106 assert(SourceMgr &&
"SourceMgr must be set at this point");
114 SourceManager *SourceMgr =
nullptr;
120 AST.
getASTContext().getTranslationUnitDecl()->dump(OS,
true);
123 llvm::Optional<ParsedAST>
125 std::shared_ptr<const PreambleData>
Preamble,
126 std::unique_ptr<llvm::MemoryBuffer> Buffer,
127 std::shared_ptr<PCHContainerOperations>
PCHs,
128 IntrusiveRefCntPtr<vfs::FileSystem>
VFS) {
132 CI->getFrontendOpts().DisableFree =
false;
133 const PrecompiledPreamble *PreamblePCH =
134 Preamble ? &Preamble->Preamble :
nullptr;
139 std::move(PCHs), std::move(VFS), ASTDiags);
144 llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> CICleanup(
147 auto Action = llvm::make_unique<ClangdFrontendAction>();
148 const FrontendInputFile &MainInput = Clang->getFrontendOpts().Inputs[0];
149 if (!Action->BeginSourceFile(*Clang, MainInput)) {
150 log(
"BeginSourceFile() failed when building AST for {0}",
151 MainInput.getFile());
158 Clang->getPreprocessor().addPPCallbacks(
161 if (!Action->Execute())
162 log(
"Execute() failed when building AST for {0}", MainInput.getFile());
170 std::vector<Decl *> ParsedDecls = Action->takeTopLevelDecls();
171 std::vector<Diag> Diags = ASTDiags.
take();
174 Diags.insert(Diags.begin(), Preamble->Diags.begin(), Preamble->Diags.end());
175 return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action),
176 std::move(ParsedDecls), std::move(Diags),
177 std::move(Includes));
193 return Clang->getASTContext();
199 return Clang->getPreprocessorPtr();
203 return Clang->getPreprocessor();
207 return LocalTopLevelDecls;
213 auto &
AST = getASTContext();
217 ::getUsedBytes(LocalTopLevelDecls) + ::getUsedBytes(Diags);
223 Total +=
AST.getASTAllocatedMemory();
224 Total +=
AST.getSideTableAllocatedMemory();
225 Total +=
AST.Idents.getAllocator().getTotalMemory();
226 Total +=
AST.Selectors.getTotalMemory();
228 Total +=
AST.getSourceManager().getContentCacheSize();
229 Total +=
AST.getSourceManager().getDataStructureSizes();
230 Total +=
AST.getSourceManager().getMemoryBufferSizes().malloc_bytes;
232 if (ExternalASTSource *Ext =
AST.getExternalSource())
233 Total += Ext->getMemoryBufferSizes().malloc_bytes;
235 const Preprocessor &PP = getPreprocessor();
236 Total += PP.getTotalMemory();
237 if (PreprocessingRecord *PRec = PP.getPreprocessingRecord())
238 Total += PRec->getTotalMemory();
239 Total += PP.getHeaderSearchInfo().getTotalMemory();
250 : Preamble(std::move(Preamble)), Diags(std::move(Diags)),
251 Includes(std::move(Includes)) {}
254 std::unique_ptr<CompilerInstance> Clang,
255 std::unique_ptr<FrontendAction>
Action,
256 std::vector<Decl *> LocalTopLevelDecls,
258 :
Preamble(std::move(Preamble)), Clang(std::move(Clang)),
259 Action(std::move(Action)),
Diags(std::move(Diags)),
260 LocalTopLevelDecls(std::move(LocalTopLevelDecls)),
263 assert(this->Action);
266 std::unique_ptr<CompilerInvocation>
268 std::vector<const char *> ArgStrs;
270 ArgStrs.push_back(S.c_str());
272 if (Inputs.
FS->setCurrentWorkingDirectory(Inputs.
CompileCommand.Directory)) {
273 log(
"Couldn't set working directory when creating compiler invocation.");
281 IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
282 CompilerInstance::createDiagnostics(
new DiagnosticOptions,
283 &IgnoreDiagnostics,
false);
284 std::unique_ptr<CompilerInvocation> CI = createInvocationFromCommandLine(
285 ArgStrs, CommandLineDiagsEngine, Inputs.
FS);
289 CI->getFrontendOpts().DisableFree =
false;
290 CI->getLangOpts()->CommentOpts.ParseAllComments =
true;
296 std::shared_ptr<const PreambleData> OldPreamble,
297 const tooling::CompileCommand &OldCompileCommand,
const ParseInputs &Inputs,
298 std::shared_ptr<PCHContainerOperations>
PCHs,
bool StoreInMemory,
302 auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(Inputs.
Contents);
304 ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0);
307 compileCommandsAreEqual(Inputs.
CompileCommand, OldCompileCommand) &&
308 OldPreamble->Preamble.CanReuse(CI, ContentsBuffer.get(), Bounds,
310 vlog(
"Reusing preamble for file {0}", Twine(FileName));
313 vlog(
"Preamble for file {0} cannot be reused. Attempting to rebuild it.",
319 IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
320 CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(),
321 &PreambleDiagnostics,
false);
325 assert(!CI.getFrontendOpts().SkipFunctionBodies);
326 CI.getFrontendOpts().SkipFunctionBodies =
true;
329 CI.getPreprocessorOpts().WriteCommentListToPCH =
false;
331 CppFilePreambleCallbacks SerializedDeclsCollector(FileName, PreambleCallback);
332 if (Inputs.
FS->setCurrentWorkingDirectory(Inputs.
CompileCommand.Directory)) {
333 log(
"Couldn't set working directory when building the preamble.");
337 auto BuiltPreamble = PrecompiledPreamble::Build(
338 CI, ContentsBuffer.get(), Bounds, *PreambleDiagsEngine, Inputs.
FS,
PCHs,
339 StoreInMemory, SerializedDeclsCollector);
343 CI.getFrontendOpts().SkipFunctionBodies =
false;
346 vlog(
"Built preamble of size {0} for file {1}", BuiltPreamble->getSize(),
348 return std::make_shared<PreambleData>(
349 std::move(*BuiltPreamble), PreambleDiagnostics.
take(),
350 SerializedDeclsCollector.takeIncludes());
352 elog(
"Could not build a preamble for file {0}", FileName);
359 const ParseInputs &Inputs, std::shared_ptr<const PreambleData> Preamble,
360 std::shared_ptr<PCHContainerOperations>
PCHs) {
364 if (Inputs.
FS->setCurrentWorkingDirectory(Inputs.
CompileCommand.Directory)) {
365 log(
"Couldn't set working directory when building the preamble.");
371 llvm::make_unique<CompilerInvocation>(*Invocation), Preamble,
372 llvm::MemoryBuffer::getMemBufferCopy(Inputs.
Contents), PCHs, Inputs.
FS);
379 const SourceManager &SourceMgr = AST.getSourceManager();
382 log(
"getBeginningOfIdentifier: {0}", Offset.takeError());
383 return SourceLocation();
385 SourceLocation InputLoc = SourceMgr.getComposedLoc(FID, *Offset);
397 return SourceMgr.getMacroArgExpandedLocation(InputLoc);
398 SourceLocation Before =
399 SourceMgr.getMacroArgExpandedLocation(InputLoc.getLocWithOffset(-1));
400 Before = Lexer::GetBeginningOfToken(Before, SourceMgr, AST.getLangOpts());
402 if (Before.isValid() &&
403 !Lexer::getRawToken(Before, Tok, SourceMgr, AST.getLangOpts(),
false) &&
404 Tok.is(tok::raw_identifier))
406 return SourceMgr.getMacroArgExpandedLocation(InputLoc);
StoreDiags collects the diagnostics that can later be reported by clangd.
Preprocessor & getPreprocessor()
std::vector< Diag > take()
std::function< void(PathRef Path, ASTContext &, std::shared_ptr< clang::Preprocessor >)> PreambleParsedCallback
llvm::Optional< ParsedAST > buildAST(PathRef FileName, std::unique_ptr< CompilerInvocation > Invocation, const ParseInputs &Inputs, std::shared_ptr< const PreambleData > Preamble, std::shared_ptr< PCHContainerOperations > PCHs)
Build an AST from provided user inputs.
void dumpAST(ParsedAST &AST, llvm::raw_ostream &OS)
For testing/debugging purposes.
const std::vector< Diag > & getDiagnostics() const
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Documents should not be synced at all.
const IncludeStructure & getIncludeStructure() const
void vlog(const char *Fmt, Ts &&... Vals)
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
void elog(const char *Fmt, Ts &&... Vals)
llvm::Expected< size_t > positionToOffset(StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
ParsedAST(ParsedAST &&Other)
ArrayRef< Decl * > getLocalTopLevelDecls()
This function returns top-level decls present in the main file of the AST.
std::size_t getUsedBytes() const
Returns the esitmated size of the AST and the accessory structures, in bytes.
llvm::unique_function< void()> Action
void log(const char *Fmt, Ts &&... Vals)
PreambleData(PrecompiledPreamble Preamble, std::vector< Diag > Diags, IncludeStructure Includes)
ParsedAST & operator=(ParsedAST &&Other)
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs)
Builds compiler invocation that could be used to build AST or preamble.
std::shared_ptr< Preprocessor > getPreprocessorPtr()
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation &CI, std::shared_ptr< const PreambleData > OldPreamble, const tooling::CompileCommand &OldCompileCommand, const ParseInputs &Inputs, std::shared_ptr< PCHContainerOperations > PCHs, bool StoreInMemory, PreambleParsedCallback PreambleCallback)
Rebuild the preamble for the new inputs unless the old one can be reused.
PrecompiledPreamble const * Preamble
IntrusiveRefCntPtr< vfs::FileSystem > VFS
Stores and provides access to parsed AST.
SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos, const FileID FID)
Get the beginning SourceLocation at a specified Pos.
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::unique_ptr< CompilerInstance > prepareCompilerInstance(std::unique_ptr< clang::CompilerInvocation > CI, const PrecompiledPreamble *Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, std::shared_ptr< PCHContainerOperations > PCHs, IntrusiveRefCntPtr< vfs::FileSystem > VFS, DiagnosticConsumer &DiagsClient)
Creates a compiler instance, configured so that:
std::shared_ptr< PCHContainerOperations > PCHs
void EndSourceFile() override
static llvm::Optional< ParsedAST > build(std::unique_ptr< clang::CompilerInvocation > CI, std::shared_ptr< const PreambleData > Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, std::shared_ptr< PCHContainerOperations > PCHs, IntrusiveRefCntPtr< vfs::FileSystem > VFS)
Attempts to run Clang and store parsed AST.
std::vector< Diag > Diags
PrecompiledPreamble Preamble
IncludeStructure Includes
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.