Skip to content

Commit

Permalink
[Clang] Add VerboseOutputStream to CompilerInstance
Browse files Browse the repository at this point in the history
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
  • Loading branch information
scott-linder committed Oct 21, 2019
1 parent 03d35ab commit fd456e4
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 6 deletions.
24 changes: 21 additions & 3 deletions include/clang/Frontend/CompilerInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -217,9 +223,6 @@ class CompilerInstance : public ModuleLoader {
/// \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);
Expand Down Expand Up @@ -349,6 +352,21 @@ class CompilerInstance : public ModuleLoader {
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
/// {
Expand Down
14 changes: 11 additions & 3 deletions lib/Frontend/CompilerInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down Expand Up @@ -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;
Expand Down
55 changes: 55 additions & 0 deletions unittests/Frontend/OutputStreamTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"));
}
}

0 comments on commit fd456e4

Please sign in to comment.