awarzynski updated this revision to Diff 293780.
awarzynski marked 17 inline comments as done.
awarzynski added a comment.

Move code from Fortran to Fortran::frontend namespace, address PR comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87774/new/

https://reviews.llvm.org/D87774

Files:
  clang/include/clang/Driver/Options.td
  flang/include/flang/Frontend/CompilerInvocation.h
  flang/include/flang/Frontend/TextDiagnostic.h
  flang/include/flang/Frontend/TextDiagnosticBuffer.h
  flang/include/flang/Frontend/TextDiagnosticPrinter.h
  flang/lib/Frontend/CMakeLists.txt
  flang/lib/Frontend/CompilerInstance.cpp
  flang/lib/Frontend/CompilerInvocation.cpp
  flang/lib/Frontend/TextDiagnostic.cpp
  flang/lib/Frontend/TextDiagnosticBuffer.cpp
  flang/lib/Frontend/TextDiagnosticPrinter.cpp
  flang/test/Flang-Driver/driver-error-cc1.c
  flang/test/Flang-Driver/driver-error-cc1.cpp
  flang/test/Flang-Driver/driver-help.f90
  flang/test/Flang-Driver/driver-version.f90
  flang/test/Flang-Driver/missing-input.f90
  flang/tools/flang-driver/driver.cpp
  flang/tools/flang-driver/fc1_main.cpp
  flang/unittests/Frontend/CompilerInstanceTest.cpp

Index: flang/unittests/Frontend/CompilerInstanceTest.cpp
===================================================================
--- flang/unittests/Frontend/CompilerInstanceTest.cpp
+++ flang/unittests/Frontend/CompilerInstanceTest.cpp
@@ -9,9 +9,9 @@
 #include "flang/Frontend/CompilerInstance.h"
 #include "gtest/gtest.h"
 #include "flang/Frontend/CompilerInvocation.h"
+#include "flang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Driver/Options.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "llvm/Support/raw_ostream.h"
 
 #include <filesystem>
@@ -24,7 +24,7 @@
   // 1. Set-up a basic DiagnosticConsumer
   std::string diagnosticOutput;
   llvm::raw_string_ostream diagnosticsOS(diagnosticOutput);
-  auto diagPrinter = std::make_unique<clang::TextDiagnosticPrinter>(
+  auto diagPrinter = std::make_unique<Fortran::TextDiagnosticPrinter>(
       diagnosticsOS, new clang::DiagnosticOptions());
 
   // 2. Create a CompilerInstance (to manage a DiagnosticEngine)
Index: flang/tools/flang-driver/fc1_main.cpp
===================================================================
--- flang/tools/flang-driver/fc1_main.cpp
+++ flang/tools/flang-driver/fc1_main.cpp
@@ -14,9 +14,9 @@
 
 #include "flang/Frontend/CompilerInstance.h"
 #include "flang/Frontend/CompilerInvocation.h"
+#include "flang/Frontend/TextDiagnosticBuffer.h"
 #include "flang/FrontendTool/Utils.h"
 #include "clang/Driver/DriverDiagnostic.h"
-#include "clang/Frontend/TextDiagnosticBuffer.h"
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/OptTable.h"
@@ -34,18 +34,22 @@
   if (!flang->HasDiagnostics())
     return 1;
 
+  // We will buffer diagnostics from argument parsing so that we can output
+  // them using a well formed diagnostic object.
+  TextDiagnosticBuffer *diagsBuffer = new TextDiagnosticBuffer;
+
   // Create CompilerInvocation - use a dedicated instance of DiagnosticsEngine
   // for parsing the arguments
   llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
       new clang::DiagnosticIDs());
   llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts =
       new clang::DiagnosticOptions();
-  clang::TextDiagnosticBuffer *diagsBuffer = new clang::TextDiagnosticBuffer;
   clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagsBuffer);
   bool success =
       CompilerInvocation::CreateFromArgs(flang->GetInvocation(), argv, diags);
 
   diagsBuffer->FlushDiagnostics(flang->getDiagnostics());
+
   if (!success)
     return 1;
 
Index: flang/tools/flang-driver/driver.cpp
===================================================================
--- flang/tools/flang-driver/driver.cpp
+++ flang/tools/flang-driver/driver.cpp
@@ -11,17 +11,21 @@
 //
 //===----------------------------------------------------------------------===//
 #include "clang/Driver/Driver.h"
+#include "flang/Frontend/CompilerInvocation.h"
+#include "flang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticIDs.h"
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Driver/Compilation.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Support/Host.h"
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/VirtualFileSystem.h"
+#include <clang/Driver/Options.h>
+
+using llvm::StringRef;
 
 // main frontend method. Lives inside fc1_main.cpp
 extern int fc1_main(llvm::ArrayRef<const char *> argv, const char *argv0);
@@ -37,6 +41,17 @@
 static clang::DiagnosticOptions *CreateAndPopulateDiagOpts(
     llvm::ArrayRef<const char *> argv) {
   auto *diagOpts = new clang::DiagnosticOptions;
+
+  // Ignore missingArgCount and the return value of ParseDiagnosticArgs.
+  // Any errors that would be diagnosed here will also be diagnosed later,
+  // when the DiagnosticsEngine actually exists.
+  unsigned missingArgIndex, missingArgCount;
+  llvm::opt::InputArgList args = clang::driver::getDriverOptTable().ParseArgs(
+      argv.slice(1), missingArgIndex, missingArgCount,
+      /*FlagsToInclude=*/clang::driver::options::FlangOption);
+
+  (void)Fortran::frontend::ParseDiagnosticArgs(*diagOpts, args);
+
   return diagOpts;
 }
 
@@ -83,8 +98,12 @@
       CreateAndPopulateDiagOpts(argv);
   llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID(
       new clang::DiagnosticIDs());
-  clang::TextDiagnosticPrinter *diagClient =
-      new clang::TextDiagnosticPrinter(llvm::errs(), &*diagOpts);
+  Fortran::frontend::TextDiagnosticPrinter *diagClient =
+      new Fortran::frontend::TextDiagnosticPrinter(llvm::errs(), &*diagOpts);
+
+  diagClient->set_prefix(
+      std::string(llvm::sys::path::stem(GetExecutablePath(argv[0]))));
+
   clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagClient);
 
   // Prepare the driver
Index: flang/test/Flang-Driver/missing-input.f90
===================================================================
--- flang/test/Flang-Driver/missing-input.f90
+++ flang/test/Flang-Driver/missing-input.f90
@@ -2,4 +2,4 @@
 
 ! REQUIRES: new-flang-driver
 
-! CHECK: error: no input files
+! CHECK: flang-new: error: no input files
Index: flang/test/Flang-Driver/driver-version.f90
===================================================================
--- flang/test/Flang-Driver/driver-version.f90
+++ flang/test/Flang-Driver/driver-version.f90
@@ -8,4 +8,4 @@
 ! CHECK-NEXT:Thread model:
 ! CHECK-NEXT:InstalledDir:
 
-! ERROR: error: unsupported option '--versions'; did you mean '--version'?
+! ERROR: flang-new: error: unsupported option '--versions'; did you mean '--version'?
Index: flang/test/Flang-Driver/driver-help.f90
===================================================================
--- flang/test/Flang-Driver/driver-help.f90
+++ flang/test/Flang-Driver/driver-help.f90
@@ -7,7 +7,9 @@
 ! CHECK:USAGE: flang-new
 ! CHECK-EMPTY:
 ! CHECK-NEXT:OPTIONS:
+! CHECK-NEXT: -fcolor-diagnostics    Enable colors in diagnostics
+! CHECK-NEXT: -fno-color-diagnostics Disable colors in diagnostics
 ! CHECK-NEXT: -help     Display available options
 ! CHECK-NEXT: --version Print version information
 
-! ERROR: error: unknown argument '-helps'; did you mean '-help'
+! ERROR: flang-new: error: unknown argument '-helps'; did you mean '-help'
Index: flang/test/Flang-Driver/driver-error-cc1.cpp
===================================================================
--- flang/test/Flang-Driver/driver-error-cc1.cpp
+++ flang/test/Flang-Driver/driver-error-cc1.cpp
@@ -4,4 +4,4 @@
 
 // C++ files are currently not supported (i.e. `flang -cc1`)
 
