[cfe-commits] r94740 - in /cfe/trunk: include/clang/Basic/ include/clang/Driver/ include/clang/Frontend/ lib/Basic/ lib/Driver/ lib/Frontend/ test/Index/ tools/CIndex/

Douglas Gregor dgregor at apple.com
Wed Jan 27 22:00:52 PST 2010


Author: dgregor
Date: Thu Jan 28 00:00:51 2010
New Revision: 94740

URL: http://llvm.org/viewvc/llvm-project?rev=94740&view=rev
Log:
Introduce serialization and deserialization of diagnostic information
so that CIndex can report diagnostics through the normal mechanisms
even when executing Clang in a separate process. This applies both
when performing code completion and when using ASTs as an intermediary
for clang_createTranslationUnitFromSourceFile().

The serialized format is not perfect at the moment, because it does
not encapsulate macro-instantiation information. Instead, it maps all
source locations back to the instantiation location. However, it does
maintain source-range and fix-it information. To get perfect fidelity
from the serialized format would require serializing a large chunk of
the source manager; at present, it isn't clear if this code will live
long enough for that to matter.


Added:
    cfe/trunk/test/Index/code-complete-errors.c   (with props)
Modified:
    cfe/trunk/include/clang/Basic/Diagnostic.h
    cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
    cfe/trunk/include/clang/Basic/SourceManager.h
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Driver/Options.td
    cfe/trunk/include/clang/Frontend/DiagnosticOptions.h
    cfe/trunk/lib/Basic/Diagnostic.cpp
    cfe/trunk/lib/Driver/Tools.cpp
    cfe/trunk/lib/Frontend/CompilerInstance.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/tools/CIndex/CIndex.cpp
    cfe/trunk/tools/CIndex/CIndexCodeCompletion.cpp
    cfe/trunk/tools/CIndex/CIndexDiagnostic.cpp
    cfe/trunk/tools/CIndex/CIndexDiagnostic.h

Modified: cfe/trunk/include/clang/Basic/Diagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Diagnostic.h?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/Diagnostic.h (original)
+++ cfe/trunk/include/clang/Basic/Diagnostic.h Thu Jan 28 00:00:51 2010
@@ -23,16 +23,19 @@
 
 namespace llvm {
   template <typename T> class SmallVectorImpl;
+  class raw_ostream;
 }
 
 namespace clang {
   class DeclContext;
   class DiagnosticBuilder;
   class DiagnosticClient;
+  class FileManager;
   class IdentifierInfo;
   class LangOptions;
   class PartialDiagnostic;
   class Preprocessor;
+  class SourceManager;
   class SourceRange;
 
   // Import the diagnostic enums themselves.
@@ -400,6 +403,13 @@
   /// \brief Clear out the current diagnostic.
   void Clear() { CurDiagID = ~0U; }
 
+  /// Deserialize - Deserialize the first diagnostic within the memory
+  /// [Memory, MemoryEnd), producing a new diagnostic builder describing the
+  /// deserialized diagnostic. If the memory does not contain a
+  /// diagnostic, returns a diagnostic builder with no diagnostic ID.
+  DiagnosticBuilder Deserialize(FileManager &FM, SourceManager &SM, 
+                                const char *&Memory, const char *MemoryEnd);
+
 private:
   /// getDiagnosticMappingInfo - Return the mapping info currently set for the
   /// specified builtin diagnostic.  This returns the high bit encoding, or zero
@@ -568,6 +578,9 @@
   /// been emitted.
   ~DiagnosticBuilder() { Emit(); }
 
+  /// isActive - Determine whether this diagnostic is still active.
+  bool isActive() const { return DiagObj != 0; }
+
   /// Operator bool: conversion of DiagnosticBuilder to bool always returns
   /// true.  This allows is to be used in boolean error contexts like:
   /// return Diag(...);
@@ -786,6 +799,12 @@
   /// output buffer using the arguments stored in this diagnostic.
   void FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
                         llvm::SmallVectorImpl<char> &OutStr) const;
+
+  /// Serialize - Serialize the given diagnostic (with its diagnostic
+  /// level) to the given stream. Serialization is a lossy operation,
+  /// since the specific diagnostic ID and any macro-instantiation
+  /// information is lost.
+  void Serialize(Diagnostic::Level DiagLevel, llvm::raw_ostream &OS) const;
 };
 
 /// DiagnosticClient - This is an abstract interface implemented by clients of

