[libclang] If displayDiagnostics is set (when calling clang_createIndex), make sure to

output the errors that occurred even if we did not get an AST (e.g. because the
PCH failed to load).

Also honor displayDiagnostics in clang_indexSourceFile().

rdar://11203489

llvm-svn: 154472
This commit is contained in:
Argyrios Kyrtzidis 2012-04-11 02:11:16 +00:00
parent 67a09fc397
commit ac1cc934b3
5 changed files with 109 additions and 49 deletions

View File

@ -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.

View File

@ -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) {

View File

@ -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());

View File

@ -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

View File

@ -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)