]> granicus.if.org Git - clang/commitdiff
implement a new -fprint-source-range-info option, which
authorChris Lattner <sabre@nondot.org>
Fri, 13 Mar 2009 01:08:23 +0000 (01:08 +0000)
committerChris Lattner <sabre@nondot.org>
Fri, 13 Mar 2009 01:08:23 +0000 (01:08 +0000)
defaults to off.  When enabled, it emits range info along
with the file/line/col information for a diagnostic.  This
allows tools that textually parse the output of clang to know
where the ranges are, even if they span multiple lines.  For
example, with:

$ clang exprs.c -fprint-source-range-info

We now produce:

exprs.c:21:11:{21:12-21:13}: warning: use of unary operator that may be intended as compound assignment (+=)
      var =+ 5;  // expected-warning {{use of unary operator that may be intended as compound assignment (+=)}}
          ^~
exprs.c:22:11:{22:12-22:13}: warning: use of unary operator that may be intended as compound assignment (-=)
      var =- 5;  // expected-warning {{use of unary operator that may be intended as compound assignment (-=)}}
          ^~
exprs.c:36:13:{36:3-36:12}: error: assignment to cast is illegal, lvalue casts are not supported
  (float*)X = P;   // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
  ~~~~~~~~~ ^
exprs.c:41:4:{41:3-41:4}: error: called object type 'int' is not a function or function pointer
  X();  // expected-error {{called object type 'int' is not a function or function pointer}}
  ~^
exprs.c:45:15:{45:8-45:14}{45:17-45:24}: error: invalid operands to binary expression ('int *' and '_Complex float')
   P = (P-42) + Gamma*4;  // expected-error {{invalid operands to binary expression ('int *' and '_Complex float')}}
       ~~~~~~ ^ ~~~~~~~
exprs.c:61:7:{61:16-61:22}: error: invalid application of '__alignof' to bitfield
  R = __alignof(P->x);  // expected-error {{invalid application of '__alignof' to bitfield}} expected-warning {{extension used}}
      ^        ~~~~~~

Note the range info after the column in the initial diagnostic.

This is obviously really annoying if you're not a tool parsing the
output of clang, which is why it is off by default.

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

Driver/clang.cpp
include/clang/Frontend/TextDiagnosticPrinter.h
lib/Frontend/TextDiagnosticPrinter.cpp

index a0195c629a728f91647468a82d94502785b89a06..171e4ecb3112720dc33d778bbbb181fed30bfacf 100644 (file)
@@ -202,6 +202,10 @@ NoCaretDiagnostics("fno-caret-diagnostics",
                    llvm::cl::desc("Do not include source line and caret with"
                                   " diagnostics"));
 
+static llvm::cl::opt<bool>
+PrintSourceRangeInfo("fprint-source-range-info",
+                    llvm::cl::desc("Print source range spans in numeric form"));
+
 
 //===----------------------------------------------------------------------===//
 // C++ Visualization.
@@ -799,6 +803,8 @@ static std::string CreateTargetTriple() {
 //   -A...    - Play with #assertions
 //   -undef   - Undefine all predefined macros
 
+// FIXME: -imacros
+
 static llvm::cl::list<std::string>
 D_macros("D", llvm::cl::value_desc("macro"), llvm::cl::Prefix,
        llvm::cl::desc("Predefine the specified macro"));
@@ -810,7 +816,6 @@ static llvm::cl::list<std::string>
 ImplicitIncludes("include", llvm::cl::value_desc("file"),
                  llvm::cl::desc("Include file before parsing"));
 
-
 // Append a #define line to Buf for Macro.  Macro should be of the form XXX,
 // in which case we emit "#define XXX 1" or "XXX=Y z W" in which case we emit
 // "#define XXX Y z W".  To get a #define with no value, use "XXX=".
@@ -910,7 +915,6 @@ static bool InitializePreprocessor(Preprocessor &PP,
 // FIXME: -nostdinc,-nostdinc++
 // FIXME: -imultilib
 //
-// FIXME: -imacros
 
 static llvm::cl::opt<bool>
 nostdinc("nostdinc", llvm::cl::desc("Disable standard #include directories"));
@@ -1496,7 +1500,8 @@ int main(int argc, char **argv) {
     TextDiagClient = new TextDiagnosticPrinter(llvm::errs(),
                                                !NoShowColumn,
                                                !NoCaretDiagnostics,
-                                               !NoShowLocation);
+                                               !NoShowLocation,
+                                               PrintSourceRangeInfo);
   } else {
     // When checking diagnostics, just buffer them up.
     TextDiagClient = new TextDiagnosticBuffer();
index eeff2795131d872d6d7dbd6125f0d9eb7f42621e..0f08a952839de1c42c7e4386fcad0d38dde4a3ce 100644 (file)
@@ -33,11 +33,14 @@ class TextDiagnosticPrinter : public DiagnosticClient {
   bool ShowColumn;
   bool CaretDiagnostics;
   bool ShowLocation;
+  bool PrintRangeInfo;
 public:
   TextDiagnosticPrinter(llvm::raw_ostream &os, bool showColumn = true,
-                        bool caretDiagnistics = true, bool showLocation = true)
+                        bool caretDiagnistics = true, bool showLocation = true,
+                        bool printRangeInfo = true)
     : LastCaretDiagnosticWasNote(false), OS(os), ShowColumn(showColumn), 
-      CaretDiagnostics(caretDiagnistics), ShowLocation(showLocation) {}
+      CaretDiagnostics(caretDiagnistics), ShowLocation(showLocation),
+      PrintRangeInfo(printRangeInfo) {}
 
   void PrintIncludeStack(SourceLocation Loc, const SourceManager &SM);
 
index 160b5cfae1114923c8bbebc037d5d80a2a1f5de2..f1555dbff31f6d2cb66c587e6d77ea65807ae576 100644 (file)
@@ -261,6 +261,38 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level,
       if (ShowColumn)
         if (unsigned ColNo = PLoc.getColumn())
           OS << ColNo << ':';
+      
+      if (PrintRangeInfo && Info.getNumRanges()) {
+        FileID CaretFileID =
+          SM.getFileID(SM.getInstantiationLoc(Info.getLocation()));
+        bool PrintedRange = false;
+        
+        for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) {
+          SourceLocation B = Info.getRange(i).getBegin();
+          SourceLocation E = Info.getRange(i).getEnd();
+          std::pair<FileID, unsigned> BInfo=SM.getDecomposedInstantiationLoc(B);
+          
+          E = SM.getInstantiationLoc(E);
+          std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+          
+          // If the start or end of the range is in another file, just discard
+          // it.
+          if (BInfo.first != CaretFileID || EInfo.first != CaretFileID)
+            continue;
+          
+          // Add in the length of the token, so that we cover multi-char tokens.
+          unsigned TokSize = Lexer::MeasureTokenLength(E, SM);
+          
+          OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':'
+             << SM.getColumnNumber(BInfo.first, BInfo.second) << '-'
+             << SM.getLineNumber(EInfo.first, EInfo.second) << ':'
+             << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) << '}';
+          PrintedRange = true;
+        }
+        
+        if (PrintedRange)
+          OS << ':';
+      }
       OS << ' ';
     }
   }