[cfe-commits] r116285 - in /cfe/trunk: include/clang/Frontend/ASTUnit.h lib/Frontend/ASTUnit.cpp test/Index/complete-driver-errors.c tools/libclang/CIndexDiagnostic.cpp

Douglas Gregor dgregor at apple.com
Mon Oct 11 17:50:20 PDT 2010


Author: dgregor
Date: Mon Oct 11 19:50:20 2010
New Revision: 116285

URL: http://llvm.org/viewvc/llvm-project?rev=116285&view=rev
Log:
When we load an ASTUnit from command-line arguments, hold on to the
diagnostics produced by the driver itself. Previously, we were
allowing these to either be dropped or to slip through to stderr.

Fixes <rdar://problem/7595339>.

Added:
    cfe/trunk/test/Index/complete-driver-errors.c
Modified:
    cfe/trunk/include/clang/Frontend/ASTUnit.h
    cfe/trunk/lib/Frontend/ASTUnit.cpp
    cfe/trunk/tools/libclang/CIndexDiagnostic.cpp

Modified: cfe/trunk/include/clang/Frontend/ASTUnit.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/ASTUnit.h?rev=116285&r1=116284&r2=116285&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/ASTUnit.h (original)
+++ cfe/trunk/include/clang/Frontend/ASTUnit.h Mon Oct 11 19:50:20 2010
@@ -115,6 +115,13 @@
   /// translation unit.
   llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
 
+  /// \brief The number of stored diagnostics that come from the driver
+  /// itself.
+  ///
+  /// Diagnostics that come from the driver are retained from one parse to
+  /// the next.
+  unsigned NumStoredDiagnosticsFromDriver;
+  
   /// \brief Temporary files that should be removed when the ASTUnit is 
   /// destroyed.
   llvm::SmallVector<llvm::sys::Path, 4> TemporaryFiles;
@@ -483,6 +490,19 @@
                                   unsigned NumRemappedFiles = 0,
                                   bool CaptureDiagnostics = false);
 
+private:
+  /// \brief Helper function for \c LoadFromCompilerInvocation() and
+  /// \c LoadFromCommandLine(), which loads an AST from a compiler invocation.
+  ///
+  /// \param PrecompilePreamble Whether to precompile the preamble of this
+  /// translation unit, to improve the performance of reparsing.
+  ///
+  /// \returns \c true if a catastrophic failure occurred (which means that the
+  /// \c ASTUnit itself is invalid), or \c false otherwise.
+  bool LoadFromCompilerInvocation(bool PrecompilePreamble);
+  
+public:
+  
   /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a
   /// CompilerInvocation object.
   ///

Modified: cfe/trunk/lib/Frontend/ASTUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTUnit.cpp?rev=116285&r1=116284&r2=116285&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/ASTUnit.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTUnit.cpp Mon Oct 11 19:50:20 2010
@@ -52,7 +52,8 @@
 
 ASTUnit::ASTUnit(bool _MainFileIsAST)
   : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST), 
-    CompleteTranslationUnit(true), ConcurrencyCheckValue(CheckUnlocked), 
+    CompleteTranslationUnit(true), NumStoredDiagnosticsFromDriver(0),
+    ConcurrencyCheckValue(CheckUnlocked), 
     PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0),
     ShouldCacheCodeCompletionResults(false),
     NumTopLevelDeclsAtLastCompletionCache(0),
@@ -714,7 +715,9 @@
   PreprocessedEntitiesByFile.clear();
 
   if (!OverrideMainBuffer) {
-    StoredDiagnostics.clear();
+    StoredDiagnostics.erase(
+                    StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
+                            StoredDiagnostics.end());
     TopLevelDeclsInPreamble.clear();
   }
 
@@ -737,19 +740,21 @@
     PreprocessorOpts.ImplicitPCHInclude = PreambleFile;
     PreprocessorOpts.DisablePCHValidation = true;
     
-    // Keep track of the override buffer;
-    SavedMainFileBuffer = OverrideMainBuffer;
-
     // The stored diagnostic has the old source manager in it; update
     // the locations to refer into the new source manager. Since we've
     // been careful to make sure that the source manager's state
     // before and after are identical, so that we can reuse the source
     // location itself.
-    for (unsigned I = 0, N = StoredDiagnostics.size(); I != N; ++I) {
+    for (unsigned I = NumStoredDiagnosticsFromDriver, 
+                  N = StoredDiagnostics.size(); 
+         I < N; ++I) {
       FullSourceLoc Loc(StoredDiagnostics[I].getLocation(),
                         getSourceManager());
       StoredDiagnostics[I].setLocation(Loc);
     }
+
+    // Keep track of the override buffer;
+    SavedMainFileBuffer = OverrideMainBuffer;
   } else {
     PreprocessorOpts.PrecompiledPreambleBytes.first = 0;
     PreprocessorOpts.PrecompiledPreambleBytes.second = false;
@@ -1201,7 +1206,9 @@
   // Clear out old caches and data.
   getDiagnostics().Reset();
   ProcessWarningOptions(getDiagnostics(), Clang.getDiagnosticOpts());
-  StoredDiagnostics.clear();
+  StoredDiagnostics.erase(
+                    StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver,
+                          StoredDiagnostics.end());
   TopLevelDecls.clear();
   TopLevelDeclsInPreamble.clear();
   
@@ -1306,6 +1313,41 @@
   return 0;
 }
 
+bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) {
+  if (!Invocation)
+    return true;
+  
+  // We'll manage file buffers ourselves.
+  Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true;
+  Invocation->getFrontendOpts().DisableFree = false;
+
+  if (getenv("LIBCLANG_TIMING"))
+    TimerGroup.reset(
+          new llvm::TimerGroup(Invocation->getFrontendOpts().Inputs[0].second));
+  
+  
+  llvm::MemoryBuffer *OverrideMainBuffer = 0;
+  // FIXME: When C++ PCH is ready, allow use of it for a precompiled preamble.
+  if (PrecompilePreamble && !Invocation->getLangOpts().CPlusPlus) {
+    PreambleRebuildCounter = 1;
+    OverrideMainBuffer
+      = getMainBufferWithPrecompiledPreamble(*Invocation);
+  }
+  
+  llvm::Timer *ParsingTimer = 0;
+  if (TimerGroup.get()) {
+    ParsingTimer = new llvm::Timer("Initial parse", *TimerGroup);
+    ParsingTimer->startTimer();
+    Timers.push_back(ParsingTimer);
+  }
+  
+  bool Failed = Parse(OverrideMainBuffer);
+  if (ParsingTimer)
+    ParsingTimer->stopTimer();
+
+  return Failed;
+}
+
 ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI,
                                    llvm::IntrusiveRefCntPtr<Diagnostic> Diags,
                                              bool OnlyLocalDecls,
@@ -1329,33 +1371,8 @@
   AST->CompleteTranslationUnit = CompleteTranslationUnit;
   AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
   AST->Invocation.reset(CI);
-  CI->getPreprocessorOpts().RetainRemappedFileBuffers = true;
-  
-  if (getenv("LIBCLANG_TIMING"))
-    AST->TimerGroup.reset(
-                  new llvm::TimerGroup(CI->getFrontendOpts().Inputs[0].second));
-  
-  
-  llvm::MemoryBuffer *OverrideMainBuffer = 0;
-  // FIXME: When C++ PCH is ready, allow use of it for a precompiled preamble.
-  if (PrecompilePreamble && !CI->getLangOpts().CPlusPlus) {
-    AST->PreambleRebuildCounter = 1;
-    OverrideMainBuffer
-      = AST->getMainBufferWithPrecompiledPreamble(*AST->Invocation);
-  }
   
-  llvm::Timer *ParsingTimer = 0;
-  if (AST->TimerGroup.get()) {
-    ParsingTimer = new llvm::Timer("Initial parse", *AST->TimerGroup);
-    ParsingTimer->startTimer();
-    AST->Timers.push_back(ParsingTimer);
-  }
-  
-  bool Failed = AST->Parse(OverrideMainBuffer);
-  if (ParsingTimer)
-    ParsingTimer->stopTimer();
-  
-  return Failed? 0 : AST.take();
+  return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take();
 }
 
 ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
@@ -1387,41 +1404,50 @@
   // also want to force it to use clang.
   Args.push_back("-fsyntax-only");
 
-  // FIXME: We shouldn't have to pass in the path info.
-  driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
-                           "a.out", false, false, *Diags);
-
-  // Don't check that inputs exist, they have been remapped.
-  TheDriver.setCheckInputsExist(false);
-
-  llvm::OwningPtr<driver::Compilation> C(
-    TheDriver.BuildCompilation(Args.size(), Args.data()));
-
-  // We expect to get back exactly one command job, if we didn't something
-  // failed.
-  const driver::JobList &Jobs = C->getJobs();
-  if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
-    llvm::SmallString<256> Msg;
-    llvm::raw_svector_ostream OS(Msg);
-    C->PrintJob(OS, C->getJobs(), "; ", true);
-    Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
-    return 0;
-  }
-
-  const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
-  if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
-    Diags->Report(diag::err_fe_expected_clang_command);
-    return 0;
-  }
+  llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
+  
+  llvm::OwningPtr<CompilerInvocation> CI;
+  {
+    CaptureDroppedDiagnostics Capture(CaptureDiagnostics, 
+                                      *Diags,
+                                      StoredDiagnostics);
+
+    // FIXME: We shouldn't have to pass in the path info.
+    driver::Driver TheDriver("clang", llvm::sys::getHostTriple(),
+                             "a.out", false, false, *Diags);
+
+    // Don't check that inputs exist, they have been remapped.
+    TheDriver.setCheckInputsExist(false);
+
+    llvm::OwningPtr<driver::Compilation> C(
+      TheDriver.BuildCompilation(Args.size(), Args.data()));
+
+    // We expect to get back exactly one command job, if we didn't something
+    // failed.
+    const driver::JobList &Jobs = C->getJobs();
+    if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
+      llvm::SmallString<256> Msg;
+      llvm::raw_svector_ostream OS(Msg);
+      C->PrintJob(OS, C->getJobs(), "; ", true);
+      Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
+      return 0;
+    }
 