-// CHECK:error: unknown integrated tool '-cc1'. Valid tools include '-fc1'.
+// CHECK: error: unknown integrated tool '-cc1'. Valid tools include '-fc1'.
Index: flang/test/Flang-Driver/driver-error-cc1.c
===================================================================
--- flang/test/Flang-Driver/driver-error-cc1.c
+++ flang/test/Flang-Driver/driver-error-cc1.c
@@ -4,4 +4,4 @@
 
 // C files are currently not supported (i.e. `flang -cc1`)
 
-// CHECK:error: unknown integrated tool '-cc1'. Valid tools include '-fc1'.
+// CHECK: error: unknown integrated tool '-cc1'. Valid tools include '-fc1'.
Index: flang/lib/Frontend/TextDiagnosticPrinter.cpp
===================================================================
--- /dev/null
+++ flang/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -0,0 +1,57 @@
+//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This diagnostic client prints out their diagnostic messages.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Frontend/TextDiagnosticPrinter.h"
+#include "flang/Frontend/TextDiagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace Fortran::frontend;
+
+using llvm::SmallString;
+
+TextDiagnosticPrinter::TextDiagnosticPrinter(
+    raw_ostream &os, clang::DiagnosticOptions *diags)
+    : os_(os), diagOpts_(diags) {}
+
+TextDiagnosticPrinter::~TextDiagnosticPrinter() {}
+
+void TextDiagnosticPrinter::HandleDiagnostic(
+    clang::DiagnosticsEngine::Level level, const clang::Diagnostic &info) {
+  // Default implementation (Warnings/errors count).
+  DiagnosticConsumer::HandleDiagnostic(level, info);
+
+  // Render the diagnostic message into a temporary buffer eagerly. We'll use
+  // this later as we print out the diagnostic to the terminal.
+  SmallString<100> outStr;
+  info.FormatDiagnostic(outStr);
+
+  llvm::raw_svector_ostream DiagMessageStream(outStr);
+
+  if (!prefix_.empty())
+    os_ << prefix_ << ": ";
+
+  // We only emit diagnostics in contexts that lack valid source locations.
+  assert(!info.getLocation().isValid() &&
+      "Diagnostics with valid source location are not supported");
+
+  Fortran::frontend::TextDiagnostic::PrintDiagnosticLevel(
+      os_, level, diagOpts_->ShowColors);
+  Fortran::frontend::TextDiagnostic::PrintDiagnosticMessage(os_,
+      /*IsSupplemental=*/level == clang::DiagnosticsEngine::Note,
+      DiagMessageStream.str(), diagOpts_->ShowColors);
+
+  os_.flush();
+  return;
+}
Index: flang/lib/Frontend/TextDiagnosticBuffer.cpp
===================================================================
--- /dev/null
+++ flang/lib/Frontend/TextDiagnosticBuffer.cpp
@@ -0,0 +1,74 @@
+//===- TextDiagnosticBuffer.cpp - Buffer Text Diagnostics -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a concrete diagnostic client, which buffers the diagnostic messages.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace Fortran::frontend;
+
+/// HandleDiagnostic - Store the errors, warnings, and notes that are
+/// reported.
+void TextDiagnosticBuffer::HandleDiagnostic(
+    clang::DiagnosticsEngine::Level level, const clang::Diagnostic &info) {
+  // Default implementation (warnings_/errors count).
+  DiagnosticConsumer::HandleDiagnostic(level, info);
+
+  llvm::SmallString<100> buf;
+  info.FormatDiagnostic(buf);
+  switch (level) {
+  default:
+    llvm_unreachable("Diagnostic not handled during diagnostic buffering!");
+  case clang::DiagnosticsEngine::Note:
+    all_.emplace_back(level, notes_.size());
+    notes_.emplace_back(info.getLocation(), std::string(buf.str()));
+    break;
+  case clang::DiagnosticsEngine::Warning:
+    all_.emplace_back(level, warnings_.size());
+    warnings_.emplace_back(info.getLocation(), std::string(buf.str()));
+    break;
+  case clang::DiagnosticsEngine::Remark:
+    all_.emplace_back(level, remarks_.size());
+    remarks_.emplace_back(info.getLocation(), std::string(buf.str()));
+    break;
+  case clang::DiagnosticsEngine::Error:
+  case clang::DiagnosticsEngine::Fatal:
+    all_.emplace_back(level, errors_.size());
+    errors_.emplace_back(info.getLocation(), std::string(buf.str()));
+    break;
+  }
+}
+
+void TextDiagnosticBuffer::FlushDiagnostics(
+    clang::DiagnosticsEngine &Diags) const {
+  for (const auto &i : all_) {
+    auto Diag = Diags.Report(Diags.getCustomDiagID(i.first, "%0"));
+    switch (i.first) {
+    default:
+      llvm_unreachable("Diagnostic not handled during diagnostic flushing!");
+    case clang::DiagnosticsEngine::Note:
+      Diag << notes_[i.second].second;
+      break;
+    case clang::DiagnosticsEngine::Warning:
+      Diag << warnings_[i.second].second;
+      break;
+    case clang::DiagnosticsEngine::Remark:
+      Diag << remarks_[i.second].second;
+      break;
+    case clang::DiagnosticsEngine::Error:
+    case clang::DiagnosticsEngine::Fatal:
+      Diag << errors_[i.second].second;
+      break;
+    }
+  }
+}
Index: flang/lib/Frontend/TextDiagnostic.cpp
===================================================================
--- /dev/null
+++ flang/lib/Frontend/TextDiagnostic.cpp
@@ -0,0 +1,97 @@
+//===--- TextDiagnostic.cpp - Text Diagnostic Pretty-Printing -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Frontend/TextDiagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace Fortran::frontend;
+
+// TODO: Similar enums are defined in clang/lib/Frontend/TextDiagnostic.cpp.
+// It would be best to share them
+static const enum llvm::raw_ostream::Colors noteColor =
+    llvm::raw_ostream::BLACK;
+static const enum llvm::raw_ostream::Colors remarkColor =
+    llvm::raw_ostream::BLUE;
+static const enum llvm::raw_ostream::Colors warningColor =
+    llvm::raw_ostream::MAGENTA;
+static const enum llvm::raw_ostream::Colors errorColor = llvm::raw_ostream::RED;
+static const enum llvm::raw_ostream::Colors fatalColor = llvm::raw_ostream::RED;
+// Used for changing only the bold attribute.
+static const enum llvm::raw_ostream::Colors savedColor =
+    llvm::raw_ostream::SAVEDCOLOR;
+
+TextDiagnostic::TextDiagnostic() {}
+
+TextDiagnostic::~TextDiagnostic() {}
+
+/*static*/ void TextDiagnostic::PrintDiagnosticLevel(llvm::raw_ostream &os,
+    clang::DiagnosticsEngine::Level level, bool showColors) {
+  if (showColors) {
+    // Print diagnostic category in bold and color
+    switch (level) {
+    case clang::DiagnosticsEngine::Ignored:
+      llvm_unreachable("Invalid diagnostic type");
+    case clang::DiagnosticsEngine::Note:
+      os.changeColor(noteColor, true);
+      break;
+    case clang::DiagnosticsEngine::Remark:
+      os.changeColor(remarkColor, true);
+      break;
+    case clang::DiagnosticsEngine::Warning:
+      os.changeColor(warningColor, true);
+      break;
+    case clang::DiagnosticsEngine::Error:
+      os.changeColor(errorColor, true);
+      break;
+    case clang::DiagnosticsEngine::Fatal:
+      os.changeColor(fatalColor, true);
+      break;
+    }
+  }
+
+  switch (level) {
+  case clang::DiagnosticsEngine::Ignored:
+    llvm_unreachable("Invalid diagnostic type");
+  case clang::DiagnosticsEngine::Note:
+    os << "note";
+    break;
+  case clang::DiagnosticsEngine::Remark:
+    os << "remark";
+    break;
+  case clang::DiagnosticsEngine::Warning:
+    os << "warning";
+    break;
+  case clang::DiagnosticsEngine::Error:
+    os << "error";
+    break;
+  case clang::DiagnosticsEngine::Fatal:
+    os << "fatal error";
+    break;
+  }
+
+  os << ": ";
+
+  if (showColors)
+    os.resetColor();
+}
+
+/*static*/
+void TextDiagnostic::PrintDiagnosticMessage(llvm::raw_ostream &os,
+    bool isSupplemental, llvm::StringRef message, bool showColors) {
+  if (showColors && !isSupplemental) {
+    // Print primary diagnostic messages in bold and without color.
+    os.changeColor(savedColor, true);
+  }
+
+  os << message;
+
+  if (showColors)
+    os.resetColor();
+  os << '\n';
+}
Index: flang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- flang/lib/Frontend/CompilerInvocation.cpp
+++ flang/lib/Frontend/CompilerInvocation.cpp
@@ -17,6 +17,7 @@
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/OptTable.h"
+#include "llvm/Support/Process.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace Fortran::frontend;
@@ -35,6 +36,49 @@
 //===----------------------------------------------------------------------===//
 // Deserialization (from args)
 //===----------------------------------------------------------------------===//
