[lld] r367649 - Improve raw_ostream so that you can "write" colors using operator<<

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 1 21:48:30 PDT 2019


Author: ruiu
Date: Thu Aug  1 21:48:30 2019
New Revision: 367649

URL: http://llvm.org/viewvc/llvm-project?rev=367649&view=rev
Log:
Improve raw_ostream so that you can "write" colors using operator<<

1. raw_ostream supports ANSI colors so that you can write messages to
the termina with colors. Previously, in order to change and reset
color, you had to call `changeColor` and `resetColor` functions,
respectively.

So, if you print out "error: " in red, for example, you had to do
something like this:

  OS.changeColor(raw_ostream::RED);
  OS << "error: ";
  OS.resetColor();

With this patch, you can write the same code as follows:

  OS << raw_ostream::RED << "error: " << raw_ostream::RESET;

2. Add a boolean flag to raw_ostream so that you can disable colored
output. If you disable colors, changeColor, operator<<(Color),
resetColor and other color-related functions have no effect.

Most LLVM tools automatically prints out messages using colors, and
you can disable it by passing a flag such as `--disable-colors`.
This new flag makes it easy to write code that works that way.

Differential Revision: https://reviews.llvm.org/D65564

Modified:
    lld/trunk/COFF/Driver.cpp
    lld/trunk/COFF/DriverUtils.cpp
    lld/trunk/Common/ErrorHandler.cpp
    lld/trunk/ELF/Driver.cpp
    lld/trunk/ELF/DriverUtils.cpp
    lld/trunk/include/lld/Common/ErrorHandler.h
    lld/trunk/lib/Driver/DarwinLdDriver.cpp
    lld/trunk/test/COFF/color-diagnostics.test
    lld/trunk/test/ELF/color-diagnostics.test
    lld/trunk/wasm/Driver.cpp

Modified: lld/trunk/COFF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- lld/trunk/COFF/Driver.cpp (original)
+++ lld/trunk/COFF/Driver.cpp Thu Aug  1 21:48:30 2019
@@ -62,7 +62,6 @@ LinkerDriver *driver;
 bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &diag) {
   errorHandler().logName = args::getFilenameWithoutExe(args[0]);
   errorHandler().errorOS = &diag;
-  errorHandler().colorDiagnostics = diag.has_colors();
   errorHandler().errorLimitExceededMsg =
       "too many errors emitted, stopping now"
       " (use /errorlimit:0 to see all errors)";

Modified: lld/trunk/COFF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- lld/trunk/COFF/DriverUtils.cpp (original)
+++ lld/trunk/COFF/DriverUtils.cpp Thu Aug  1 21:48:30 2019
@@ -756,16 +756,17 @@ static void handleColorDiagnostics(opt::
                               OPT_no_color_diagnostics);
   if (!arg)
     return;
+
   if (arg->getOption().getID() == OPT_color_diagnostics) {
-    errorHandler().colorDiagnostics = true;
+    errorHandler().errorOS->enable_colors();
   } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
-    errorHandler().colorDiagnostics = false;
+    errorHandler().errorOS->disable_colors();
   } else {
     StringRef s = arg->getValue();
     if (s == "always")
-      errorHandler().colorDiagnostics = true;
+      errorHandler().errorOS->enable_colors();
     else if (s == "never")
-      errorHandler().colorDiagnostics = false;
+      errorHandler().errorOS->disable_colors();
     else if (s != "auto")
       error("unknown option: --color-diagnostics=" + s);
   }

Modified: lld/trunk/Common/ErrorHandler.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/Common/ErrorHandler.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- lld/trunk/Common/ErrorHandler.cpp (original)
+++ lld/trunk/Common/ErrorHandler.cpp Thu Aug  1 21:48:30 2019
@@ -85,54 +85,41 @@ void lld::checkError(Error e) {
                   [&](ErrorInfoBase &eib) { error(eib.message()); });
 }
 