Modified: cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticFrontendKinds.td Thu Jan 28 00:00:51 2010
@@ -19,6 +19,8 @@
     "cannot locate code-completion file %0">, DefaultFatal;
 def err_fe_stdout_binary : Error<"unable to change standard output to binary">,
   DefaultFatal;
+def err_fe_stderr_binary : Error<"unable to change standard error to binary">,
+  DefaultFatal;
 def err_fe_dependency_file_requires_MT : Error<
     "-dependency-file requires at least one -MT option">;
 def err_fe_incompatible_options : Error<

Modified: cfe/trunk/include/clang/Basic/SourceManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/SourceManager.h?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/SourceManager.h (original)
+++ cfe/trunk/include/clang/Basic/SourceManager.h Thu Jan 28 00:00:51 2010
@@ -669,6 +669,9 @@
       ::const_iterator fileinfo_iterator;
   fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); }
   fileinfo_iterator fileinfo_end() const { return FileInfos.end(); }
+  bool hasFileInfo(const FileEntry *File) const {
+    return FileInfos.find(File) != FileInfos.end();
+  }
 
   /// PrintStats - Print statistics to stderr.
   ///

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Thu Jan 28 00:00:51 2010
@@ -165,6 +165,7 @@
   HelpText<"Do not include source line and caret with diagnostics">;
 def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">,
   HelpText<"Do not include fixit information in diagnostics">;
+def fdiagnostics_binary : Flag<"-fdiagnostics-binary">;
 def w : Flag<"-w">, HelpText<"Suppress all warnings">;
 def pedantic : Flag<"-pedantic">;
 def pedantic_errors : Flag<"-pedantic-errors">;

Modified: cfe/trunk/include/clang/Driver/Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/include/clang/Driver/Options.td (original)
+++ cfe/trunk/include/clang/Driver/Options.td Thu Jan 28 00:00:51 2010
@@ -252,6 +252,7 @@
 def fcreate_profile : Flag<"-fcreate-profile">, Group<f_Group>;
 def fdebug_pass_arguments : Flag<"-fdebug-pass-arguments">, Group<f_Group>;
 def fdebug_pass_structure : Flag<"-fdebug-pass-structure">, Group<f_Group>;
+def fdiagnostics_binary : Flag<"-fdiagnostics-binary">, Group<f_Group>, Flags<[HelpHidden]>;
 def fdiagnostics_fixit_info : Flag<"-fdiagnostics-fixit-info">, Group<f_Group>;
 def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, Group<f_Group>;
 def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>;

Modified: cfe/trunk/include/clang/Frontend/DiagnosticOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/DiagnosticOptions.h?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/include/clang/Frontend/DiagnosticOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/DiagnosticOptions.h Thu Jan 28 00:00:51 2010
@@ -31,9 +31,12 @@
   unsigned ShowOptionNames : 1;  /// Show the diagnostic name for mappable
                                  /// diagnostics.
   unsigned ShowColors : 1;       /// Show diagnostics with ANSI color sequences.
-  unsigned VerifyDiagnostics;    /// Check that diagnostics match the expected
+  unsigned VerifyDiagnostics: 1; /// Check that diagnostics match the expected
                                  /// diagnostics, indicated by markers in the
                                  /// input source file.
+  unsigned BinaryOutput : 1;     /// Emit diagnostics via the diagnostic 
+                                 /// binary serialization mechanism, to be
+                                 /// deserialized by, e.g., the CIndex library.
 
   /// The distance between tab stops.
   unsigned TabStop;
@@ -66,6 +69,7 @@
     ShowOptionNames = 0;
     ShowSourceRanges = 0;
     VerifyDiagnostics = 0;
+    BinaryOutput = 0;
   }
 };
 

Modified: cfe/trunk/lib/Basic/Diagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Diagnostic.cpp?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/lib/Basic/Diagnostic.cpp (original)
+++ cfe/trunk/lib/Basic/Diagnostic.cpp Thu Jan 28 00:00:51 2010
@@ -21,8 +21,10 @@
 #include "clang/Analysis/AnalysisDiagnostic.h"
 #include "clang/Driver/DriverDiagnostic.h"
 
