diff options
author | Vedant Kumar <vsk@apple.com> | 2016-06-28 00:18:57 +0000 |
---|---|---|
committer | Vedant Kumar <vsk@apple.com> | 2016-06-28 00:18:57 +0000 |
commit | 02507c435ca6957468cbaac76e8135494a0266c0 (patch) | |
tree | a7a644f55f9995e21e7de77da5e8cbf73c58a5f4 | |
parent | dcbf4d68b2cc64319e65696b3bb09be1612605e9 (diff) | |
download | llvm-02507c435ca6957468cbaac76e8135494a0266c0.zip llvm-02507c435ca6957468cbaac76e8135494a0266c0.tar.gz llvm-02507c435ca6957468cbaac76e8135494a0266c0.tar.bz2 |
[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.
llvm-svn: 273971
-rw-r--r-- | llvm/docs/CommandGuide/llvm-cov.rst | 8 | ||||
-rw-r--r-- | llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp | 6 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CodeCoverage.cpp | 39 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/CoverageViewOptions.h | 1 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageView.cpp | 45 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageView.h | 21 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageViewText.cpp | 9 | ||||
-rw-r--r-- | llvm/tools/llvm-cov/SourceCoverageViewText.h | 7 |
8 files changed, 130 insertions, 6 deletions
diff --git a/llvm/docs/CommandGuide/llvm-cov.rst b/llvm/docs/CommandGuide/llvm-cov.rst index 8e2806b..35a7a03 100644 --- a/llvm/docs/CommandGuide/llvm-cov.rst +++ b/llvm/docs/CommandGuide/llvm-cov.rst @@ -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 diff --git a/llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp b/llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp index 6b969f7..587b973e 100644 --- a/llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp +++ b/llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp @@ -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 diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp index 04901a2..e7a4f67 100644 --- a/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -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; + } + 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; } @@ -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; diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h index 93bc09c..bde8b82 100644 --- a/llvm/tools/llvm-cov/CoverageViewOptions.h +++ b/llvm/tools/llvm-cov/CoverageViewOptions.h @@ -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, diff --git a/llvm/tools/llvm-cov/SourceCoverageView.cpp b/llvm/tools/llvm-cov/SourceCoverageView.cpp index 3309189..097d01b 100644 --- a/llvm/tools/llvm-cov/SourceCoverageView.cpp +++ b/llvm/tools/llvm-cov/SourceCoverageView.cpp @@ -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,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) { diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h index 03c0742..57b5d94 100644 --- a/llvm/tools/llvm-cov/SourceCoverageView.h +++ b/llvm/tools/llvm-cov/SourceCoverageView.h @@ -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,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; @@ -183,6 +196,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<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) diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp index 0757a4e..f8a313e 100644 --- a/llvm/tools/llvm-cov/SourceCoverageViewText.cpp +++ b/llvm/tools/llvm-cov/SourceCoverageViewText.cpp @@ -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"; diff --git a/llvm/tools/llvm-cov/SourceCoverageViewText.h b/llvm/tools/llvm-cov/SourceCoverageViewText.h index 17f2e79..bcbdffd 100644 --- a/llvm/tools/llvm-cov/SourceCoverageViewText.h +++ b/llvm/tools/llvm-cov/SourceCoverageViewText.h @@ -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; |