From: Argyrios Kyrtzidis Date: Tue, 3 May 2011 23:26:34 +0000 (+0000) Subject: Introduce ASTUnit::LoadFromCompilerInvocationAction that allows one to create an... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d808bd2978bd4ac95a92b309b038452b533fd7a0;p=clang Introduce ASTUnit::LoadFromCompilerInvocationAction that allows one to create an ASTUnit from a CompilerInvocation along with an ASTFrontendAction to invoke, and without all the goo about the precompiled preamble. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130805 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 57c59d951e..57d9f712aa 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -51,6 +51,7 @@ class HeaderSearch; class Preprocessor; class SourceManager; class TargetInfo; +class ASTFrontendAction; using namespace idx; @@ -574,6 +575,21 @@ private: public: + /// \brief Create an ASTUnit from a source file, via a CompilerInvocation + /// object, by invoking the optionally provided ASTFrontendAction. + /// + /// \param CI - The compiler invocation to use; it must have exactly one input + /// source file. The ASTUnit takes ownership of the CompilerInvocation object. + /// + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + /// + /// \param Action - The ASTFrontendAction to invoke. Its ownership is not + /// transfered. + static ASTUnit *LoadFromCompilerInvocationAction(CompilerInvocation *CI, + llvm::IntrusiveRefCntPtr Diags, + ASTFrontendAction *Action = 0); + /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a /// CompilerInvocation object. /// diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 2a1244841e..88653b2240 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1554,6 +1554,119 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI, return AST.take(); } +ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, + llvm::IntrusiveRefCntPtr Diags, + ASTFrontendAction *Action) { + assert(CI && "A CompilerInvocation is required"); + + // Create the AST unit. + llvm::OwningPtr AST; + AST.reset(new ASTUnit(false)); + ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics*/false); + AST->Diagnostics = Diags; + AST->OnlyLocalDecls = false; + AST->CaptureDiagnostics = false; + AST->CompleteTranslationUnit = Action ? Action->usesCompleteTranslationUnit() + : true; + AST->ShouldCacheCodeCompletionResults = false; + AST->Invocation = CI; + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + ASTUnitCleanup(AST.get()); + llvm::CrashRecoveryContextCleanupRegistrar > + DiagCleanup(Diags.getPtr()); + + // We'll manage file buffers ourselves. + CI->getPreprocessorOpts().RetainRemappedFileBuffers = true; + CI->getFrontendOpts().DisableFree = false; + ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts()); + + // Save the target features. + AST->TargetFeatures = CI->getTargetOpts().Features; + + // Create the compiler instance to use for building the AST. + llvm::OwningPtr Clang(new CompilerInstance()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + CICleanup(Clang.get()); + + Clang->setInvocation(CI); + AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second; + + // Set up diagnostics, capturing any diagnostics that would + // otherwise be dropped. + Clang->setDiagnostics(&AST->getDiagnostics()); + + // Create the target instance. + Clang->getTargetOpts().Features = AST->TargetFeatures; + Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), + Clang->getTargetOpts())); + if (!Clang->hasTarget()) + return 0; + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + Clang->getTarget().setForcedLangOptions(Clang->getLangOpts()); + + assert(Clang->getFrontendOpts().Inputs.size() == 1 && + "Invocation must have exactly one source file!"); + assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST && + "FIXME: AST inputs not yet supported here!"); + assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR && + "IR inputs not supported here!"); + + // Configure the various subsystems. + AST->FileSystemOpts = Clang->getFileSystemOpts(); + AST->FileMgr = new FileManager(AST->FileSystemOpts); + AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr); + AST->TheSema.reset(); + AST->Ctx = 0; + AST->PP = 0; + + // Create a file manager object to provide access to and cache the filesystem. + Clang->setFileManager(&AST->getFileManager()); + + // Create the source manager. + Clang->setSourceManager(&AST->getSourceManager()); + + ASTFrontendAction *Act = Action; + + llvm::OwningPtr TrackerAct; + if (!Act) { + TrackerAct.reset(new TopLevelDeclTrackerAction(*AST)); + Act = TrackerAct.get(); + } + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + ActCleanup(TrackerAct.get()); + + if (!Act->BeginSourceFile(*Clang.get(), + Clang->getFrontendOpts().Inputs[0].second, + Clang->getFrontendOpts().Inputs[0].first)) + return 0; + + Act->Execute(); + + // Steal the created target, context, and preprocessor. + AST->TheSema.reset(Clang->takeSema()); + AST->Consumer.reset(Clang->takeASTConsumer()); + AST->Ctx = &Clang->getASTContext(); + AST->PP = &Clang->getPreprocessor(); + Clang->setSourceManager(0); + Clang->setFileManager(0); + AST->Target = &Clang->getTarget(); + + Act->EndSourceFile(); + + return AST.take(); +} + bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { if (!Invocation) return true;