forked from OSchip/llvm-project
[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:
parent
67a09fc397
commit
ac1cc934b3
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue