mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 12:43:36 +01:00
Reapply "[llvm-cov] Add an -output-dir option for the show sub-command""
Passing -output-dir path/to/dir to llvm-cov show creates path/to/dir if it doesn't already exist, and prints reports into that directory. In function view mode, all views are written into path/to/dir/functions.$EXTENSION. In file view mode, all views are written into path/to/dir/coverage/$PATH.$EXTENSION. Changes since the initial commit: - Avoid accidentally closing stdout twice. llvm-svn: 273985
This commit is contained in:
parent
d48e0385a1
commit
d930dacca2
@ -240,6 +240,14 @@ OPTIONS
|
||||
|
||||
Use the specified output format. The supported formats are: "text".
|
||||
|
||||
.. option:: -output-dir=PATH
|
||||
|
||||
Specify a directory to write coverage reports into. If the directory does not
|
||||
exist, it is created. When used in function view mode (i.e when -name or
|
||||
-name-regex are used to select specific functions), the report is written to
|
||||
PATH/functions.EXTENSION. When used in file view mode, a report for each file
|
||||
is written to PATH/REL_PATH_TO_FILE.EXTENSION.
|
||||
|
||||
.. option:: -line-coverage-gt=<N>
|
||||
|
||||
Show code coverage only for functions with line coverage greater than the
|
||||
|
@ -28,3 +28,9 @@ int main() { // CHECK: 161| [[@LINE]]|int main(
|
||||
|
||||
// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -filename-equivalence %s | FileCheck -check-prefixes=CHECK,WHOLE-FILE %s
|
||||
// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -filename-equivalence -name=main %s | FileCheck -check-prefixes=CHECK,FILTER %s
|
||||
|
||||
// Test -output-dir.
|
||||
// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.dir -instr-profile %t.profdata -filename-equivalence %s
|
||||
// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.dir -instr-profile %t.profdata -filename-equivalence -name=main %s
|
||||
// RUN: FileCheck -check-prefixes=CHECK,WHOLE-FILE -input-file %t.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %s
|
||||
// RUN: FileCheck -check-prefixes=CHECK,FILTER -input-file %t.dir/functions.txt %s
|
||||
|
@ -406,6 +406,12 @@ int CodeCoverageTool::show(int argc, const char **argv,
|
||||
clEnumValEnd),
|
||||
cl::init(CoverageViewOptions::OutputFormat::Text));
|
||||
|
||||
cl::opt<std::string> ShowOutputDirectory(
|
||||
"output-dir", cl::init(""),
|
||||
cl::desc("Directory in which coverage information is written out"));
|
||||
cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
|
||||
cl::aliasopt(ShowOutputDirectory));
|
||||
|
||||
auto Err = commandLineParser(argc, argv);
|
||||
if (Err)
|
||||
return Err;
|
||||
@ -418,6 +424,14 @@ int CodeCoverageTool::show(int argc, const char **argv,
|
||||
ViewOpts.ShowExpandedRegions = ShowExpansions;
|
||||
ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
|
||||
ViewOpts.ShowFormat = ShowFormat;
|
||||
ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
|
||||
|
||||
if (ViewOpts.ShowOutputDirectory != "") {
|
||||
if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
|
||||
error("Could not create output directory!", E.message());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto Coverage = load();
|
||||
if (!Coverage)
|
||||
@ -436,8 +450,17 @@ int CodeCoverageTool::show(int argc, const char **argv,
|
||||
<< "\n";
|
||||
continue;
|
||||
}
|
||||
mainView->print(outs(), /*WholeFile=*/false, /*ShowSourceName=*/true);
|
||||
outs() << "\n";
|
||||
|
||||
auto OSOrErr =
|
||||
mainView->createOutputFile("functions", /*InToplevel=*/true);
|
||||
if (Error E = OSOrErr.takeError()) {
|
||||
handleAllErrors(OSOrErr.takeError(),
|
||||
[&](const ErrorInfoBase &EI) { error(EI.message()); });
|
||||
return 1;
|
||||
}
|
||||
auto OS = std::move(OSOrErr.get());
|
||||
mainView->print(*OS.get(), /*WholeFile=*/false, /*ShowSourceName=*/true);
|
||||
mainView->closeOutputFile(std::move(OS));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -459,10 +482,16 @@ int CodeCoverageTool::show(int argc, const char **argv,
|
||||
continue;
|
||||
}
|
||||
|
||||
mainView->print(outs(), /*Wholefile=*/true,
|
||||
auto OSOrErr = mainView->createOutputFile(SourceFile, /*InToplevel=*/false);
|
||||
if (Error E = OSOrErr.takeError()) {
|
||||
handleAllErrors(OSOrErr.takeError(),
|
||||
[&](const ErrorInfoBase &EI) { error(EI.message()); });
|
||||
return 1;
|
||||
}
|
||||
auto OS = std::move(OSOrErr.get());
|
||||
mainView->print(*OS.get(), /*Wholefile=*/true,
|
||||
/*ShowSourceName=*/ShowFilenames);
|
||||
if (SourceFiles.size() > 1)
|
||||
outs() << "\n";
|
||||
mainView->closeOutputFile(std::move(OS));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -30,6 +30,7 @@ struct CoverageViewOptions {
|
||||
bool ShowFunctionInstantiations;
|
||||
bool ShowFullFilenames;
|
||||
OutputFormat ShowFormat;
|
||||
std::string ShowOutputDirectory;
|
||||
|
||||
/// \brief Change the output's stream color if the colors are enabled.
|
||||
ColoredRawOstream colored_ostream(raw_ostream &OS,
|
||||
|
@ -15,7 +15,9 @@
|
||||
#include "SourceCoverageViewText.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/LineIterator.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@ -34,6 +36,51 @@ std::string SourceCoverageView::formatCount(uint64_t N) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
void SourceCoverageView::StreamDestructor::operator()(raw_ostream *OS) const {
|
||||
if (OS == &outs())
|
||||
return;
|
||||
delete OS;
|
||||
}
|
||||
|
||||
/// \brief Create a file at ``Dir/ToplevelDir/@Path.Extension``. If
|
||||
/// \p ToplevelDir is empty, its path component is skipped.
|
||||
static Expected<SourceCoverageView::OwnedStream>
|
||||
createFileInDirectory(StringRef Dir, StringRef ToplevelDir, StringRef Path,
|
||||
StringRef Extension) {
|
||||
assert(Extension.size() && "The file extension may not be empty");
|
||||
|
||||
SmallString<256> FullPath(Dir);
|
||||
if (!ToplevelDir.empty())
|
||||
sys::path::append(FullPath, ToplevelDir);
|
||||
|
||||
auto PathBaseDir = sys::path::relative_path(sys::path::parent_path(Path));
|
||||
sys::path::append(FullPath, PathBaseDir);
|
||||
|
||||
if (auto E = sys::fs::create_directories(FullPath))
|
||||
return errorCodeToError(E);
|
||||
|
||||
auto PathFilename = (sys::path::filename(Path) + "." + Extension).str();
|
||||
sys::path::append(FullPath, PathFilename);
|
||||
|
||||
std::error_code E;
|
||||
auto OS = SourceCoverageView::OwnedStream(
|
||||
new raw_fd_ostream(FullPath, E, sys::fs::F_RW));
|
||||
if (E)
|
||||
return errorCodeToError(E);
|
||||
return std::move(OS);
|
||||
}
|
||||
|
||||
Expected<SourceCoverageView::OwnedStream>
|
||||
SourceCoverageView::createOutputStream(const CoverageViewOptions &Opts,
|
||||
StringRef Path, StringRef Extension,
|
||||
bool InToplevel) {
|
||||
if (Opts.ShowOutputDirectory == "")
|
||||
return OwnedStream(&outs());
|
||||
|
||||
return createFileInDirectory(Opts.ShowOutputDirectory,
|
||||
InToplevel ? "" : "coverage", Path, Extension);
|
||||
}
|
||||
|
||||
void SourceCoverageView::addExpansion(
|
||||
const coverage::CounterMappingRegion &Region,
|
||||
std::unique_ptr<SourceCoverageView> View) {
|
||||
|
@ -101,7 +101,7 @@ struct LineCoverageStats {
|
||||
///
|
||||
/// A source coverage view and its nested sub-views form a file-oriented
|
||||
/// representation of code coverage data. This view can be printed out by a
|
||||
/// renderer which implements the Rendering Interface.
|
||||
/// renderer which implements both the File Creation and Rendering interfaces.
|
||||
class SourceCoverageView {
|
||||
/// A function or file name.
|
||||
StringRef SourceName;
|
||||
@ -122,6 +122,25 @@ class SourceCoverageView {
|
||||
/// on display.
|
||||
std::vector<InstantiationView> InstantiationSubViews;
|
||||
|
||||
public:
|
||||
struct StreamDestructor {
|
||||
void operator()(raw_ostream *OS) const;
|
||||
};
|
||||
|
||||
using OwnedStream = std::unique_ptr<raw_ostream, StreamDestructor>;
|
||||
|
||||
/// @name File Creation Interface
|
||||
/// @{
|
||||
|
||||
/// \brief Create a file to print a coverage view into.
|
||||
virtual Expected<OwnedStream> createOutputFile(StringRef Path,
|
||||
bool InToplevel) = 0;
|
||||
|
||||
/// \brief Close a file which has been used to print a coverage view.
|
||||
virtual void closeOutputFile(OwnedStream OS) = 0;
|
||||
|
||||
/// @}
|
||||
|
||||
protected:
|
||||
struct LineRef {
|
||||
StringRef Line;
|
||||
@ -183,6 +202,12 @@ protected:
|
||||
/// digits.
|
||||
static std::string formatCount(uint64_t N);
|
||||
|
||||
/// \brief If directory output is enabled, create a file with \p Path as the
|
||||
/// suffix. Otherwise, return stdout.
|
||||
static Expected<OwnedStream>
|
||||
createOutputStream(const CoverageViewOptions &Opts, StringRef Path,
|
||||
StringRef Extension, bool InToplevel);
|
||||
|
||||
SourceCoverageView(StringRef SourceName, const MemoryBuffer &File,
|
||||
const CoverageViewOptions &Options,
|
||||
coverage::CoverageData &&CoverageInfo)
|
||||
|
@ -37,6 +37,15 @@ unsigned getDividerWidth(const CoverageViewOptions &Opts) {
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
Expected<SourceCoverageView::OwnedStream>
|
||||
SourceCoverageViewText::createOutputFile(StringRef Path, bool InToplevel) {
|
||||
return createOutputStream(getOptions(), Path, "txt", InToplevel);
|
||||
}
|
||||
|
||||
void SourceCoverageViewText::closeOutputFile(OwnedStream OS) {
|
||||
OS->operator<<('\n');
|
||||
}
|
||||
|
||||
void SourceCoverageViewText::renderSourceName(raw_ostream &OS) {
|
||||
getOptions().colored_ostream(OS, raw_ostream::CYAN) << getSourceName()
|
||||
<< ":\n";
|
||||
|
@ -20,6 +20,13 @@ namespace llvm {
|
||||
|
||||
/// \brief A code coverage view which supports text-based rendering.
|
||||
class SourceCoverageViewText : public SourceCoverageView {
|
||||
public:
|
||||
Expected<OwnedStream> createOutputFile(StringRef Path,
|
||||
bool InToplevel) override;
|
||||
|
||||
void closeOutputFile(OwnedStream OS) override;
|
||||
|
||||
private:
|
||||
void renderSourceName(raw_ostream &OS) override;
|
||||
|
||||
void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) override;
|
||||
|
Loading…
Reference in New Issue
Block a user