diff options
-rw-r--r-- | include/clang/Frontend/ASTUnit.h | 30 | ||||
-rw-r--r-- | lib/Frontend/ASTUnit.cpp | 68 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 47 | ||||
-rw-r--r-- | tools/libclang/CIndexer.h | 5 | ||||
-rw-r--r-- | tools/libclang/Indexing.cpp | 8 |
5 files changed, 109 insertions, 49 deletions
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 5b869a2136..2fd87c941e 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -46,6 +46,7 @@ class ASTContext; class ASTReader; class CodeCompleteConsumer; class CompilerInvocation; +class CompilerInstance; class Decl; class DiagnosticsEngine; class FileEntry; @@ -143,6 +144,10 @@ private: /// translation unit. SmallVector<StoredDiagnostic, 4> StoredDiagnostics; + /// \brief The set of diagnostics produced when failing to parse, e.g. due + /// to failure to load the PCH. + SmallVector<StoredDiagnostic, 4> FailedParseDiagnostics; + /// \brief The number of stored diagnostics that come from the driver /// itself. /// @@ -384,7 +389,11 @@ private: bool AllowRebuild = true, unsigned MaxLines = 0); void RealizeTopLevelDeclsFromPreamble(); - + + /// \brief Transfers ownership of the objects (like SourceManager) from + /// \param CI to this ASTUnit. + void transferASTDataFromCompilerInstance(CompilerInstance &CI); + /// \brief Allows us to assert that ASTUnit is not being used concurrently, /// which is not supported. /// @@ -663,6 +672,13 @@ public: /// \param Persistent - if true the returned ASTUnit will be complete. /// false means the caller is only interested in getting info through the /// provided \see Action. + /// + /// \param ErrAST - If non-null and parsing failed without any AST to return + /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit + /// mainly to allow the caller to see the diagnostics. + /// This will only receive an ASTUnit if a new one was created. If an already + /// created ASTUnit was passed in \param Unit then the caller can check that. + /// static ASTUnit *LoadFromCompilerInvocationAction(CompilerInvocation *CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, ASTFrontendAction *Action = 0, @@ -672,7 +688,8 @@ public: bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, bool PrecompilePreamble = false, - bool CacheCodeCompletionResults = false); + bool CacheCodeCompletionResults = false, + OwningPtr<ASTUnit> *ErrAST = 0); /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a /// CompilerInvocation object. @@ -704,7 +721,11 @@ public: /// lifetime is expected to extend past that of the returned ASTUnit. /// /// \param ResourceFilesPath - The path to the compiler resource files. - // + /// + /// \param ErrAST - If non-null and parsing failed without any AST to return + /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit + /// mainly to allow the caller to see the diagnostics. + /// // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we // shouldn't need to specify them at construction time. static ASTUnit *LoadFromCommandLine(const char **ArgBegin, @@ -719,7 +740,8 @@ public: bool PrecompilePreamble = false, TranslationUnitKind TUKind = TU_Complete, bool CacheCodeCompletionResults = false, - bool AllowPCHWithCompilerErrors = false); + bool AllowPCHWithCompilerErrors = false, + OwningPtr<ASTUnit> *ErrAST = 0); /// \brief Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 563ed03588..15500989e8 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1138,19 +1138,13 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { } Act->Execute(); - - // Steal the created target, context, and preprocessor. - TheSema.reset(Clang->takeSema()); - Consumer.reset(Clang->takeASTConsumer()); - Ctx = &Clang->getASTContext(); - PP = &Clang->getPreprocessor(); - Clang->setSourceManager(0); - Clang->setFileManager(0); - Target = &Clang->getTarget(); - Reader = Clang->getModuleManager(); + + transferASTDataFromCompilerInstance(*Clang); Act->EndSourceFile(); + FailedParseDiagnostics.clear(); + return false; error: @@ -1159,7 +1153,11 @@ error: delete OverrideMainBuffer; SavedMainFileBuffer = 0; } - + + // Keep the ownership of the data in the ASTUnit because the client may + // want to see the diagnostics. + transferASTDataFromCompilerInstance(*Clang); + FailedParseDiagnostics.swap(StoredDiagnostics); StoredDiagnostics.clear(); NumStoredDiagnosticsFromDriver = 0; return true; @@ -1647,6 +1645,18 @@ void ASTUnit::RealizeTopLevelDeclsFromPreamble() { TopLevelDecls.insert(TopLevelDecls.begin(), Resolved.begin(), Resolved.end()); } +void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) { + // Steal the created target, context, and preprocessor. + TheSema.reset(CI.takeSema()); + Consumer.reset(CI.takeASTConsumer()); + Ctx = &CI.getASTContext(); + PP = &CI.getPreprocessor(); + CI.setSourceManager(0); + CI.setFileManager(0); + Target = &CI.getTarget(); + Reader = CI.getModuleManager(); +} + StringRef ASTUnit::getMainFileName() const { return Invocation->getFrontendOpts().Inputs[0].File; } @@ -1675,7 +1685,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble, - bool CacheCodeCompletionResults) { + bool CacheCodeCompletionResults, + OwningPtr<ASTUnit> *ErrAST) { assert(CI && "A CompilerInvocation is required"); OwningPtr<ASTUnit> OwnAST; @@ -1770,8 +1781,13 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction> ActCleanup(TrackerAct.get()); - if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) + if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) { + AST->transferASTDataFromCompilerInstance(*Clang); + if (OwnAST && ErrAST) + ErrAST->swap(OwnAST); + return 0; + } if (Persistent && !TrackerAct) { Clang->getPreprocessor().addPPCallbacks( @@ -1784,16 +1800,9 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, Clang->setASTConsumer(new MultiplexConsumer(Consumers)); } 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(); - AST->Reader = Clang->getModuleManager(); + AST->transferASTDataFromCompilerInstance(*Clang); Act->EndSourceFile(); @@ -1872,7 +1881,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, bool PrecompilePreamble, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, - bool AllowPCHWithCompilerErrors) { + bool AllowPCHWithCompilerErrors, + OwningPtr<ASTUnit> *ErrAST) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -1936,7 +1946,17 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> ASTUnitCleanup(AST.get()); - return AST->LoadFromCompilerInvocation(PrecompilePreamble) ? 0 : AST.take(); + if (AST->LoadFromCompilerInvocation(PrecompilePreamble)) { + // Some error occurred, if caller wants to examine diagnostics, pass it the + // ASTUnit. + if (ErrAST) { + AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics); + ErrAST->swap(AST); + } + return 0; + } + + return AST.take(); } bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index eafb867eb2..df4c8eda66 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -51,6 +51,7 @@ using namespace clang; using namespace clang::cxcursor; using namespace clang::cxstring; using namespace clang::cxtu; +using namespace clang::cxindex; CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU) { if (!TU) @@ -2482,7 +2483,28 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, unsaved_files, num_unsaved_files, Options); } - + +void cxindex::printDiagsToStderr(ASTUnit *Unit) { + if (!Unit) + return; + + for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(), + DEnd = Unit->stored_diag_end(); + D != DEnd; ++D) { + CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOpts()); + CXString Msg = clang_formatDiagnostic(&Diag, + clang_defaultDiagnosticDisplayOptions()); + fprintf(stderr, "%s\n", clang_getCString(Msg)); + clang_disposeString(Msg); + } +#ifdef LLVM_ON_WIN32 + // On Windows, force a flush, since there may be multiple copies of + // stderr and stdout in the file system, all with different buffers + // but writing to the same device. + fflush(stderr); +#endif +} + struct ParseTranslationUnitInfo { CXIndex CIdx; const char *source_filename; @@ -2587,6 +2609,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { } unsigned NumErrors = Diags->getClient()->getNumErrors(); + OwningPtr<ASTUnit> ErrUnit; OwningPtr<ASTUnit> Unit( ASTUnit::LoadFromCommandLine(Args->size() ? &(*Args)[0] : 0 /* vector::data() not portable */, @@ -2601,27 +2624,13 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { PrecompilePreamble, TUKind, CacheCodeCompetionResults, - /*AllowPCHWithCompilerErrors=*/true)); + /*AllowPCHWithCompilerErrors=*/true, + &ErrUnit)); if (NumErrors != Diags->getClient()->getNumErrors()) { // Make sure to check that 'Unit' is non-NULL. - if (CXXIdx->getDisplayDiagnostics() && Unit.get()) { - for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(), - DEnd = Unit->stored_diag_end(); - D != DEnd; ++D) { - CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOpts()); - CXString Msg = clang_formatDiagnostic(&Diag, - clang_defaultDiagnosticDisplayOptions()); - fprintf(stderr, "%s\n", clang_getCString(Msg)); - clang_disposeString(Msg); - } -#ifdef LLVM_ON_WIN32 - // On Windows, force a flush, since there may be multiple copies of - // stderr and stdout in the file system, all with different buffers - // but writing to the same device. - fflush(stderr); -#endif - } + if (CXXIdx->getDisplayDiagnostics()) + printDiagsToStderr(Unit ? Unit.get() : ErrUnit.get()); } PTUI->result = MakeCXTranslationUnit(CXXIdx, Unit.take()); diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h index 8a249f0ceb..1e5fb824bb 100644 --- a/tools/libclang/CIndexer.h +++ b/tools/libclang/CIndexer.h @@ -25,6 +25,7 @@ namespace llvm { } namespace clang { + class ASTUnit; class CIndexer { bool OnlyLocalDecls; @@ -94,6 +95,10 @@ public: /// \brief Print libclang's resource usage to standard error. void PrintLibclangResourceUsage(CXTranslationUnit TU); + + namespace cxindex { + void printDiagsToStderr(ASTUnit *Unit); + } } #endif diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp index 6ece54857a..e660c4d6eb 100644 --- a/tools/libclang/Indexing.cpp +++ b/tools/libclang/Indexing.cpp @@ -388,7 +388,8 @@ static void clang_indexSourceFile_Impl(void *UserData) { } } - Unit = ASTUnit::LoadFromCompilerInvocationAction(CInvok.getPtr(), Diags, + DiagnosticErrorTrap DiagTrap(*Diags); + bool Success = ASTUnit::LoadFromCompilerInvocationAction(CInvok.getPtr(), Diags, IndexAction.get(), Unit, Persistent, @@ -397,7 +398,10 @@ static void clang_indexSourceFile_Impl(void *UserData) { /*CaptureDiagnostics=*/true, PrecompilePreamble, CacheCodeCompletionResults); - if (!Unit) + if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics()) + printDiagsToStderr(Unit); + + if (!Success) return; if (out_TU) |