mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-14 11:39:35 +00:00
Improve ASTUnit's capture of diagnostics so that the
diagnostic-capturing client lives as long as the ASTUnit itself does. Otherwise, we can end up with crashes when we get a diagnostic outside of parsing/code completion. The circumstances under which this happen are really hard to reproduce, because a file needs to change from under us. llvm-svn: 118751
This commit is contained in:
parent
8bf3d832e5
commit
44c6ee7729
clang
include/clang/Frontend
lib/Frontend
test/Index
tools/libclang
@ -91,7 +91,7 @@ private:
|
||||
|
||||
/// \brief Whether to capture any diagnostics produced.
|
||||
bool CaptureDiagnostics;
|
||||
|
||||
|
||||
/// \brief Track whether the main file was loaded from an AST or not.
|
||||
bool MainFileIsAST;
|
||||
|
||||
@ -218,6 +218,9 @@ private:
|
||||
/// \brief Whether we should be caching code-completion results.
|
||||
bool ShouldCacheCodeCompletionResults;
|
||||
|
||||
static void ConfigureDiags(llvm::IntrusiveRefCntPtr<Diagnostic> &Diags,
|
||||
ASTUnit &AST, bool CaptureDiagnostics);
|
||||
|
||||
public:
|
||||
/// \brief A cached code-completion result, which may be introduced in one of
|
||||
/// many different contexts.
|
||||
@ -540,9 +543,9 @@ public:
|
||||
llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
|
||||
llvm::StringRef ResourceFilesPath,
|
||||
bool OnlyLocalDecls = false,
|
||||
bool CaptureDiagnostics = false,
|
||||
RemappedFile *RemappedFiles = 0,
|
||||
unsigned NumRemappedFiles = 0,
|
||||
bool CaptureDiagnostics = false,
|
||||
bool PrecompilePreamble = false,
|
||||
bool CompleteTranslationUnit = true,
|
||||
bool CacheCodeCompletionResults = false,
|
||||
|
@ -477,8 +477,14 @@ public:
|
||||
/// Create the diagnostics engine using the invocation's diagnostic options
|
||||
/// and replace any existing one with it.
|
||||
///
|
||||
/// Note that this routine also replaces the diagnostic client.
|
||||
void createDiagnostics(int Argc, const char* const *Argv);
|
||||
/// Note that this routine also replaces the diagnostic client,
|
||||
/// allocating one if one is not provided.
|
||||
///
|
||||
/// \param Client If non-NULL, a diagnostic client that will be
|
||||
/// attached to (and, then, owned by) the Diagnostic inside this AST
|
||||
/// unit.
|
||||
void createDiagnostics(int Argc, const char* const *Argv,
|
||||
DiagnosticClient *Client = 0);
|
||||
|
||||
/// Create a Diagnostic object with a the TextDiagnosticPrinter.
|
||||
///
|
||||
@ -486,18 +492,24 @@ public:
|
||||
/// when the diagnostic options indicate that the compiler should output
|
||||
/// logging information.
|
||||
///
|
||||
/// Note that this creates an unowned DiagnosticClient, if using directly the
|
||||
/// caller is responsible for releasing the returned Diagnostic's client
|
||||
/// eventually.
|
||||
/// If no diagnostic client is provided, this creates a
|
||||
/// DiagnosticClient that is owned by the returned diagnostic
|
||||
/// object, if using directly the caller is responsible for
|
||||
/// releasing the returned Diagnostic's client eventually.
|
||||
///
|
||||
/// \param Opts - The diagnostic options; note that the created text
|
||||
/// diagnostic object contains a reference to these options and its lifetime
|
||||
/// must extend past that of the diagnostic engine.
|
||||
///
|
||||
/// \param Client If non-NULL, a diagnostic client that will be
|
||||
/// attached to (and, then, owned by) the returned Diagnostic
|
||||
/// object.
|
||||
///
|
||||
/// \return The new object on success, or null on failure.
|
||||
static llvm::IntrusiveRefCntPtr<Diagnostic>
|
||||
createDiagnostics(const DiagnosticOptions &Opts, int Argc,
|
||||
const char* const *Argv);
|
||||
const char* const *Argv,
|
||||
DiagnosticClient *Client = 0);
|
||||
|
||||
/// Create the file manager and replace any existing one with it.
|
||||
void createFileManager();
|
||||
|
@ -406,7 +406,7 @@ class CaptureDroppedDiagnostics {
|
||||
|
||||
public:
|
||||
CaptureDroppedDiagnostics(bool RequestCapture, Diagnostic &Diags,
|
||||
llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
|
||||
llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiags)
|
||||
: Diags(Diags), Client(StoredDiags), PreviousClient(0)
|
||||
{
|
||||
if (RequestCapture || Diags.getClient() == 0) {
|
||||
@ -447,6 +447,22 @@ llvm::MemoryBuffer *ASTUnit::getBufferForFile(llvm::StringRef Filename,
|
||||
ErrorStr, FileSize, FileInfo);
|
||||
}
|
||||
|
||||
/// \brief Configure the diagnostics object for use with ASTUnit.
|
||||
void ASTUnit::ConfigureDiags(llvm::IntrusiveRefCntPtr<Diagnostic> &Diags,
|
||||
ASTUnit &AST, bool CaptureDiagnostics) {
|
||||
if (!Diags.getPtr()) {
|
||||
// No diagnostics engine was provided, so create our own diagnostics object
|
||||
// with the default options.
|
||||
DiagnosticOptions DiagOpts;
|
||||
DiagnosticClient *Client = 0;
|
||||
if (CaptureDiagnostics)
|
||||
Client = new StoredDiagnosticClient(AST.StoredDiagnostics);
|
||||
Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0, Client);
|
||||
} else if (CaptureDiagnostics) {
|
||||
Diags->setClient(new StoredDiagnosticClient(AST.StoredDiagnostics));
|
||||
}
|
||||
}
|
||||
|
||||
ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
|
||||
llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
|
||||
const FileSystemOptions &FileSystemOpts,
|
||||
@ -455,16 +471,10 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
|
||||
unsigned NumRemappedFiles,
|
||||
bool CaptureDiagnostics) {
|
||||
llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
|
||||
|
||||
if (!Diags.getPtr()) {
|
||||
// No diagnostics engine was provided, so create our own diagnostics object
|
||||
// with the default options.
|
||||
DiagnosticOptions DiagOpts;
|
||||
Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
|
||||
}
|
||||
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
|
||||
|
||||
AST->CaptureDiagnostics = CaptureDiagnostics;
|
||||
AST->OnlyLocalDecls = OnlyLocalDecls;
|
||||
AST->CaptureDiagnostics = CaptureDiagnostics;
|
||||
AST->Diagnostics = Diags;
|
||||
AST->FileSystemOpts = FileSystemOpts;
|
||||
AST->FileMgr.reset(new FileManager);
|
||||
@ -474,10 +484,6 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename,
|
||||
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(),
|
||||
AST->getFileSystemOpts()));
|
||||
|
||||
// If requested, capture diagnostics in the ASTUnit.
|
||||
CaptureDroppedDiagnostics Capture(CaptureDiagnostics, AST->getDiagnostics(),
|
||||
AST->StoredDiagnostics);
|
||||
|
||||
for (unsigned I = 0; I != NumRemappedFiles; ++I) {
|
||||
// Create the file entry for the file that we're mapping from.
|
||||
const FileEntry *FromFile
|
||||
@ -708,9 +714,6 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) {
|
||||
// Set up diagnostics, capturing any diagnostics that would
|
||||
// otherwise be dropped.
|
||||
Clang.setDiagnostics(&getDiagnostics());
|
||||
CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
|
||||
getDiagnostics(),
|
||||
StoredDiagnostics);
|
||||
|
||||
// Create the target instance.
|
||||
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
|
||||
@ -1200,9 +1203,6 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble(
|
||||
|
||||
// Set up diagnostics, capturing all of the diagnostics produced.
|
||||
Clang.setDiagnostics(&getDiagnostics());
|
||||
CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
|
||||
getDiagnostics(),
|
||||
StoredDiagnostics);
|
||||
|
||||
// Create the target instance.
|
||||
Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
|
||||
@ -1367,20 +1367,14 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
|
||||
bool CaptureDiagnostics,
|
||||
bool PrecompilePreamble,
|
||||
bool CompleteTranslationUnit,
|
||||
bool CacheCodeCompletionResults) {
|
||||
if (!Diags.getPtr()) {
|
||||
// No diagnostics engine was provided, so create our own diagnostics object
|
||||
// with the default options.
|
||||
DiagnosticOptions DiagOpts;
|
||||
Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
|
||||
}
|
||||
|
||||
bool CacheCodeCompletionResults) {
|
||||
// Create the AST unit.
|
||||
llvm::OwningPtr<ASTUnit> AST;
|
||||
AST.reset(new ASTUnit(false));
|
||||
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
|
||||
AST->Diagnostics = Diags;
|
||||
AST->CaptureDiagnostics = CaptureDiagnostics;
|
||||
AST->OnlyLocalDecls = OnlyLocalDecls;
|
||||
AST->CaptureDiagnostics = CaptureDiagnostics;
|
||||
AST->CompleteTranslationUnit = CompleteTranslationUnit;
|
||||
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
|
||||
AST->Invocation.reset(CI);
|
||||
@ -1393,22 +1387,19 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
|
||||
llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
|
||||
llvm::StringRef ResourceFilesPath,
|
||||
bool OnlyLocalDecls,
|
||||
bool CaptureDiagnostics,
|
||||
RemappedFile *RemappedFiles,
|
||||
unsigned NumRemappedFiles,
|
||||
bool CaptureDiagnostics,
|
||||
bool PrecompilePreamble,
|
||||
bool CompleteTranslationUnit,
|
||||
bool CacheCodeCompletionResults,
|
||||
bool CXXPrecompilePreamble,
|
||||
bool CXXChainedPCH) {
|
||||
bool CreatedDiagnosticsObject = false;
|
||||
|
||||
if (!Diags.getPtr()) {
|
||||
// No diagnostics engine was provided, so create our own diagnostics object
|
||||
// with the default options.
|
||||
DiagnosticOptions DiagOpts;
|
||||
Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
|
||||
CreatedDiagnosticsObject = true;
|
||||
}
|
||||
|
||||
llvm::SmallVector<const char *, 16> Args;
|
||||
@ -1422,9 +1413,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
|
||||
llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
|
||||
|
||||
llvm::OwningPtr<CompilerInvocation> CI;
|
||||
|
||||
{
|
||||
CaptureDroppedDiagnostics Capture(CaptureDiagnostics,
|
||||
*Diags,
|
||||
CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags,
|
||||
StoredDiagnostics);
|
||||
|
||||
// FIXME: We shouldn't have to pass in the path info.
|
||||
@ -1457,12 +1448,12 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
|
||||
const driver::ArgStringList &CCArgs = Cmd->getArguments();
|
||||
CI.reset(new CompilerInvocation);
|
||||
CompilerInvocation::CreateFromArgs(*CI,
|
||||
const_cast<const char **>(CCArgs.data()),
|
||||
const_cast<const char **>(CCArgs.data()) +
|
||||
const_cast<const char **>(CCArgs.data()),
|
||||
const_cast<const char **>(CCArgs.data()) +
|
||||
CCArgs.size(),
|
||||
*Diags);
|
||||
}
|
||||
|
||||
|
||||
// Override any files that need remapping
|
||||
for (unsigned I = 0; I != NumRemappedFiles; ++I)
|
||||
CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
|
||||
@ -1484,9 +1475,10 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
|
||||
// Create the AST unit.
|
||||
llvm::OwningPtr<ASTUnit> AST;
|
||||
AST.reset(new ASTUnit(false));
|
||||
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
|
||||
AST->Diagnostics = Diags;
|
||||
AST->CaptureDiagnostics = CaptureDiagnostics;
|
||||
AST->OnlyLocalDecls = OnlyLocalDecls;
|
||||
AST->CaptureDiagnostics = CaptureDiagnostics;
|
||||
AST->CompleteTranslationUnit = CompleteTranslationUnit;
|
||||
AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
|
||||
AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
|
||||
@ -1813,7 +1805,7 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column,
|
||||
Clang.setDiagnostics(&Diag);
|
||||
ProcessWarningOptions(Diag, CCInvocation.getDiagnosticOpts());
|
||||
CaptureDroppedDiagnostics Capture(true,
|
||||
Clang.getDiagnostics(),
|
||||
Clang.getDiagnostics(),
|
||||
StoredDiagnostics);
|
||||
|
||||
// Create the target instance.
|
||||
|
@ -113,19 +113,23 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
|
||||
Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger));
|
||||
}
|
||||
|
||||
void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv) {
|
||||
Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv);
|
||||
void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv,
|
||||
DiagnosticClient *Client) {
|
||||
Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client);
|
||||
}
|
||||
|
||||
llvm::IntrusiveRefCntPtr<Diagnostic>
|
||||
CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
|
||||
int Argc, const char* const *Argv) {
|
||||
int Argc, const char* const *Argv,
|
||||
DiagnosticClient *Client) {
|
||||
llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic());
|
||||
|
||||
// Create the diagnostic client for reporting errors or for
|
||||
// implementing -verify.
|
||||
llvm::OwningPtr<DiagnosticClient> DiagClient;
|
||||
Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
|
||||
if (Client)
|
||||
Diags->setClient(Client);
|
||||
else
|
||||
Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts));
|
||||
|
||||
// Chain in -verify checker, if requested.
|
||||
if (Opts.VerifyDiagnostics)
|
||||
|
@ -2,20 +2,21 @@ int *blah = 1;
|
||||
|
||||
int
|
||||
|
||||
// Test driver errors with code completion
|
||||
// RUN: c-index-test -code-completion-at=%s:4:1 -std= %s 2> %t | FileCheck -check-prefix=CHECK-RESULTS %s
|
||||
// RUN: FileCheck -check-prefix=CHECK-DIAGS %s < %t
|
||||
// CHECK-RESULTS: NotImplemented:{TypedText const} (40)
|
||||
// CHECK-RESULTS: NotImplemented:{TypedText restrict} (40)
|
||||
// CHECK-RESULTS: NotImplemented:{TypedText volatile} (40)
|
||||
// CHECK-DIAGS: error: invalid value '' in '-std='
|
||||
// CHECK-DIAGS: complete-driver-errors.c:1:6:{1:13-1:14}: warning: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int'
|
||||
|
||||
// Test driver errors with code completion
|
||||
// RUN: c-index-test -code-completion-at=%s:4:1 -std= %s 2> %t | FileCheck -check-prefix=CHECK-RESULTS %s
|
||||
// RUN: FileCheck -check-prefix=CHECK-DIAGS %s < %t
|
||||
|
||||
// Test driver errors with parsing
|
||||
// RUN: c-index-test -test-load-source all -std= %s 2> %t | FileCheck -check-prefix=CHECK-LOAD %s
|
||||
// RUN: FileCheck -check-prefix=CHECK-DIAGS %s < %t
|
||||
// CHECK-LOAD: complete-driver-errors.c:1:6: VarDecl=blah:1:6
|
||||
|
||||
// CHECK-DIAGS: error: invalid value '' in '-std='
|
||||
// CHECK-DIAGS: complete-driver-errors.c:1:6:{1:13-1:14}: warning: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int'
|
||||
// Test driver errors with code completion and precompiled preamble
|
||||
// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:4:1 -std= %s 2> %t | FileCheck -check-prefix=CHECK-RESULTS %s
|
||||
// RUN: FileCheck -check-prefix=CHECK-DIAGS %s < %t
|
||||
|
@ -2186,9 +2186,9 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
|
||||
Diags,
|
||||
CXXIdx->getClangResourcesPath(),
|
||||
CXXIdx->getOnlyLocalDecls(),
|
||||
/*CaptureDiagnostics=*/true,
|
||||
RemappedFiles.data(),
|
||||
RemappedFiles.size(),
|
||||
/*CaptureDiagnostics=*/true,
|
||||
PrecompilePreamble,
|
||||
CompleteTranslationUnit,
|
||||
CacheCodeCompetionResults,
|
||||
|
Loading…
Reference in New Issue
Block a user