+#include "clang/Basic/FileManager.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/raw_ostream.h"
@@ -385,6 +387,123 @@
   return Result;
 }
 
+static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
+                         unsigned &Value) {
+  if (Memory + sizeof(unsigned) > MemoryEnd)
+    return true;
+
+  memmove(&Value, Memory, sizeof(unsigned));
+  Memory += sizeof(unsigned);
+  return false;
+}
+
+static bool ReadSourceLocation(FileManager &FM, SourceManager &SM,
+                               const char *&Memory, const char *MemoryEnd,
+                               SourceLocation &Location) {
+  // Read the filename.
+  unsigned FileNameLen = 0;
+  if (ReadUnsigned(Memory, MemoryEnd, FileNameLen) || 
+      Memory + FileNameLen > MemoryEnd)
+    return true;
+
+  llvm::StringRef FileName(Memory, FileNameLen);
+  Memory += FileNameLen;
+
+  // Read the line, column.
+  unsigned Line = 0, Column = 0;
+  if (ReadUnsigned(Memory, MemoryEnd, Line) ||
+      ReadUnsigned(Memory, MemoryEnd, Column))
+    return true;
+
+  if (FileName.empty()) {
+    Location = SourceLocation();
+    return false;
+  }
+
+  const FileEntry *File = FM.getFile(FileName);
+  if (!File)
+    return true;
+
+  // Make sure that this file has an entry in the source manager.
+  if (!SM.hasFileInfo(File))
+    SM.createFileID(File, SourceLocation(), SrcMgr::C_User);
+
+  Location = SM.getLocation(File, Line, Column);
+  return false;
+}
+
+DiagnosticBuilder Diagnostic::Deserialize(FileManager &FM, SourceManager &SM, 
+                                          const char *&Memory, 
+                                          const char *MemoryEnd) {
+  if (Memory == MemoryEnd)
+    return DiagnosticBuilder(0);
+
+  // Read the severity level.
+  unsigned Level = 0;
+  if (ReadUnsigned(Memory, MemoryEnd, Level) || Level > Fatal)
+    return DiagnosticBuilder(0);
+
+  // Read the source location.
+  SourceLocation Location;
+  if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Location))
+    return DiagnosticBuilder(0);
+
+  // Read the diagnostic text.
+  if (Memory == MemoryEnd)
+    return DiagnosticBuilder(0);
+
+  unsigned MessageLen = 0;
+  if (ReadUnsigned(Memory, MemoryEnd, MessageLen) ||
+      Memory + MessageLen > MemoryEnd)
+    return DiagnosticBuilder(0);
+  
+  llvm::StringRef Message(Memory, MessageLen);
+  Memory += MessageLen;
+
+  // At this point, we have enough information to form a diagnostic. Do so.
+  unsigned DiagID = getCustomDiagID((enum Level)Level, Message);
+  DiagnosticBuilder DB = Report(FullSourceLoc(Location, SM), DiagID);
+  if (Memory == MemoryEnd)
+    return DB;
+
+  // Read the source ranges.
+  unsigned NumSourceRanges = 0;
+  if (ReadUnsigned(Memory, MemoryEnd, NumSourceRanges))
+    return DB;
+  for (unsigned I = 0; I != NumSourceRanges; ++I) {
+    SourceLocation Begin, End;
+    if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, Begin) ||
+        ReadSourceLocation(FM, SM, Memory, MemoryEnd, End))
+      return DB;
+
+    DB << SourceRange(Begin, End);
+  }
+
+  // Read the fix-it hints.
+  unsigned NumFixIts = 0;
+  if (ReadUnsigned(Memory, MemoryEnd, NumFixIts))
+    return DB;
+  for (unsigned I = 0; I != NumFixIts; ++I) {
+    SourceLocation RemoveBegin, RemoveEnd, InsertionLoc;
+    unsigned InsertLen = 0;
+    if (ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveBegin) ||
+        ReadSourceLocation(FM, SM, Memory, MemoryEnd, RemoveEnd) ||
+        ReadSourceLocation(FM, SM, Memory, MemoryEnd, InsertionLoc) ||
+        ReadUnsigned(Memory, MemoryEnd, InsertLen) ||
+        Memory + InsertLen > MemoryEnd)
+      return DB;
+
+    CodeModificationHint Hint;
+    Hint.RemoveRange = SourceRange(RemoveBegin, RemoveEnd);
+    Hint.InsertionLoc = InsertionLoc;
+    Hint.CodeToInsert.assign(Memory, Memory + InsertLen);
+    Memory += InsertLen;
+    DB << Hint;
+  }
+
+  return DB;
+}
+
 struct WarningOption {
   const char  *Name;
   const short *Members;
@@ -917,6 +1036,104 @@
   }
 }
 
