]> granicus.if.org Git - clang/commitdiff
Improve ASTUnit's capture of diagnostics so that the
authorDouglas Gregor <dgregor@apple.com>
Thu, 11 Nov 2010 00:39:14 +0000 (00:39 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 11 Nov 2010 00:39:14 +0000 (00:39 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118751 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Frontend/ASTUnit.h
include/clang/Frontend/CompilerInstance.h
lib/Frontend/ASTUnit.cpp
lib/Frontend/CompilerInstance.cpp
test/Index/complete-driver-errors.c
tools/libclang/CIndex.cpp

index 980cd54cb314933f3fd39082fe6d695a48f24929..559c8c5e077a83e0fd486f78acf41529973490c0 100644 (file)
@@ -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,
index 3db6077029110ab312db6dc2bf0d9e1326ca20ed..f5d6221efc5e494893052b7ce843d8f112d39f26 100644 (file)
@@ -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();
index e130e4b79b96530fe714bf23b72555e001c54d00..ff05f45b14d6ffc7ba9c8e30ffc9aff99be6b5b0 100644 (file)
@@ -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.
index c5e5d7f90a0131f8ecd78d3c230f8ebebfbec389..7cfcd1c41984d2359c60a4a13e74315c70f2289f 100644 (file)
@@ -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)
index 1918511a1866b948e50d7f21cd60491460d69dfa..566090c2606444268e226bdc8545e5ef4532e10f 100644 (file)
@@ -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
index 30e903449fd61711a7395d5c04c0210eff0390c7..8de774cb887aadbbb6713f000b4138f8f4b73d0d 100644 (file)
@@ -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,