Add machine-parseable Fix-It output as part of diagnostics, under the
flag -fdiagnostics-parseable-fixits, from Eelis van der Weegen!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111557 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/docs/UsersManual.html b/docs/UsersManual.html
index 2402bf8..1fcd59e 100644
--- a/docs/UsersManual.html
+++ b/docs/UsersManual.html
@@ -358,6 +358,18 @@
 <p>The {}'s are generated by -fdiagnostics-print-source-range-info.</p>
 </dd>
 
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+<dt id="opt_fdiagnostics-parseable-fixits">
+<b>-fdiagnostics-parseable-fixits</b>:
+Print Fix-Its in a machine parseable form.</dt>
+<dd><p>This option makes Clang print available Fix-Its in a machine parseable format at the end of diagnostics. The following example illustrates the format:</p>
+
+<pre>
+ fix-it: "t.cpp":{7:25-7:29}: "Gamma"
+</pre>
+
+<p>The range printed is a half-open range, so in this example the characters at column 25 up to but not including column 29 on line 7 in t.cpp should be replaced with the string "Gamma". Either the range or the replacement string may be empty (representing strict insertions and strict erasures, respectively). Both the file name and the insertion string escape '\', tabs (as "\n"), newlines (as "\n"), double quotes(as "\n") and non-printable characters (as octal "\xxx").</p>
+</dd>
 
 </dl>
 
diff --git a/docs/tools/clang.pod b/docs/tools/clang.pod
index 94f6b76..bcf84b7 100644
--- a/docs/tools/clang.pod
+++ b/docs/tools/clang.pod
@@ -395,6 +395,7 @@
 B<-fshow-source-location>
 B<-fcaret-diagnostics>
 B<-fdiagnostics-fixit-info>
+B<-fdiagnostics-parseable-fixits>
 B<-fdiagnostics-print-source-range-info>
 B<-fprint-source-range-info>
 B<-fdiagnostics-show-option>
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index abe8148..74d9fba 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -215,6 +215,8 @@
 
 def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">,
   HelpText<"Print source range spans in numeric form">;
+def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">,
+  HelpText<"Print fix-its in machine parseable form">;
 def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">,
   HelpText<"Print diagnostic name with mappable diagnostics">;
 def fdiagnostics_show_category : Separate<"-fdiagnostics-show-category">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 034a234..45bea9c 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -261,6 +261,7 @@
 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_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">, Group<f_Group>;
 def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>;
 def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_Group>;
 def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, Group<f_Group>;
diff --git a/include/clang/Frontend/DiagnosticOptions.h b/include/clang/Frontend/DiagnosticOptions.h
index 516dc67..c80bc03 100644
--- a/include/clang/Frontend/DiagnosticOptions.h
+++ b/include/clang/Frontend/DiagnosticOptions.h
@@ -30,6 +30,7 @@
   unsigned ShowCarets : 1;       /// Show carets in diagnostics.
   unsigned ShowFixits : 1;       /// Show fixit information.
   unsigned ShowSourceRanges : 1; /// Show source ranges in numeric form.
+  unsigned ShowParseableFixits : 1; /// Show machine parseable fix-its.
   unsigned ShowOptionNames : 1;  /// Show the diagnostic name for mappable
                                  /// diagnostics.
   unsigned ShowCategories : 2;   /// Show categories: 0 -> none, 1 -> Number,
@@ -83,6 +84,7 @@
     ShowOptionNames = 0;
     ShowCategories = 0;
     ShowSourceRanges = 0;
+    ShowParseableFixits = 0;
     VerifyDiagnostics = 0;
     BinaryOutput = 0;
     ErrorLimit = 0;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 8fe2271..dd9e713 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1207,6 +1207,7 @@
   Args.AddLastArg(CmdArgs, options::OPT_fno_show_column);
   Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
   Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
+  Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits);
   Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
   Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
   Args.AddLastArg(CmdArgs, options::OPT_fwrapv);
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 47bfefa..f8a56a0 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -244,6 +244,8 @@
     Res.push_back("-fno-diagnostics-fixit-info");
   if (Opts.ShowSourceRanges)
     Res.push_back("-fdiagnostics-print-source-range-info");
+  if (Opts.ShowParseableFixits)
+    Res.push_back("-fdiagnostics-parseable-fixits");
   if (Opts.ShowColors)
     Res.push_back("-fcolor-diagnostics");
   if (Opts.VerifyDiagnostics)
@@ -933,6 +935,7 @@
       << ShowCategory;
   
   Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info);
+  Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits);
   Opts.VerifyDiagnostics = Args.hasArg(OPT_verify);
   Opts.BinaryOutput = Args.hasArg(OPT_fdiagnostics_binary);
   Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags);
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index bc1b504..c971ca3 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -537,6 +537,48 @@
     if (DiagOpts->ShowColors)
       OS.resetColor();
   }
+
+  if (DiagOpts->ShowParseableFixits) {
+
+    // We follow FixItRewriter's example in not (yet) handling
+    // fix-its in macros.
+    bool BadApples = false;
+    for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) {
+      if (Hint->RemoveRange.isInvalid() ||
+          Hint->RemoveRange.getBegin().isMacroID() ||
+          Hint->RemoveRange.getEnd().isMacroID()) {
+        BadApples = true;
+        break;
+      }
+    }
+
+    if (!BadApples) {
+      for (const FixItHint *Hint = Hints; Hint != Hints + NumHints; ++Hint) {
+
+        SourceLocation B = Hint->RemoveRange.getBegin();
+        SourceLocation E = Hint->RemoveRange.getEnd();
+
+        std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B);
+        std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E);
+
+        // Adjust for token ranges.
+        if (Hint->RemoveRange.isTokenRange())
+          EInfo.second += Lexer::MeasureTokenLength(E, SM, *LangOpts);
+
+        // We specifically do not do word-wrapping or tab-expansion here,
+        // because this is supposed to be easy to parse.
+        OS << " fix-it: \"";
+        OS.write_escaped(SM.getPresumedLoc(B).getFilename());
+        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)
+          << "}: \"";
+        OS.write_escaped(Hint->CodeToInsert);
+        OS << "\"\n";
+      }
+    }
+  }
 }
 
 /// \brief Skip over whitespace in the string, starting at the given