+static bool parseShowColorsArgs(
+    const llvm::opt::ArgList &args, bool defaultColor) {
+  // Color diagnostics default to auto ("on" if terminal supports) in the driver
+  // but default to off in cc1, needing an explicit OPT_fdiagnostics_color.
+  // Support both clang's -f[no-]color-diagnostics and gcc's
+  // -f[no-]diagnostics-colors[=never|always|auto].
+  enum {
+    Colors_On,
+    Colors_Off,
+    Colors_Auto
+  } ShowColors = defaultColor ? Colors_Auto : Colors_Off;
+
+  for (auto *a : args) {
+    const llvm::opt::Option &O = a->getOption();
+    if (O.matches(clang::driver::options::OPT_fcolor_diagnostics) ||
+        O.matches(clang::driver::options::OPT_fdiagnostics_color)) {
+      ShowColors = Colors_On;
+    } else if (O.matches(clang::driver::options::OPT_fno_color_diagnostics) ||
+        O.matches(clang::driver::options::OPT_fno_diagnostics_color)) {
+      ShowColors = Colors_Off;
+    } else if (O.matches(clang::driver::options::OPT_fdiagnostics_color_EQ)) {
+      llvm::StringRef value(a->getValue());
+      if (value == "always")
+        ShowColors = Colors_On;
+      else if (value == "never")
+        ShowColors = Colors_Off;
+      else if (value == "auto")
+        ShowColors = Colors_Auto;
+    }
+  }
+
+  return ShowColors == Colors_On ||
+      (ShowColors == Colors_Auto && llvm::sys::Process::StandardErrHasColors());
+}
+
+bool Fortran::frontend::ParseDiagnosticArgs(clang::DiagnosticOptions &opts,
+    llvm::opt::ArgList &args, clang::DiagnosticsEngine *diags,
+    bool defaultDiagColor) {
+  opts.ShowColors = parseShowColorsArgs(args, defaultDiagColor);
+
+  return true;
+}
+
 static InputKind ParseFrontendArgs(FrontendOptions &opts,
     llvm::opt::ArgList &args, clang::DiagnosticsEngine &diags) {
   // Identify the action (i.e. opts.ProgramAction)
Index: flang/lib/Frontend/CompilerInstance.cpp
===================================================================
--- flang/lib/Frontend/CompilerInstance.cpp
+++ flang/lib/Frontend/CompilerInstance.cpp
@@ -8,7 +8,7 @@
 
 #include "flang/Frontend/CompilerInstance.h"
 #include "flang/Frontend/CompilerInvocation.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "flang/Frontend/TextDiagnosticPrinter.h"
 #include "llvm/Support/raw_ostream.h"
 
 using namespace Fortran::frontend;
@@ -36,7 +36,7 @@
   if (client) {
     diags->setClient(client, shouldOwnClient);
   } else {
-    diags->setClient(new clang::TextDiagnosticPrinter(llvm::errs(), opts));
+    diags->setClient(new TextDiagnosticPrinter(llvm::errs(), opts));
   }
   return diags;
 }