+static void WriteUnsigned(llvm::raw_ostream &OS, unsigned Value) {
+  OS.write((const char *)&Value, sizeof(unsigned));
+}
+
+static void WriteString(llvm::raw_ostream &OS, llvm::StringRef String) {
+  WriteUnsigned(OS, String.size());
+  OS.write(String.data(), String.size());
+}
+
+static void WriteSourceLocation(llvm::raw_ostream &OS, 
+                                SourceManager *SM,
+                                SourceLocation Location) {
+  if (!SM || Location.isInvalid()) {
+    // If we don't have a source manager or this location is invalid,
+    // just write an invalid location.
+    WriteUnsigned(OS, 0);
+    WriteUnsigned(OS, 0);
+    WriteUnsigned(OS, 0);
+    return;
+  }
+
+  Location = SM->getInstantiationLoc(Location);
+  std::pair<FileID, unsigned> Decomposed = SM->getDecomposedLoc(Location);
+  
+  WriteString(OS, SM->getFileEntryForID(Decomposed.first)->getName());
+  WriteUnsigned(OS, SM->getLineNumber(Decomposed.first, Decomposed.second));
+  WriteUnsigned(OS, SM->getColumnNumber(Decomposed.first, Decomposed.second));
+}
+
+void DiagnosticInfo::Serialize(Diagnostic::Level DiagLevel, 
+                               llvm::raw_ostream &OS) const {
+  SourceManager *SM = 0;
+  if (getLocation().isValid())
+    SM = &const_cast<SourceManager &>(getLocation().getManager());
+
+  // Write the diagnostic level and location.
+  WriteUnsigned(OS, (unsigned)DiagLevel);
+  WriteSourceLocation(OS, SM, getLocation());
+
+  // Write the diagnostic message.
+  llvm::SmallString<64> Message;
+  FormatDiagnostic(Message);
+  WriteString(OS, Message);
+  
+  // Count the number of ranges that don't point into macros, since
+  // only simple file ranges serialize well.
+  unsigned NumNonMacroRanges = 0;
+  for (unsigned I = 0, N = getNumRanges(); I != N; ++I) {
+    SourceRange R = getRange(I);
+    if (R.getBegin().isMacroID() || R.getEnd().isMacroID())
+      continue;
+
+    ++NumNonMacroRanges;
+  }
+
+  // Write the ranges.
+  WriteUnsigned(OS, NumNonMacroRanges);
+  if (NumNonMacroRanges) {
+    for (unsigned I = 0, N = getNumRanges(); I != N; ++I) {
+      SourceRange R = getRange(I);
+      if (R.getBegin().isMacroID() || R.getEnd().isMacroID())
+        continue;
+      
+      WriteSourceLocation(OS, SM, R.getBegin());
+      WriteSourceLocation(OS, SM, R.getEnd());
+    }
+  }
+
+  // Determine if all of the fix-its involve rewrites with simple file
+  // locations (not in macro instantiations). If so, we can write
+  // fix-it information.
+  unsigned NumFixIts = getNumCodeModificationHints();
+  for (unsigned I = 0; I != NumFixIts; ++I) {
+    const CodeModificationHint &Hint = getCodeModificationHint(I);
+    if (Hint.RemoveRange.isValid() &&
+        (Hint.RemoveRange.getBegin().isMacroID() ||
+         Hint.RemoveRange.getEnd().isMacroID())) {
+      NumFixIts = 0;
+      break;
+    }
+
+    if (Hint.InsertionLoc.isValid() && Hint.InsertionLoc.isMacroID()) {
+      NumFixIts = 0;
+      break;
+    }
+  }
+
+  // Write the fix-its.
+  WriteUnsigned(OS, NumFixIts);
+  for (unsigned I = 0; I != NumFixIts; ++I) {
+    const CodeModificationHint &Hint = getCodeModificationHint(I);
+    WriteSourceLocation(OS, SM, Hint.RemoveRange.getBegin());
+    WriteSourceLocation(OS, SM, Hint.RemoveRange.getEnd());
+    WriteSourceLocation(OS, SM, Hint.InsertionLoc);
+    WriteString(OS, Hint.CodeToInsert);
+  }
+}
+
 /// IncludeInDiagnosticCounts - This method (whose default implementation
 ///  returns true) indicates whether the diagnostics handled by this
 ///  DiagnosticClient should be included in the number of diagnostics

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Thu Jan 28 00:00:51 2010
@@ -1058,6 +1058,9 @@
                     options::OPT_fno_diagnostics_fixit_info))
     CmdArgs.push_back("-fno-diagnostics-fixit-info");
 