-  const driver::ArgStringList &CCArgs = Cmd->getArguments();
-  llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
-  CompilerInvocation::CreateFromArgs(*CI,
-                                     const_cast<const char **>(CCArgs.data()),
-                                     const_cast<const char **>(CCArgs.data()) +
-                                     CCArgs.size(),
-                                     *Diags);
+    const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
+    if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
+      Diags->Report(diag::err_fe_expected_clang_command);
+      return 0;
+    }
 
+    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()) +
+                                       CCArgs.size(),
+                                       *Diags);
+  }
+  
   // Override any files that need remapping
   for (unsigned I = 0; I != NumRemappedFiles; ++I)
     CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
@@ -1430,11 +1456,19 @@
   // Override the resources path.
   CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
 
-  CI->getFrontendOpts().DisableFree = false;
-  return LoadFromCompilerInvocation(CI.take(), Diags, OnlyLocalDecls,
-                                    CaptureDiagnostics, PrecompilePreamble,
-                                    CompleteTranslationUnit,
-                                    CacheCodeCompletionResults);
+  // Create the AST unit.
+  llvm::OwningPtr<ASTUnit> AST;
+  AST.reset(new ASTUnit(false));
+  AST->Diagnostics = Diags;
+  AST->CaptureDiagnostics = CaptureDiagnostics;
+  AST->OnlyLocalDecls = OnlyLocalDecls;
+  AST->CompleteTranslationUnit = CompleteTranslationUnit;
+  AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults;
+  AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size();
+  AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size();
+  AST->StoredDiagnostics.swap(StoredDiagnostics);
+  AST->Invocation.reset(CI.take());
+  return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take();
 }
 
 bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) {
@@ -1832,6 +1866,9 @@
 
   // If the main file has been overridden due to the use of a preamble,
   // make that override happen and introduce the preamble.
+  StoredDiagnostics.insert(StoredDiagnostics.end(),
+                           this->StoredDiagnostics.begin(),
+             this->StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver);
   if (OverrideMainBuffer) {
     PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer);
     PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size();
@@ -1843,12 +1880,14 @@
     // The stored diagnostics have the old source manager. Copy them
     // to our output set of stored diagnostics, updating the source
     // manager to the one we were given.
-    for (unsigned I = 0, N = this->StoredDiagnostics.size(); I != N; ++I) {
+    for (unsigned I = NumStoredDiagnosticsFromDriver, 
+                  N = this->StoredDiagnostics.size(); 
+         I < N; ++I) {
       StoredDiagnostics.push_back(this->StoredDiagnostics[I]);
       FullSourceLoc Loc(StoredDiagnostics[I].getLocation(), SourceMgr);
       StoredDiagnostics[I].setLocation(Loc);
     }
-    
+
     OwnedBuffers.push_back(OverrideMainBuffer);
   } else {
     PreprocessorOpts.PrecompiledPreambleBytes.first = 0;

Added: cfe/trunk/test/Index/complete-driver-errors.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-driver-errors.c?rev=116285&view=auto
==============================================================================
--- cfe/trunk/test/Index/complete-driver-errors.c (added)
+++ cfe/trunk/test/Index/complete-driver-errors.c Mon Oct 11 19:50:20 2010
@@ -0,0 +1,23 @@
+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} (30)
+// CHECK-RESULTS: NotImplemented:{TypedText restrict} (30)
+// CHECK-RESULTS: NotImplemented:{TypedText volatile} (30)
+
+// 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
+// RUN: env CINDEXTEST_EDITING=1 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

Modified: cfe/trunk/tools/libclang/CIndexDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndexDiagnostic.cpp?rev=116285&r1=116284&r2=116285&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndexDiagnostic.cpp (original)
+++ cfe/trunk/tools/libclang/CIndexDiagnostic.cpp Mon Oct 11 19:50:20 2010
@@ -56,10 +56,6 @@
 
   CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
 
-  // Ignore diagnostics that should be ignored.
-  if (Severity == CXDiagnostic_Ignored)
-    return createCXString("");
-
   llvm::SmallString<256> Str;
   llvm::raw_svector_ostream Out(Str);
   
@@ -101,9 +97,9 @@
         if (PrintedRange)
           Out << ":";
       }
+      
+      Out << " ";
     }
-
-    Out << " ";
   }
 
   /* Print warning/error/etc. */





More information about the cfe-commits mailing list