]> granicus.if.org Git - clang/commitdiff
[Clang] Add VerboseOutputStream to CompilerInstance
authorScott Linder <scott@scottlinder.com>
Mon, 21 Oct 2019 19:04:56 +0000 (19:04 +0000)
committerScott Linder <scott@scottlinder.com>
Mon, 21 Oct 2019 19:04:56 +0000 (19:04 +0000)
Remove one instance of a hardcoded output stream in
CompilerInstance::ExecuteAction. There are still other cases of output
being hard-coded to standard streams in ExecuteCompilerInvocation, but
this patch covers the case when no flags like -version or -help are
passed, namely the "X warnings and Y errors generated." diagnostic.

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

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

include/clang/Frontend/CompilerInstance.h
lib/Frontend/CompilerInstance.cpp
unittests/Frontend/OutputStreamTest.cpp

index eb49c53ff40b785577ceeb7a5ad5ce297b96cf2c..d15bdc4665a31f5f4492f01107b434c1776e667d 100644 (file)
@@ -155,6 +155,12 @@ class CompilerInstance : public ModuleLoader {
   /// One or more modules failed to build.
   bool ModuleBuildFailed = false;
 
+  /// The stream for verbose output if owned, otherwise nullptr.
+  std::unique_ptr<raw_ostream> OwnedVerboseOutputStream;
+
+  /// The stream for verbose output.
+  raw_ostream *VerboseOutputStream = &llvm::errs();
+
   /// Holds information about the output file.
   ///
   /// If TempFilename is not empty we must rename it to Filename at the end.
@@ -217,9 +223,6 @@ public:
   /// \param Act - The action to execute.
   /// \return - True on success.
   //
-  // FIXME: This function should take the stream to write any debugging /
-  // verbose output to as an argument.
-  //
   // FIXME: Eliminate the llvm_shutdown requirement, that should either be part
   // of the context or else not CompilerInstance specific.
   bool ExecuteAction(FrontendAction &Act);
@@ -349,6 +352,21 @@ public:
     return *Diagnostics->getClient();
   }
 
+  /// }
+  /// @name VerboseOutputStream
+  /// }
+
+  /// Replace the current stream for verbose output.
+  void setVerboseOutputStream(raw_ostream &Value);
+
+  /// Replace the current stream for verbose output.
+  void setVerboseOutputStream(std::unique_ptr<raw_ostream> Value);
+
+  /// Get the current stream for verbose output.
+  raw_ostream &getVerboseOutputStream() {
+    return *VerboseOutputStream;
+  }
+
   /// }
   /// @name Target Info
   /// {
index a01224f6e0ab7346565015fc02ce2081f13b5778..c409c07ff133adc79ad4428f2fd56f8adc1615e0 100644 (file)
@@ -84,6 +84,16 @@ void CompilerInstance::setDiagnostics(DiagnosticsEngine *Value) {
   Diagnostics = Value;
 }
 
+void CompilerInstance::setVerboseOutputStream(raw_ostream &Value) {
+  OwnedVerboseOutputStream.release();
+  VerboseOutputStream = &Value;
+}
+
+void CompilerInstance::setVerboseOutputStream(std::unique_ptr<raw_ostream> Value) {
+  OwnedVerboseOutputStream.swap(Value);
+  VerboseOutputStream = OwnedVerboseOutputStream.get();
+}
+
 void CompilerInstance::setTarget(TargetInfo *Value) { Target = Value; }
 void CompilerInstance::setAuxTarget(TargetInfo *Value) { AuxTarget = Value; }
 
@@ -896,9 +906,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
   // DesiredStackSpace available.
   noteBottomOfStack();
 
-  // FIXME: Take this as an argument, once all the APIs we used have moved to
-  // taking it as an input instead of hard-coding llvm::errs.
-  raw_ostream &OS = llvm::errs();
+  raw_ostream &OS = getVerboseOutputStream();
 
   if (!Act.PrepareToExecute(*this))
     return false;
index a973582f5defb1ac5b33bb3deab4603eebb1f627..14537ecdc56c7c68685c2dd735980c87b03c945b 100644 (file)
@@ -10,6 +10,7 @@
 #include "clang/CodeGen/BackendUtil.h"
 #include "clang/CodeGen/CodeGenAction.h"
 #include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/FrontendTool/Utils.h"
 #include "clang/Lex/PreprocessorOptions.h"
 #include "gtest/gtest.h"
@@ -43,4 +44,58 @@ TEST(FrontendOutputTests, TestOutputStream) {
   EXPECT_TRUE(!IRBuffer.empty());
   EXPECT_TRUE(StringRef(IRBuffer.data()).startswith("BC"));
 }
+
+TEST(FrontendOutputTests, TestVerboseOutputStreamShared) {
+  auto Invocation = std::make_shared<CompilerInvocation>();
+  Invocation->getPreprocessorOpts().addRemappedFile(
+      "test.cc", MemoryBuffer::getMemBuffer("invalid").release());
+  Invocation->getFrontendOpts().Inputs.push_back(
+      FrontendInputFile("test.cc", Language::CXX));
+  Invocation->getFrontendOpts().ProgramAction = EmitBC;
+  Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
+  CompilerInstance Compiler;
+
+  std::string VerboseBuffer;
+  raw_string_ostream VerboseStream(VerboseBuffer);
+
+  Compiler.setInvocation(std::move(Invocation));
+  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+  Compiler.createDiagnostics(
+      new TextDiagnosticPrinter(llvm::nulls(), &*DiagOpts), true);
+  Compiler.setVerboseOutputStream(VerboseStream);
+
+  bool Success = ExecuteCompilerInvocation(&Compiler);
+  EXPECT_FALSE(Success);
+  EXPECT_TRUE(!VerboseStream.str().empty());
+  EXPECT_TRUE(StringRef(VerboseBuffer.data()).contains("errors generated"));
+}
+
+TEST(FrontendOutputTests, TestVerboseOutputStreamOwned) {
+  std::string VerboseBuffer;
+  bool Success;
+  {
+    auto Invocation = std::make_shared<CompilerInvocation>();
+    Invocation->getPreprocessorOpts().addRemappedFile(
+        "test.cc", MemoryBuffer::getMemBuffer("invalid").release());
+    Invocation->getFrontendOpts().Inputs.push_back(
+        FrontendInputFile("test.cc", Language::CXX));
+    Invocation->getFrontendOpts().ProgramAction = EmitBC;
+    Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
+    CompilerInstance Compiler;
+
+    std::unique_ptr<raw_ostream> VerboseStream =
+        std::make_unique<raw_string_ostream>(VerboseBuffer);
+
+    Compiler.setInvocation(std::move(Invocation));
+    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+    Compiler.createDiagnostics(
+        new TextDiagnosticPrinter(llvm::nulls(), &*DiagOpts), true);
+    Compiler.setVerboseOutputStream(std::move(VerboseStream));
+
+    Success = ExecuteCompilerInvocation(&Compiler);
+  }
+  EXPECT_FALSE(Success);
+  EXPECT_TRUE(!VerboseBuffer.empty());
+  EXPECT_TRUE(StringRef(VerboseBuffer.data()).contains("errors generated"));
+}
 }