+  if (Args.hasArg(options::OPT_fdiagnostics_binary))
+    CmdArgs.push_back("-fdiagnostics-binary");
+
   // Enable -fdiagnostics-show-option by default.
   if (Args.hasFlag(options::OPT_fdiagnostics_show_option,
                    options::OPT_fno_diagnostics_show_option))

Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Thu Jan 28 00:00:51 2010
@@ -83,6 +83,23 @@
 }
 
 // Diagnostics
+namespace {
+  class BinaryDiagnosticSerializer : public DiagnosticClient {
+    llvm::raw_ostream &OS;
+    SourceManager *SourceMgr;
+  public:
+    explicit BinaryDiagnosticSerializer(llvm::raw_ostream &OS)
+      : OS(OS), SourceMgr(0) { }
+    
+    virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
+                                  const DiagnosticInfo &Info);
+  };
+}
+
+void BinaryDiagnosticSerializer::HandleDiagnostic(Diagnostic::Level DiagLevel,
+                                                  const DiagnosticInfo &Info) {
+  Info.Serialize(DiagLevel, OS);
+}
 
 static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
                               unsigned argc, char **argv,
@@ -122,8 +139,23 @@
 
   // Create the diagnostic client for reporting errors or for
   // implementing -verify.
-  llvm::OwningPtr<DiagnosticClient> DiagClient(
-    new TextDiagnosticPrinter(llvm::errs(), Opts));
+  llvm::OwningPtr<DiagnosticClient> DiagClient;
+  if (Opts.BinaryOutput) {
+    if (llvm::sys::Program::ChangeStderrToBinary()) {
+      // We weren't able to set standard error to binary, which is a
+      // bit of a problem. So, just create a text diagnostic printer
+      // to complain about this problem, and pretend that the user
+      // didn't try to use binary output.
+      DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
+      Diags->setClient(DiagClient.take());
+      Diags->Report(diag::err_fe_stderr_binary);
+      return Diags.take();
+    } else {
+      DiagClient.reset(new BinaryDiagnosticSerializer(llvm::errs()));
+    }
+  } else {
+    DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
+  }
 
   // Chain in -verify checker, if requested.
   if (Opts.VerifyDiagnostics)

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Thu Jan 28 00:00:51 2010
@@ -220,6 +220,8 @@
     Res.push_back("-fcolor-diagnostics");
   if (Opts.VerifyDiagnostics)
     Res.push_back("-verify");
+  if (Opts.BinaryOutput)
+    Res.push_back("-fdiagnostics-binary");
   if (Opts.ShowOptionNames)
     Res.push_back("-fdiagnostics-show-option");
   if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) {
@@ -808,6 +810,7 @@
   Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option);
   Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
   Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