-static std::string getLocation(std::string msg, std::string defaultMsg) {
-  static std::vector<std::regex> Regexes{
-      std::regex(R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+)\n.*)"),
+std::string ErrorHandler::getLocation(const Twine &msg) {
+  if (!vsDiagnostics)
+    return logName;
+
+  static std::regex regexes[] = {
+      std::regex(
+          R"(^undefined (?:\S+ )?symbol:.*\n>>> referenced by (\S+):(\d+)\n.*)"),
       std::regex(R"(^undefined symbol:.*\n>>> referenced by (.*):)"),
       std::regex(
           R"(^duplicate symbol: .*\n>>> defined in (\S+)\n>>> defined in.*)"),
-      std::regex(
-          R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+).*)"),
-      std::regex(
-          R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"),
+      std::regex(R"(^duplicate symbol: .*\n>>> defined at (\S+):(\d+).*)"),
+      std::regex(R"(.*\n>>> defined in .*\n>>> referenced by (\S+):(\d+))"),
       std::regex(R"((\S+):(\d+): unclosed quote)"),
   };
 
-  std::smatch Match;
-  for (std::regex &Re : Regexes) {
-    if (std::regex_search(msg, Match, Re)) {
-      return Match.size() > 2 ? Match.str(1) + "(" + Match.str(2) + ")"
-                              : Match.str(1);
-    }
-  }
-  return defaultMsg;
-}
+  std::string str = msg.str();
 
-void ErrorHandler::printHeader(StringRef s, raw_ostream::Colors c,
-                               const Twine &msg) {
+  for (std::regex &re : regexes) {
+    std::smatch match;
+    if (!std::regex_search(str, match, re))
+      continue;
 
-  if (vsDiagnostics) {
-    // A Visual Studio-style error message starts with an error location.
-    // If a location cannot be extracted then we default to LogName.
-    *errorOS << getLocation(msg.str(), logName) << ": ";
-  } else {
-    *errorOS << logName << ": ";
+    if (match.size() > 2)
+      return match.str(1) + "(" + match.str(2) + ")";
+    return match.str(1);
   }
 
-  if (colorDiagnostics) {
-    errorOS->changeColor(c, true);
-    *errorOS << s;
-    errorOS->resetColor();
-  } else {
-    *errorOS << s;
-  }
+  return logName;
 }
 
 void ErrorHandler::log(const Twine &msg) {
-  if (verbose) {
-    std::lock_guard<std::mutex> lock(mu);
-    *errorOS << logName << ": " << msg << "\n";
-  }
+  if (!verbose)
+    return;
+  std::lock_guard<std::mutex> lock(mu);
+  *errorOS << logName << ": " << msg << "\n";
 }
 
 void ErrorHandler::message(const Twine &msg) {
@@ -149,42 +136,37 @@ void ErrorHandler::warn(const Twine &msg
 
   std::lock_guard<std::mutex> lock(mu);
   newline(errorOS, msg);
-  printHeader("warning: ", raw_ostream::MAGENTA, msg);
-  *errorOS << msg << "\n";
-}
-
-void ErrorHandler::printErrorMsg(const Twine &msg) {
-  newline(errorOS, msg);
-  printHeader("error: ", raw_ostream::RED, msg);
-  *errorOS << msg << "\n";
+  *errorOS << getLocation(msg) << ": " << Color::MAGENTA
+           << "warning: " << Color::RESET << msg << "\n";
 }
 
-void ErrorHandler::printError(const Twine &msg) {
+void ErrorHandler::error(const Twine &msg) {
+  // If Microsoft Visual Studio-style error message mode is enabled,
+  // this particular error is printed out as two errors.
   if (vsDiagnostics) {
-    static std::regex reDuplicateSymbol(
-        R"(^(duplicate symbol: .*))"
-        R"((\n>>> defined at \S+:\d+\n>>>.*))"
-        R"((\n>>> defined at \S+:\d+\n>>>.*))");
-    std::string msgStr = msg.str();
-    std::smatch match;
-    if (std::regex_match(msgStr, match, reDuplicateSymbol)) {
-      printErrorMsg(match.str(1) + match.str(2));
-      printErrorMsg(match.str(1) + match.str(3));
+    static std::regex re(R"(^(duplicate symbol: .*))"
+                         R"((\n>>> defined at \S+:\d+\n>>>.*))"
+                         R"((\n>>> defined at \S+:\d+\n>>>.*))");
+    std::string str = msg.str();
+    std::smatch m;
+
+    if (std::regex_match(str, m, re)) {
+      error(m.str(1) + m.str(2));
+      error(m.str(1) + m.str(3));
       return;
     }
   }
-  printErrorMsg(msg);
-}
 
-void ErrorHandler::error(const Twine &msg) {
   std::lock_guard<std::mutex> lock(mu);
 
   if (errorLimit == 0 || errorCount < errorLimit) {
-    printError(msg);
+    newline(errorOS, msg);
+    *errorOS << getLocation(msg) << ": " << Color::RED
+             << "error: " << Color::RESET << msg << "\n";
   } else if (errorCount == errorLimit) {
     newline(errorOS, msg);
-    printHeader("error: ", raw_ostream::RED, msg);
-    *errorOS << errorLimitExceededMsg << "\n";
+    *errorOS << getLocation(msg) << ": " << Color::RED
+             << "error: " << Color::RESET << errorLimitExceededMsg << "\n";
     if (exitEarly)
       exitLld(1);
   }

Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Thu Aug  1 21:48:30 2019
@@ -82,7 +82,6 @@ bool elf::link(ArrayRef<const char *> ar
       "-error-limit=0 to see all errors)";
   errorHandler().errorOS = &error;
   errorHandler().exitEarly = canExitEarly;
-  errorHandler().colorDiagnostics = error.has_colors();
 
   inputSections.clear();
   outputSections.clear();

Modified: lld/trunk/ELF/DriverUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/DriverUtils.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- lld/trunk/ELF/DriverUtils.cpp (original)
+++ lld/trunk/ELF/DriverUtils.cpp Thu Aug  1 21:48:30 2019
@@ -58,16 +58,17 @@ static void handleColorDiagnostics(opt::
                               OPT_no_color_diagnostics);
   if (!arg)
     return;
+
   if (arg->getOption().getID() == OPT_color_diagnostics) {
-    errorHandler().colorDiagnostics = true;
+    errorHandler().errorOS->enable_colors();
   } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
-    errorHandler().colorDiagnostics = false;
+    errorHandler().errorOS->disable_colors();
   } else {
     StringRef s = arg->getValue();
     if (s == "always")
-      errorHandler().colorDiagnostics = true;
+      errorHandler().errorOS->enable_colors();
     else if (s == "never")
-      errorHandler().colorDiagnostics = false;
+      errorHandler().errorOS->disable_colors();
     else if (s != "auto")
       error("unknown option: --color-diagnostics=" + s);
   }

Modified: lld/trunk/include/lld/Common/ErrorHandler.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Common/ErrorHandler.h?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- lld/trunk/include/lld/Common/ErrorHandler.h (original)
+++ lld/trunk/include/lld/Common/ErrorHandler.h Thu Aug  1 21:48:30 2019
@@ -87,7 +87,6 @@ public:
   StringRef errorLimitExceededMsg = "too many errors emitted, stopping now";
   StringRef logName = "lld";
   llvm::raw_ostream *errorOS = &llvm::errs();
-  bool colorDiagnostics = llvm::errs().has_colors();
   bool exitEarly = true;
   bool fatalWarnings = false;
   bool verbose = false;
@@ -102,9 +101,9 @@ public:
   std::unique_ptr<llvm::FileOutputBuffer> outputBuffer;
 
 private:
-  void printHeader(StringRef s, raw_ostream::Colors c, const Twine &msg);
-  void printErrorMsg(const Twine &msg);
-  void printError(const Twine &msg);
+  using Color = raw_ostream::Color;
+
+  std::string getLocation(const Twine &msg);
 };
 
 /// Returns the default error handler.

Modified: lld/trunk/lib/Driver/DarwinLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/DarwinLdDriver.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- lld/trunk/lib/Driver/DarwinLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/DarwinLdDriver.cpp Thu Aug  1 21:48:30 2019
@@ -1151,7 +1151,6 @@ bool link(llvm::ArrayRef<const char *> a
       "'-error-limit 0' to see all errors)";
   errorHandler().errorOS = &Error;
   errorHandler().exitEarly = CanExitEarly;
-  errorHandler().colorDiagnostics = Error.has_colors();
 
   MachOLinkingContext ctx;
   if (!parse(args, ctx))

Modified: lld/trunk/test/COFF/color-diagnostics.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/color-diagnostics.test?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- lld/trunk/test/COFF/color-diagnostics.test (original)
+++ lld/trunk/test/COFF/color-diagnostics.test Thu Aug  1 21:48:30 2019
@@ -6,8 +6,8 @@
 # RUN: not lld-link -xyz --color-diagnostics=always /nosuchfile 2>&1 \
 # RUN:   | FileCheck -check-prefix=COLOR %s
 
-# COLOR: {{lld-link: .\[0;1;35mwarning: .\[0mignoring unknown argument '-xyz'}}
-# COLOR: {{lld-link: .\[0;1;31merror: .\[0mcould not open '/nosuchfile'}}
+# COLOR: {{lld-link: .\[0;35mwarning: .\[0mignoring unknown argument '-xyz'}}
+# COLOR: {{lld-link: .\[0;31merror: .\[0mcould not open '/nosuchfile'}}
 
 # RUN: not lld-link /nosuchfile 2>&1 | FileCheck -check-prefix=NOCOLOR %s
 # RUN: not lld-link -color-diagnostics=never /nosuchfile 2>&1 \

Modified: lld/trunk/test/ELF/color-diagnostics.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/color-diagnostics.test?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- lld/trunk/test/ELF/color-diagnostics.test (original)
+++ lld/trunk/test/ELF/color-diagnostics.test Thu Aug  1 21:48:30 2019
@@ -6,8 +6,8 @@
 # RUN: not ld.lld -xyz -color-diagnostics=always /nosuchfile 2>&1 \
 # RUN:   | FileCheck -check-prefix=COLOR %s
 
-# COLOR: {{ld.lld: .\[0;1;31merror: .\[0munknown argument '-xyz'}}
-# COLOR: {{ld.lld: .\[0;1;31merror: .\[0mcannot open /nosuchfile}}
+# COLOR: {{ld.lld: .\[0;31merror: .\[0munknown argument '-xyz'}}
+# COLOR: {{ld.lld: .\[0;31merror: .\[0mcannot open /nosuchfile}}
 
 # RUN: not ld.lld -color-diagnostics=foobar 2>&1 | FileCheck -check-prefix=ERR %s
 # ERR: unknown option: --color-diagnostics=foobar

Modified: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=367649&r1=367648&r2=367649&view=diff
==============================================================================
--- lld/trunk/wasm/Driver.cpp (original)
+++ lld/trunk/wasm/Driver.cpp Thu Aug  1 21:48:30 2019
@@ -83,7 +83,6 @@ bool lld::wasm::link(ArrayRef<const char
                      raw_ostream &error) {
   errorHandler().logName = args::getFilenameWithoutExe(args[0]);
   errorHandler().errorOS = &error;
-  errorHandler().colorDiagnostics = error.has_colors();
   errorHandler().errorLimitExceededMsg =
       "too many errors emitted, stopping now (use "
       "-error-limit=0 to see all errors)";
@@ -133,16 +132,17 @@ static void handleColorDiagnostics(opt::
                               OPT_no_color_diagnostics);
   if (!arg)
     return;
+
   if (arg->getOption().getID() == OPT_color_diagnostics) {
-    errorHandler().colorDiagnostics = true;
+    errorHandler().errorOS->enable_colors();
   } else if (arg->getOption().getID() == OPT_no_color_diagnostics) {
-    errorHandler().colorDiagnostics = false;
+    errorHandler().errorOS->disable_colors();
   } else {
     StringRef s = arg->getValue();
     if (s == "always")
-      errorHandler().colorDiagnostics = true;
+      errorHandler().errorOS->enable_colors();
     else if (s == "never")
-      errorHandler().colorDiagnostics = false;
+      errorHandler().errorOS->disable_colors();
     else if (s != "auto")
       error("unknown option: --color-diagnostics=" + s);
   }




More information about the llvm-commits mailing list