Index: flang/lib/Frontend/CMakeLists.txt
===================================================================
--- flang/lib/Frontend/CMakeLists.txt
+++ flang/lib/Frontend/CMakeLists.txt
@@ -2,13 +2,13 @@
   CompilerInstance.cpp
   CompilerInvocation.cpp
   FrontendOptions.cpp
+  TextDiagnosticPrinter.cpp
+  TextDiagnosticBuffer.cpp
+  TextDiagnostic.cpp
 
   LINK_LIBS
   clangBasic
   clangDriver
-  # TODO: Added to re-use clang's TextDiagnosticBuffer & TextDiagnosticPrinter.
-  # Add a custom implementation for Flang and remove this dependency.
-  clangFrontend
 
   LINK_COMPONENTS
   Option
Index: flang/include/flang/Frontend/TextDiagnosticPrinter.h
===================================================================
--- /dev/null
+++ flang/include/flang/Frontend/TextDiagnosticPrinter.h
@@ -0,0 +1,55 @@
+//===--- TextDiagnosticPrinter.h - Text Diagnostic Client -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a concrete diagnostic client. In terminals that support it, the
+// diagnostics are pretty-printed (colors + bold). The printing/flushing
+// happens in HandleDiagnostics (usually called at the point when the
+// diagnostic is generated).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FLANG_FRONTEND_TEXTDIAGNOSTICPRINTER_H
+#define LLVM_FLANG_FRONTEND_TEXTDIAGNOSTICPRINTER_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+class DiagnosticOptions;
+class DiagnosticsEngine;
+}; // namespace clang
+
+using llvm::IntrusiveRefCntPtr;
+using llvm::raw_ostream;
+
+namespace Fortran::frontend {
+class TextDiagnostic;
+
+class TextDiagnosticPrinter : public clang::DiagnosticConsumer {
+  raw_ostream &os_;
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts_;
+
+  /// A string to prefix to error messages.
+  std::string prefix_;
+
+public:
+  TextDiagnosticPrinter(raw_ostream &os, clang::DiagnosticOptions *diags);
+  ~TextDiagnosticPrinter() override;
+
+  /// Set the diagnostic printer prefix string, which will be printed at the
+  /// start of any diagnostics. If empty, no prefix string is used.
+  void set_prefix(std::string value) { prefix_ = std::move(value); }
+
+  void HandleDiagnostic(clang::DiagnosticsEngine::Level level,
+      const clang::Diagnostic &info) override;
+};
+
+} // namespace Fortran::frontend
+
+#endif
Index: flang/include/flang/Frontend/TextDiagnosticBuffer.h
===================================================================
--- /dev/null
+++ flang/include/flang/Frontend/TextDiagnosticBuffer.h
@@ -0,0 +1,52 @@
+//===- TextDiagnosticBuffer.h - Buffer Text Diagnostics ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a concrete diagnostic client. The diagnostics are buffered rather
+// than printed. In order to print them, use the FlushDiagnostics method.
+// Pretty-printing is not supported.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FLANG_FRONTEND_TEXTDIAGNOSTICBUFFER_H
+#define LLVM_FLANG_FRONTEND_TEXTDIAGNOSTICBUFFER_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include <cstddef>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace Fortran::frontend {
+
+class TextDiagnosticBuffer : public clang::DiagnosticConsumer {
+public:
+  using DiagList = std::vector<std::pair<clang::SourceLocation, std::string>>;
+  using DiagnosticsLevelAndIndexPairs =
+      std::vector<std::pair<clang::DiagnosticsEngine::Level, size_t>>;
+
+private:
+  DiagList errors_, warnings_, remarks_, notes_;
+
+  /// All diagnostics in the order in which they were generated. That order
+  /// likely doesn't correspond to user input order, but at least it keeps
+  /// notes in the right places. Each pair is a diagnostic level and an index
+  /// into the corresponding DiagList above.
+  DiagnosticsLevelAndIndexPairs all_;
+
+public:
+  void HandleDiagnostic(clang::DiagnosticsEngine::Level diagLevel,
+      const clang::Diagnostic &info) override;
+
+  /// Flush the buffered diagnostics to a given diagnostic engine.
+  void FlushDiagnostics(clang::DiagnosticsEngine &diags) const;
+};
+
+} // namespace Fortran::frontend
+
+#endif // LLVM_CLANG_FRONTEND_TEXTDIAGNOSTICBUFFER_H
Index: flang/include/flang/Frontend/TextDiagnostic.h
===================================================================
--- /dev/null
+++ flang/include/flang/Frontend/TextDiagnostic.h
@@ -0,0 +1,70 @@
+//===--- TextDiagnostic.h - Text Diagnostic Pretty-Printing -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// A utility class that provides support for textual pretty-printing of
+// diagnostics. Based on clang::TextDiagnostic (this is a trimmed version).
+//
+// TODO: If expanding, consider sharing the implementation with Clang.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FLANG_FRONTEND_TEXTDIAGNOSTIC_H
+#define LLVM_FLANG_FRONTEND_TEXTDIAGNOSTIC_H
+
+#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+
+namespace Fortran::frontend {
+
+/// Class to encapsulate the logic for formatting and printing a textual
+/// diagnostic message.
+///
+/// The purpose of this class is to isolate the implementation of printing
+/// beautiful text diagnostics from any particular interfaces. Currently only
+/// simple diagnostics that lack source location information are supported (e.g.
+/// Flang driver errors).
+///
+/// In the future we can extend this class (akin to Clang) to support more
+/// complex diagnostics that would include macro backtraces, caret diagnostics,
+/// FixIt Hints and code snippets.
+///
+class TextDiagnostic {
+public:
+  TextDiagnostic();
+
+  ~TextDiagnostic();
+
+  /// Print the diagnostic level to a llvm::raw_ostream.
+  ///
+  /// This is a static helper that handles colorizing the level and formatting
+  /// it into an arbitrary output stream.
+  ///
+  /// \param os Where the message is printed
+  /// \param level The diagnostic level (e.g. error or warning)
+  /// \param showColors Enable colorizing of the message.
+  static void PrintDiagnosticLevel(llvm::raw_ostream &os,
+      clang::DiagnosticsEngine::Level level, bool showColors);
+
+  /// Pretty-print a diagnostic message to a llvm::raw_ostream.
+  ///
+  /// This is a static helper to handle the colorizing and rendering diagnostic
+  /// message to a particular ostream. In the future we can
+  /// extend it to support e.g. line wrapping. It is
+  /// publicly visible as at this stage we don't require any state data to
+  /// print a diagnostic.
+  ///
+  /// \param os Where the message is printed
+  /// \param isSupplemental true if this is a continuation note diagnostic
+  /// \param message The text actually printed
+  /// \param showColors Enable colorizing of the message.
+  static void PrintDiagnosticMessage(llvm::raw_ostream &os, bool isSupplemental,
+      llvm::StringRef message, bool showColors);
+};
+
+} // namespace Fortran::frontend
+
+#endif
Index: flang/include/flang/Frontend/CompilerInvocation.h
===================================================================
--- flang/include/flang/Frontend/CompilerInvocation.h
+++ flang/include/flang/Frontend/CompilerInvocation.h
@@ -11,8 +11,18 @@
 #include "flang/Frontend/FrontendOptions.h"
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/DiagnosticOptions.h"
+#include "llvm/Option/ArgList.h"
 
 namespace Fortran::frontend {
+
+/// Fill out Opts based on the options given in Args.
+///
+/// When errors are encountered, return false and, if Diags is non-null,
+/// report the error(s).
+bool ParseDiagnosticArgs(clang::DiagnosticOptions &opts,
+    llvm::opt::ArgList &args, clang::DiagnosticsEngine *diags = nullptr,
+    bool defaultDiagColor = true);
+
 class CompilerInvocationBase {
 public:
   /// Options controlling the diagnostic engine.$
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -870,7 +870,8 @@
   Flags<[CC1Option]>, MetaVarName<"<version>">, Values<"<major>.<minor>,latest">,
   HelpText<"Attempt to match the ABI of Clang <version>">;
 def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group<f_Group>;
-defm color_diagnostics : OptInFFlag<"color-diagnostics", "Enable", "Disable", " colors in diagnostics", [CoreOption]>;
+defm color_diagnostics : OptInFFlag<"color-diagnostics", "Enable", "Disable", " colors in diagnostics",
+  [CoreOption, FlangOption]>;
 def fdiagnostics_color : Flag<["-"], "fdiagnostics-color">, Group<f_Group>,
   Flags<[CoreOption, DriverOption]>;
 def fdiagnostics_color_EQ : Joined<["-"], "fdiagnostics-color=">, Group<f_Group>;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to