+  Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
   Opts.TabStop = getLastArgIntValue(Args, OPT_ftabstop,
                                     DiagnosticOptions::DefaultTabStop, Diags);
   if (Opts.TabStop == 0 || Opts.TabStop > DiagnosticOptions::MaxTabStop) {

Added: cfe/trunk/test/Index/code-complete-errors.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/code-complete-errors.c?rev=94740&view=auto

==============================================================================
--- cfe/trunk/test/Index/code-complete-errors.c (added)
+++ cfe/trunk/test/Index/code-complete-errors.c Thu Jan 28 00:00:51 2010
@@ -0,0 +1,16 @@
+_Complex cd; // CHECK: code-complete-errors.c:1:1: warning: plain '_Complex' requires a type specifier; assuming '_Complex double'
+
+struct s {
+  int x, y;;
+};
+
+struct s s0 = { y: 5 }; // CHECK: code-complete-errors.c:7:20: warning: use of GNU old-style field designator extension
+
+int f(int *ptr1, float *ptr2) {
+  return ptr1 != ptr2; // CHECK: code-complete-errors.c:10:15: warning: comparison of distinct pointer types ('int *' and 'float *')
+}
+
+void g() {  }
+
+// RUN: c-index-test -code-completion-at=%s:13:12 %s 2> %t
+// RUN: FileCheck -check-prefix=CHECK %s < %t

Propchange: cfe/trunk/test/Index/code-complete-errors.c

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/Index/code-complete-errors.c

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/Index/code-complete-errors.c

------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/tools/CIndex/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.cpp?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/tools/CIndex/CIndex.cpp (original)
+++ cfe/trunk/tools/CIndex/CIndex.cpp Thu Jan 28 00:00:51 2010
@@ -1044,6 +1044,13 @@
       argv.push_back(arg);
     }
 
+  // Generate a temporary name for the diagnostics file.
+  char tmpFileResults[L_tmpnam];
+  char *tmpResultsFileName = tmpnam(tmpFileResults);
+  llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
+  TemporaryFiles.push_back(DiagnosticsFile);
+  argv.push_back("-fdiagnostics-binary");
+
   // Add the null terminator.
   argv.push_back(NULL);
 
@@ -1051,7 +1058,8 @@
   llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
                            // on Unix or NUL (Windows).
   std::string ErrMsg;
-  const llvm::sys::Path *Redirects[] = { &DevNull, &DevNull, &DevNull, NULL };
+  const llvm::sys::Path *Redirects[] = { &DevNull, &DevNull, &DiagnosticsFile,
+                                         NULL };
   llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
       /* redirects */ &Redirects[0],
       /* secondsToWait */ 0, /* memoryLimits */ 0, &ErrMsg);
@@ -1078,6 +1086,9 @@
   if (ATU)
     ATU->unlinkTemporaryFile();
   
+  ReportSerializedDiagnostics(DiagnosticsFile, *Diags, 
+                              num_unsaved_files, unsaved_files);
+
   for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
     TemporaryFiles[i].eraseFromDisk();
   

Modified: cfe/trunk/tools/CIndex/CIndexCodeCompletion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndexCodeCompletion.cpp?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/tools/CIndex/CIndexCodeCompletion.cpp (original)
+++ cfe/trunk/tools/CIndex/CIndexCodeCompletion.cpp Thu Jan 28 00:00:51 2010
@@ -231,7 +231,8 @@
   argv.push_back("-no-code-completion-debug-printer");
   argv.push_back("-Xclang");
   argv.push_back("-code-completion-macros");
-  
+  argv.push_back("-fdiagnostics-binary");
+
   // Remap any unsaved files to temporary files.
   std::vector<std::string> RemapArgs;
   if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
@@ -267,17 +268,24 @@
   // Add the null terminator.
   argv.push_back(NULL);
 
-  // Generate a temporary name for the AST file.
+  // Generate a temporary name for the code-completion results file.
   char tmpFile[L_tmpnam];
   char *tmpFileName = tmpnam(tmpFile);
   llvm::sys::Path ResultsFile(tmpFileName);
   TemporaryFiles.push_back(ResultsFile);
 
+  // Generate a temporary name for the diagnostics file.
+  char tmpFileResults[L_tmpnam];
+  char *tmpResultsFileName = tmpnam(tmpFileResults);
+  llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
+  TemporaryFiles.push_back(DiagnosticsFile);
+
   // Invoke 'clang'.
   llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
                            // on Unix or NUL (Windows).
   std::string ErrMsg;
-  const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
+  const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, 
+                                         &DiagnosticsFile, 0 };
   llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
                                      /* redirects */ &Redirects[0],
                                      /* secondsToWait */ 0,
@@ -331,7 +339,8 @@
     Results->Buffer = F;
   }
 
