summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/llvm-cov/CodeCoverage.cpp
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2017-01-24 08:32:59 +0000
committerpatrick <patrick@openbsd.org>2017-01-24 08:32:59 +0000
commit53d771aafdbe5b919f264f53cba3788e2c4cffd2 (patch)
tree7eca39498be0ff1e3a6daf583cd9ca5886bb2636 /gnu/llvm/tools/llvm-cov/CodeCoverage.cpp
parentIn preparation of compiling our kernels with -ffreestanding, explicitly map (diff)
downloadwireguard-openbsd-53d771aafdbe5b919f264f53cba3788e2c4cffd2.tar.xz
wireguard-openbsd-53d771aafdbe5b919f264f53cba3788e2c4cffd2.zip
Import LLVM 4.0.0 rc1 including clang and lld to help the current
development effort on OpenBSD/arm64.
Diffstat (limited to 'gnu/llvm/tools/llvm-cov/CodeCoverage.cpp')
-rw-r--r--gnu/llvm/tools/llvm-cov/CodeCoverage.cpp379
1 files changed, 261 insertions, 118 deletions
diff --git a/gnu/llvm/tools/llvm-cov/CodeCoverage.cpp b/gnu/llvm/tools/llvm-cov/CodeCoverage.cpp
index 0a4d1a67d61..0a9807ab003 100644
--- a/gnu/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/gnu/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -30,6 +30,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
+#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/ToolOutputFile.h"
#include <functional>
@@ -38,6 +39,9 @@
using namespace llvm;
using namespace coverage;
+void exportCoverageDataToJson(const coverage::CoverageMapping &CoverageMapping,
+ raw_ostream &OS);
+
namespace {
/// \brief The implementation of the coverage tool.
class CodeCoverageTool {
@@ -46,24 +50,28 @@ public:
/// \brief The show command.
Show,
/// \brief The report command.
- Report
+ Report,
+ /// \brief The export command.
+ Export
};
+ int run(Command Cmd, int argc, const char **argv);
+
+private:
/// \brief Print the error message to the error output stream.
void error(const Twine &Message, StringRef Whence = "");
- /// \brief Record (but do not print) an error message in a thread-safe way.
- void deferError(const Twine &Message, StringRef Whence = "");
-
- /// \brief Record (but do not print) a warning message in a thread-safe way.
- void deferWarning(const Twine &Message, StringRef Whence = "");
-
- /// \brief Print (and then clear) all deferred error and warning messages.
- void consumeDeferredMessages();
+ /// \brief Print the warning message to the error output stream.
+ void warning(const Twine &Message, StringRef Whence = "");
- /// \brief Append a reference to a private copy of \p Path into SourceFiles.
+ /// \brief Convert \p Path into an absolute path and append it to the list
+ /// of collected paths.
void addCollectedPath(const std::string &Path);
+ /// \brief If \p Path is a regular file, collect the path. If it's a
+ /// directory, recursively collect all of the paths within the directory.
+ void collectPaths(const std::string &Path);
+
/// \brief Return a memory buffer for the given source file.
ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
@@ -81,16 +89,21 @@ public:
std::unique_ptr<SourceCoverageView>
createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage);
- /// \brief Load the coverage mapping data. Return nullptr if an error occured.
+ /// \brief Load the coverage mapping data. Return nullptr if an error occurred.
std::unique_ptr<CoverageMapping> load();
+ /// \brief Remove input source files which aren't mapped by \p Coverage.
+ void removeUnmappedInputs(const CoverageMapping &Coverage);
+
/// \brief If a demangler is available, demangle all symbol names.
void demangleSymbols(const CoverageMapping &Coverage);
/// \brief Demangle \p Sym if possible. Otherwise, just return \p Sym.
StringRef getSymbolForHumans(StringRef Sym) const;
- int run(Command Cmd, int argc, const char **argv);
+ /// \brief Write out a source file view to the filesystem.
+ void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage,
+ CoveragePrinter *Printer, bool ShowFilenames);
typedef llvm::function_ref<int(int, const char **)> CommandLineParserType;
@@ -100,25 +113,34 @@ public:
int report(int argc, const char **argv,
CommandLineParserType commandLineParser);
- std::string ObjectFilename;
+ int export_(int argc, const char **argv,
+ CommandLineParserType commandLineParser);
+
+ std::vector<StringRef> ObjectFilenames;
CoverageViewOptions ViewOpts;
- std::string PGOFilename;
CoverageFiltersMatchAll Filters;
- std::vector<StringRef> SourceFiles;
+
+ /// The path to the indexed profile.
+ std::string PGOFilename;
+
+ /// A list of input source files.
+ std::vector<std::string> SourceFiles;
+
+ /// Whether or not we're in -filename-equivalence mode.
bool CompareFilenamesOnly;
+
+ /// In -filename-equivalence mode, this maps absolute paths from the
+ /// coverage mapping data to input source files.
StringMap<std::string> RemappedFilenames;
+
+ /// The architecture the coverage mapping data targets.
std::string CoverageArch;
-private:
/// A cache for demangled symbol names.
StringMap<std::string> DemangledNames;
- /// File paths (absolute, or otherwise) to input source files.
- std::vector<std::string> CollectedPaths;
-
/// Errors and warnings which have not been printed.
- std::mutex DeferredMessagesLock;
- std::vector<std::string> DeferredMessages;
+ std::mutex ErrsLock;
/// A container for input source file buffers.
std::mutex LoadedSourceFilesLock;
@@ -138,29 +160,57 @@ static std::string getErrorString(const Twine &Message, StringRef Whence,
}
void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
- errs() << getErrorString(Message, Whence, false);
+ std::unique_lock<std::mutex> Guard{ErrsLock};
+ ViewOpts.colored_ostream(errs(), raw_ostream::RED)
+ << getErrorString(Message, Whence, false);
}
-void CodeCoverageTool::deferError(const Twine &Message, StringRef Whence) {
- std::unique_lock<std::mutex> Guard{DeferredMessagesLock};
- DeferredMessages.emplace_back(getErrorString(Message, Whence, false));
+void CodeCoverageTool::warning(const Twine &Message, StringRef Whence) {
+ std::unique_lock<std::mutex> Guard{ErrsLock};
+ ViewOpts.colored_ostream(errs(), raw_ostream::RED)
+ << getErrorString(Message, Whence, true);
}
-void CodeCoverageTool::deferWarning(const Twine &Message, StringRef Whence) {
- std::unique_lock<std::mutex> Guard{DeferredMessagesLock};
- DeferredMessages.emplace_back(getErrorString(Message, Whence, true));
+void CodeCoverageTool::addCollectedPath(const std::string &Path) {
+ if (CompareFilenamesOnly) {
+ SourceFiles.emplace_back(Path);
+ } else {
+ SmallString<128> EffectivePath(Path);
+ if (std::error_code EC = sys::fs::make_absolute(EffectivePath)) {
+ error(EC.message(), Path);
+ return;
+ }
+ sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true);
+ SourceFiles.emplace_back(EffectivePath.str());
+ }
}
-void CodeCoverageTool::consumeDeferredMessages() {
- std::unique_lock<std::mutex> Guard{DeferredMessagesLock};
- for (const std::string &Message : DeferredMessages)
- ViewOpts.colored_ostream(errs(), raw_ostream::RED) << Message;
- DeferredMessages.clear();
-}
+void CodeCoverageTool::collectPaths(const std::string &Path) {
+ llvm::sys::fs::file_status Status;
+ llvm::sys::fs::status(Path, Status);
+ if (!llvm::sys::fs::exists(Status)) {
+ if (CompareFilenamesOnly)
+ addCollectedPath(Path);
+ else
+ error("Missing source file", Path);
+ return;
+ }
-void CodeCoverageTool::addCollectedPath(const std::string &Path) {
- CollectedPaths.push_back(Path);
- SourceFiles.emplace_back(CollectedPaths.back());
+ if (llvm::sys::fs::is_regular_file(Status)) {
+ addCollectedPath(Path);
+ return;
+ }
+
+ if (llvm::sys::fs::is_directory(Status)) {
+ std::error_code EC;
+ for (llvm::sys::fs::recursive_directory_iterator F(Path, EC), E;
+ F != E && !EC; F.increment(EC)) {
+ if (llvm::sys::fs::is_regular_file(F->path()))
+ addCollectedPath(F->path());
+ }
+ if (EC)
+ warning(EC.message(), Path);
+ }
}
ErrorOr<const MemoryBuffer &>
@@ -177,7 +227,7 @@ CodeCoverageTool::getSourceFile(StringRef SourceFile) {
return *Files.second;
auto Buffer = MemoryBuffer::getFile(SourceFile);
if (auto EC = Buffer.getError()) {
- deferError(EC.message(), SourceFile);
+ error(EC.message(), SourceFile);
return EC;
}
LoadedSourceFiles.emplace_back(SourceFile, std::move(Buffer.get()));
@@ -241,21 +291,24 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
attachExpansionSubViews(*View, Expansions, Coverage);
for (const auto *Function : Coverage.getInstantiations(SourceFile)) {
- auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
- auto SubViewExpansions = SubViewCoverage.getExpansions();
- auto SubView = SourceCoverageView::create(
- getSymbolForHumans(Function->Name), SourceBuffer.get(), ViewOpts,
- std::move(SubViewCoverage));
- attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
+ std::unique_ptr<SourceCoverageView> SubView{nullptr};
+
+ StringRef Funcname = getSymbolForHumans(Function->Name);
- if (SubView) {
- unsigned FileID = Function->CountedRegions.front().FileID;
- unsigned Line = 0;
- for (const auto &CR : Function->CountedRegions)
- if (CR.FileID == FileID)
- Line = std::max(CR.LineEnd, Line);
- View->addInstantiation(Function->Name, Line, std::move(SubView));
+ if (Function->ExecutionCount > 0) {
+ auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
+ auto SubViewExpansions = SubViewCoverage.getExpansions();
+ SubView = SourceCoverageView::create(
+ Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
+ attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
}
+
+ unsigned FileID = Function->CountedRegions.front().FileID;
+ unsigned Line = 0;
+ for (const auto &CR : Function->CountedRegions)
+ if (CR.FileID == FileID)
+ Line = std::max(CR.LineEnd, Line);
+ View->addInstantiation(Funcname, Line, std::move(SubView));
}
return View;
}
@@ -272,39 +325,59 @@ static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
}
std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
- if (modifiedTimeGT(ObjectFilename, PGOFilename))
- errs() << "warning: profile data may be out of date - object is newer\n";
- auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename,
- CoverageArch);
+ for (StringRef ObjectFilename : ObjectFilenames)
+ if (modifiedTimeGT(ObjectFilename, PGOFilename))
+ warning("profile data may be out of date - object is newer",
+ ObjectFilename);
+ auto CoverageOrErr =
+ CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArch);
if (Error E = CoverageOrErr.takeError()) {
- colored_ostream(errs(), raw_ostream::RED)
- << "error: Failed to load coverage: " << toString(std::move(E)) << "\n";
+ error("Failed to load coverage: " + toString(std::move(E)),
+ join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "));
return nullptr;
}
auto Coverage = std::move(CoverageOrErr.get());
unsigned Mismatched = Coverage->getMismatchedCount();
- if (Mismatched) {
- colored_ostream(errs(), raw_ostream::RED)
- << "warning: " << Mismatched << " functions have mismatched data. ";
- errs() << "\n";
- }
+ if (Mismatched)
+ warning(utostr(Mismatched) + " functions have mismatched data");
- if (CompareFilenamesOnly) {
- auto CoveredFiles = Coverage.get()->getUniqueSourceFiles();
+ if (!SourceFiles.empty())
+ removeUnmappedInputs(*Coverage);
+
+ demangleSymbols(*Coverage);
+
+ return Coverage;
+}
+
+void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping &Coverage) {
+ std::vector<StringRef> CoveredFiles = Coverage.getUniqueSourceFiles();
+
+ auto UncoveredFilesIt = SourceFiles.end();
+ if (!CompareFilenamesOnly) {
+ // The user may have specified source files which aren't in the coverage
+ // mapping. Filter these files away.
+ UncoveredFilesIt = std::remove_if(
+ SourceFiles.begin(), SourceFiles.end(), [&](const std::string &SF) {
+ return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(),
+ SF);
+ });
+ } else {
for (auto &SF : SourceFiles) {
StringRef SFBase = sys::path::filename(SF);
- for (const auto &CF : CoveredFiles)
+ for (const auto &CF : CoveredFiles) {
if (SFBase == sys::path::filename(CF)) {
RemappedFilenames[CF] = SF;
SF = CF;
break;
}
+ }
}
+ UncoveredFilesIt = std::remove_if(
+ SourceFiles.begin(), SourceFiles.end(),
+ [&](const std::string &SF) { return !RemappedFilenames.count(SF); });
}
- demangleSymbols(*Coverage);
-
- return Coverage;
+ SourceFiles.erase(UncoveredFilesIt, SourceFiles.end());
}
void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
@@ -390,14 +463,43 @@ StringRef CodeCoverageTool::getSymbolForHumans(StringRef Sym) const {
return DemangledName->getValue();
}
+void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
+ CoverageMapping *Coverage,
+ CoveragePrinter *Printer,
+ bool ShowFilenames) {
+ auto View = createSourceFileView(SourceFile, *Coverage);
+ if (!View) {
+ warning("The file '" + SourceFile + "' isn't covered.");
+ return;
+ }
+
+ auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
+ if (Error E = OSOrErr.takeError()) {
+ error("Could not create view file!", toString(std::move(E)));
+ return;
+ }
+ auto OS = std::move(OSOrErr.get());
+
+ View->print(*OS.get(), /*Wholefile=*/true,
+ /*ShowSourceName=*/ShowFilenames);
+ Printer->closeViewFile(std::move(OS));
+}
+
int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
- cl::opt<std::string, true> ObjectFilename(
- cl::Positional, cl::Required, cl::location(this->ObjectFilename),
- cl::desc("Covered executable or object file."));
+ cl::opt<std::string> CovFilename(
+ cl::Positional, cl::desc("Covered executable or object file."));
+
+ cl::list<std::string> CovFilenames(
+ "object", cl::desc("Coverage executable or object file"), cl::ZeroOrMore,
+ cl::CommaSeparated);
cl::list<std::string> InputSourceFiles(
cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
+ cl::opt<bool> DebugDumpCollectedPaths(
+ "dump-collected-paths", cl::Optional, cl::Hidden,
+ cl::desc("Show the collected paths to source files"));
+
cl::opt<std::string, true> PGOFilename(
"instr-profile", cl::Required, cl::location(this->PGOFilename),
cl::desc(
@@ -414,8 +516,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
"Text output"),
clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html",
- "HTML output"),
- clEnumValEnd),
+ "HTML output")),
cl::init(CoverageViewOptions::OutputFormat::Text));
cl::opt<bool> FilenameEquivalence(
@@ -472,6 +573,15 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
ViewOpts.Debug = DebugDump;
CompareFilenamesOnly = FilenameEquivalence;
+ if (!CovFilename.empty())
+ ObjectFilenames.emplace_back(CovFilename);
+ for (const std::string &Filename : CovFilenames)
+ ObjectFilenames.emplace_back(Filename);
+ if (ObjectFilenames.empty()) {
+ errs() << "No filenames specified!\n";
+ ::exit(1);
+ }
+
ViewOpts.Format = Format;
switch (ViewOpts.Format) {
case CoverageViewOptions::OutputFormat::Text:
@@ -481,7 +591,7 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
break;
case CoverageViewOptions::OutputFormat::HTML:
if (UseColor == cl::BOU_FALSE)
- error("Color output cannot be disabled when generating html.");
+ errs() << "Color output cannot be disabled when generating html.\n";
ViewOpts.Colors = true;
break;
}
@@ -530,20 +640,20 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
if (!Arch.empty() &&
Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
- errs() << "error: Unknown architecture: " << Arch << "\n";
+ error("Unknown architecture: " + Arch);
return 1;
}
CoverageArch = Arch;
- for (const auto &File : InputSourceFiles) {
- SmallString<128> Path(File);
- if (!CompareFilenamesOnly)
- if (std::error_code EC = sys::fs::make_absolute(Path)) {
- errs() << "error: " << File << ": " << EC.message();
- return 1;
- }
- addCollectedPath(Path.str());
+ for (const std::string &File : InputSourceFiles)
+ collectPaths(File);
+
+ if (DebugDumpCollectedPaths) {
+ for (const std::string &SF : SourceFiles)
+ outs() << SF << '\n';
+ ::exit(0);
}
+
return 0;
};
@@ -552,6 +662,8 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
return show(argc, argv, commandLineParser);
case Report:
return report(argc, argv, commandLineParser);
+ case Export:
+ return export_(argc, argv, commandLineParser);
}
return 0;
}
@@ -591,6 +703,15 @@ int CodeCoverageTool::show(int argc, const char **argv,
cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
cl::aliasopt(ShowOutputDirectory));
+ cl::opt<uint32_t> TabSize(
+ "tab-size", cl::init(2),
+ cl::desc(
+ "Set tab expansion size for html coverage reports (default = 2)"));
+
+ cl::opt<std::string> ProjectTitle(
+ "project-title", cl::Optional,
+ cl::desc("Set project title for the coverage report"));
+
auto Err = commandLineParser(argc, argv);
if (Err)
return Err;
@@ -603,6 +724,8 @@ int CodeCoverageTool::show(int argc, const char **argv,
ViewOpts.ShowExpandedRegions = ShowExpansions;
ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
+ ViewOpts.TabSize = TabSize;
+ ViewOpts.ProjectTitle = ProjectTitle;
if (ViewOpts.hasOutputDirectory()) {
if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
@@ -611,6 +734,19 @@ int CodeCoverageTool::show(int argc, const char **argv,
}
}
+ sys::fs::file_status Status;
+ if (sys::fs::status(PGOFilename, Status)) {
+ error("profdata file error: can not get the file status. \n");
+ return 1;
+ }
+
+ auto ModifiedTime = Status.getLastModificationTime();
+ std::string ModifiedTimeStr = to_string(ModifiedTime);
+ size_t found = ModifiedTimeStr.rfind(':');
+ ViewOpts.CreatedTimeStr = (found != std::string::npos)
+ ? "Created: " + ModifiedTimeStr.substr(0, found)
+ : "Created: " + ModifiedTimeStr;
+
auto Coverage = load();
if (!Coverage)
return 1;
@@ -632,9 +768,7 @@ int CodeCoverageTool::show(int argc, const char **argv,
auto mainView = createFunctionView(Function, *Coverage);
if (!mainView) {
- ViewOpts.colored_ostream(errs(), raw_ostream::RED)
- << "warning: Could not read coverage for '" << Function.Name << "'."
- << "\n";
+ warning("Could not read coverage for '" + Function.Name + "'.");
continue;
}
@@ -646,7 +780,9 @@ int CodeCoverageTool::show(int argc, const char **argv,
}
// Show files
- bool ShowFilenames = SourceFiles.size() != 1;
+ bool ShowFilenames =
+ (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() ||
+ (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML);
if (SourceFiles.empty())
// Get the source files from the function coverage mapping.
@@ -655,43 +791,27 @@ int CodeCoverageTool::show(int argc, const char **argv,
// Create an index out of the source files.
if (ViewOpts.hasOutputDirectory()) {
- if (Error E = Printer->createIndexFile(SourceFiles)) {
+ if (Error E = Printer->createIndexFile(SourceFiles, *Coverage)) {
error("Could not create index file!", toString(std::move(E)));
return 1;
}
}
- // In -output-dir mode, it's safe to use multiple threads to print files.
- unsigned ThreadCount = 1;
- if (ViewOpts.hasOutputDirectory())
- ThreadCount = std::thread::hardware_concurrency();
- ThreadPool Pool(ThreadCount);
-
- for (StringRef SourceFile : SourceFiles) {
- Pool.async([this, SourceFile, &Coverage, &Printer, ShowFilenames] {
- auto View = createSourceFileView(SourceFile, *Coverage);
- if (!View) {
- deferWarning("The file '" + SourceFile.str() + "' isn't covered.");
- return;
- }
-
- auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
- if (Error E = OSOrErr.takeError()) {
- deferError("Could not create view file!", toString(std::move(E)));
- return;
- }
- auto OS = std::move(OSOrErr.get());
-
- View->print(*OS.get(), /*Wholefile=*/true,
- /*ShowSourceName=*/ShowFilenames);
- Printer->closeViewFile(std::move(OS));
- });
+ // FIXME: Sink the hardware_concurrency() == 1 check into ThreadPool.
+ if (!ViewOpts.hasOutputDirectory() ||
+ std::thread::hardware_concurrency() == 1) {
+ for (const std::string &SourceFile : SourceFiles)
+ writeSourceFileView(SourceFile, Coverage.get(), Printer.get(),
+ ShowFilenames);
+ } else {
+ // In -output-dir mode, it's safe to use multiple threads to print files.
+ ThreadPool Pool;
+ for (const std::string &SourceFile : SourceFiles)
+ Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile,
+ Coverage.get(), Printer.get(), ShowFilenames);
+ Pool.wait();
}
- Pool.wait();
-
- consumeDeferredMessages();
-
return 0;
}
@@ -708,7 +828,7 @@ int CodeCoverageTool::report(int argc, const char **argv,
if (!Coverage)
return 1;
- CoverageReport Report(ViewOpts, std::move(Coverage));
+ CoverageReport Report(ViewOpts, *Coverage.get());
if (SourceFiles.empty())
Report.renderFileReports(llvm::outs());
else
@@ -716,6 +836,24 @@ int CodeCoverageTool::report(int argc, const char **argv,
return 0;
}
+int CodeCoverageTool::export_(int argc, const char **argv,
+ CommandLineParserType commandLineParser) {
+
+ auto Err = commandLineParser(argc, argv);
+ if (Err)
+ return Err;
+
+ auto Coverage = load();
+ if (!Coverage) {
+ error("Could not load coverage information");
+ return 1;
+ }
+
+ exportCoverageDataToJson(*Coverage.get(), outs());
+
+ return 0;
+}
+
int showMain(int argc, const char *argv[]) {
CodeCoverageTool Tool;
return Tool.run(CodeCoverageTool::Show, argc, argv);
@@ -725,3 +863,8 @@ int reportMain(int argc, const char *argv[]) {
CodeCoverageTool Tool;
return Tool.run(CodeCoverageTool::Report, argc, argv);
}
+
+int exportMain(int argc, const char *argv[]) {
+ CodeCoverageTool Tool;
+ return Tool.run(CodeCoverageTool::Export, argc, argv);
+}