Skip to content

Commit

Permalink
[llvm-cov] Add an -output-dir option for the show sub-command
Browse files Browse the repository at this point in the history
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.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273971 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
vedantk committed Jun 28, 2016
1 parent ba1a097 commit b979c03
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 6 deletions.
8 changes: 8 additions & 0 deletions docs/CommandGuide/llvm-cov.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions test/tools/llvm-cov/showLineExecutionCounts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
39 changes: 34 additions & 5 deletions tools/llvm-cov/CodeCoverage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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;
}
std::unique_ptr<raw_ostream> OS = std::move(OSOrErr.get());
mainView->print(*OS.get(), /*WholeFile=*/false, /*ShowSourceName=*/true);
mainView->closeOutputFile(std::move(OS));
}
return 0;
}
Expand All @@ -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;
}
std::unique_ptr<raw_ostream> 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;
Expand Down
1 change: 1 addition & 0 deletions tools/llvm-cov/CoverageViewOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
45 changes: 45 additions & 0 deletions tools/llvm-cov/SourceCoverageView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -34,6 +36,49 @@ std::string SourceCoverageView::formatCount(uint64_t N) {
return Result;
}

/// \brief Create a file at ``Dir/ToplevelDir/@Path.Extension``. If
/// \p ToplevelDir is empty, its path component is skipped.
static Expected<std::unique_ptr<raw_ostream>>
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 = llvm::make_unique<raw_fd_ostream>(FullPath, E, sys::fs::F_RW);
if (E)
return errorCodeToError(E);
return std::move(OS);
}

Expected<std::unique_ptr<raw_ostream>>
SourceCoverageView::createOutputStream(const CoverageViewOptions &Opts,
StringRef Path, StringRef Extension,
bool InToplevel) {
if (Opts.ShowOutputDirectory == "") {
std::error_code E;
auto OS = llvm::make_unique<raw_fd_ostream>("-", E, sys::fs::F_None);
if (E)
return errorCodeToError(E);
return std::move(OS);
}

return createFileInDirectory(Opts.ShowOutputDirectory,
InToplevel ? "" : "coverage", Path, Extension);
}

void SourceCoverageView::addExpansion(
const coverage::CounterMappingRegion &Region,
std::unique_ptr<SourceCoverageView> View) {
Expand Down
21 changes: 20 additions & 1 deletion tools/llvm-cov/SourceCoverageView.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -122,6 +122,19 @@ class SourceCoverageView {
/// on display.
std::vector<InstantiationView> InstantiationSubViews;

public:
/// @name File Creation Interface
/// @{

/// \brief Create a file to print a coverage view into.
virtual Expected<std::unique_ptr<raw_ostream>>
createOutputFile(StringRef Path, bool InToplevel) = 0;

/// \brief Close a file which has been used to print a coverage view.
virtual void closeOutputFile(std::unique_ptr<raw_ostream> OS) = 0;

/// @}

protected:
struct LineRef {
StringRef Line;
Expand Down Expand Up @@ -183,6 +196,12 @@ class SourceCoverageView {
/// 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<std::unique_ptr<raw_ostream>>
createOutputStream(const CoverageViewOptions &Opts, StringRef Path,
StringRef Extension, bool InToplevel);

SourceCoverageView(StringRef SourceName, const MemoryBuffer &File,
const CoverageViewOptions &Options,
coverage::CoverageData &&CoverageInfo)
Expand Down
9 changes: 9 additions & 0 deletions tools/llvm-cov/SourceCoverageViewText.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ unsigned getDividerWidth(const CoverageViewOptions &Opts) {

} // anonymous namespace

Expected<std::unique_ptr<raw_ostream>>
SourceCoverageViewText::createOutputFile(StringRef Path, bool InToplevel) {
return createOutputStream(getOptions(), Path, "txt", InToplevel);
}

void SourceCoverageViewText::closeOutputFile(std::unique_ptr<raw_ostream> OS) {
OS.get()->operator<<('\n');
}

void SourceCoverageViewText::renderSourceName(raw_ostream &OS) {
getOptions().colored_ostream(OS, raw_ostream::CYAN) << getSourceName()
<< ":\n";
Expand Down
7 changes: 7 additions & 0 deletions tools/llvm-cov/SourceCoverageViewText.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ namespace llvm {

/// \brief A code coverage view which supports text-based rendering.
class SourceCoverageViewText : public SourceCoverageView {
public:
Expected<std::unique_ptr<raw_ostream>>
createOutputFile(StringRef Path, bool InToplevel) override;

void closeOutputFile(std::unique_ptr<raw_ostream> OS) override;

private:
void renderSourceName(raw_ostream &OS) override;

void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) override;
Expand Down

0 comments on commit b979c03

Please sign in to comment.