-  // FIXME: Parse the (redirected) standard error to emit diagnostics.
+  ReportSerializedDiagnostics(DiagnosticsFile, *Diags, 
+                              num_unsaved_files, unsaved_files);
   
   for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
     TemporaryFiles[i].eraseFromDisk();

Modified: cfe/trunk/tools/CIndex/CIndexDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndexDiagnostic.cpp?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/tools/CIndex/CIndexDiagnostic.cpp (original)
+++ cfe/trunk/tools/CIndex/CIndexDiagnostic.cpp Thu Jan 28 00:00:51 2010
@@ -14,6 +14,9 @@
 #include "CIndexer.h"
 #include "CXSourceLocation.h"
 
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/Support/MemoryBuffer.h"
+
 using namespace clang;
 using namespace clang::cxloc;
 
@@ -196,3 +199,47 @@
 }
   
 } // end extern "C"
+
+void clang::ReportSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
+                                        Diagnostic &Diags,
+                                        unsigned num_unsaved_files,
+                                        struct CXUnsavedFile *unsaved_files) {
+  using llvm::MemoryBuffer;
+  using llvm::StringRef;
+  MemoryBuffer *F = MemoryBuffer::getFile(DiagnosticsPath.c_str());
+  if (!F)
+    return;
+
+  // Enter the unsaved files into the file manager.
+  SourceManager SourceMgr;
+  FileManager FileMgr;
+  for (unsigned I = 0; I != num_unsaved_files; ++I) {
+    const FileEntry *File = FileMgr.getVirtualFile(unsaved_files[I].Filename,
+                                                   unsaved_files[I].Length,
+                                                   0);
+    if (!File) {
+      Diags.Report(diag::err_fe_remap_missing_from_file)
+        << unsaved_files[I].Filename;
+      return;
+    }
+
+    MemoryBuffer *Buffer
+      = MemoryBuffer::getMemBuffer(unsaved_files[I].Contents,
+                           unsaved_files[I].Contents + unsaved_files[I].Length);
+    if (!Buffer)
+      return;
+
+    SourceMgr.overrideFileContents(File, Buffer);
+  }
+
+  // Parse the diagnostics, emitting them one by one until we've
+  // exhausted the data.
+  StringRef Buffer = F->getBuffer();
+  const char *Memory = Buffer.data(), *MemoryEnd = Memory + Buffer.size();
+  while (Memory != MemoryEnd) {
+    DiagnosticBuilder DB = Diags.Deserialize(FileMgr, SourceMgr, 
+                                             Memory, MemoryEnd);
+    if (!DB.isActive())
+      return;
+  }
+}

Modified: cfe/trunk/tools/CIndex/CIndexDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndexDiagnostic.h?rev=94740&r1=94739&r2=94740&view=diff

==============================================================================
--- cfe/trunk/tools/CIndex/CIndexDiagnostic.h (original)
+++ cfe/trunk/tools/CIndex/CIndexDiagnostic.h Thu Jan 28 00:00:51 2010
@@ -1,4 +1,4 @@
-/*===-- CIndexDiagnostic.h - Diagnostics C Interface --------------*- C -*-===*\
+/*===-- CIndexDiagnostic.h - Diagnostics C Interface ------------*- C++ -*-===*\
 |*                                                                            *|
 |*                     The LLVM Compiler Infrastructure                       *|
 |*                                                                            *|
@@ -17,8 +17,13 @@
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/LangOptions.h"
 
+namespace llvm { namespace sys {
+class Path;
+} }
+
 namespace clang {
 
+class Diagnostic;
 class Preprocessor;
   
 /**
@@ -43,7 +48,15 @@
   virtual void HandleDiagnostic(Diagnostic::Level DiagLevel,
                                 const DiagnosticInfo &Info);
 };
-  
+
+/// \brief Given the path to a file that contains binary, serialized
+/// diagnostics produced by Clang, emit those diagnostics via the
+/// given diagnostic engine.
+void ReportSerializedDiagnostics(const llvm::sys::Path &DiagnosticsPath,
+                                 Diagnostic &Diags,
+                                 unsigned num_unsaved_files,
+                                 struct CXUnsavedFile *unsaved_files);
+
 } // end namespace clang
 
 #endif // LLVM_CLANG_CINDEX_DIAGNOSTIC_H





More information about the cfe-commits mailing list