mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
[llvm-cov] Create an index of reports in -output-dir mode
This index lists the reports available in the 'coverage' sub-directory. This will help navigate coverage output from large projects. This commit factors the file creation code out of SourceCoverageView and into CoveragePrinter. llvm-svn: 274029
This commit is contained in:
parent
51094a5889
commit
ca06df5ef5
@ -34,3 +34,7 @@ int main() { // CHECK: 161| [[@LINE]]|int main(
|
||||
// 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
|
||||
//
|
||||
// Test index creation.
|
||||
// RUN: FileCheck -check-prefix=INDEX -input-file %t.dir/index.txt %s
|
||||
// INDEX: showLineExecutionCounts.cpp.txt
|
||||
|
@ -448,6 +448,8 @@ int CodeCoverageTool::show(int argc, const char **argv,
|
||||
if (!Coverage)
|
||||
return 1;
|
||||
|
||||
auto Printer = CoveragePrinter::create(ViewOpts);
|
||||
|
||||
if (!Filters.empty()) {
|
||||
// Show functions
|
||||
for (const auto &Function : Coverage->getCoveredFunctions()) {
|
||||
@ -462,15 +464,14 @@ int CodeCoverageTool::show(int argc, const char **argv,
|
||||
continue;
|
||||
}
|
||||
|
||||
auto OSOrErr =
|
||||
mainView->createOutputFile("functions", /*InToplevel=*/true);
|
||||
auto OSOrErr = Printer->createViewFile("functions", /*InToplevel=*/true);
|
||||
if (Error E = OSOrErr.takeError()) {
|
||||
error(toString(std::move(E)));
|
||||
return 1;
|
||||
}
|
||||
auto OS = std::move(OSOrErr.get());
|
||||
mainView->print(*OS.get(), /*WholeFile=*/false, /*ShowSourceName=*/true);
|
||||
mainView->closeOutputFile(std::move(OS));
|
||||
Printer->closeViewFile(std::move(OS));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -483,6 +484,14 @@ int CodeCoverageTool::show(int argc, const char **argv,
|
||||
for (StringRef Filename : Coverage->getUniqueSourceFiles())
|
||||
SourceFiles.push_back(Filename);
|
||||
|
||||
// Create an index out of the source files.
|
||||
if (ViewOpts.hasOutputDirectory()) {
|
||||
if (Error E = Printer->createIndexFile(SourceFiles)) {
|
||||
error(toString(std::move(E)));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &SourceFile : SourceFiles) {
|
||||
auto mainView = createSourceFileView(SourceFile, *Coverage);
|
||||
if (!mainView) {
|
||||
@ -492,7 +501,7 @@ int CodeCoverageTool::show(int argc, const char **argv,
|
||||
continue;
|
||||
}
|
||||
|
||||
auto OSOrErr = mainView->createOutputFile(SourceFile, /*InToplevel=*/false);
|
||||
auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
|
||||
if (Error E = OSOrErr.takeError()) {
|
||||
error(toString(std::move(E)));
|
||||
return 1;
|
||||
@ -500,7 +509,7 @@ int CodeCoverageTool::show(int argc, const char **argv,
|
||||
auto OS = std::move(OSOrErr.get());
|
||||
mainView->print(*OS.get(), /*Wholefile=*/true,
|
||||
/*ShowSourceName=*/ShowFilenames);
|
||||
mainView->closeOutputFile(std::move(OS));
|
||||
Printer->closeViewFile(std::move(OS));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -21,6 +21,57 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
void CoveragePrinter::StreamDestructor::operator()(raw_ostream *OS) const {
|
||||
if (OS == &outs())
|
||||
return;
|
||||
delete OS;
|
||||
}
|
||||
|
||||
std::string CoveragePrinter::getOutputPath(StringRef Path, StringRef Extension,
|
||||
bool InToplevel) {
|
||||
assert(Extension.size() && "The file extension may not be empty");
|
||||
|
||||
SmallString<256> FullPath(Opts.ShowOutputDirectory);
|
||||
if (!InToplevel)
|
||||
sys::path::append(FullPath, getCoverageDir());
|
||||
|
||||
auto PathBaseDir = sys::path::relative_path(sys::path::parent_path(Path));
|
||||
sys::path::append(FullPath, PathBaseDir);
|
||||
|
||||
auto PathFilename = (sys::path::filename(Path) + "." + Extension).str();
|
||||
sys::path::append(FullPath, PathFilename);
|
||||
|
||||
return FullPath.str();
|
||||
}
|
||||
|
||||
Expected<CoveragePrinter::OwnedStream>
|
||||
CoveragePrinter::createOutputStream(StringRef Path, StringRef Extension,
|
||||
bool InToplevel) {
|
||||
if (!Opts.hasOutputDirectory())
|
||||
return OwnedStream(&outs());
|
||||
|
||||
std::string FullPath = getOutputPath(Path, Extension, InToplevel);
|
||||
|
||||
auto ParentDir = sys::path::parent_path(FullPath);
|
||||
if (auto E = sys::fs::create_directories(ParentDir))
|
||||
return errorCodeToError(E);
|
||||
|
||||
std::error_code E;
|
||||
raw_ostream *RawStream = new raw_fd_ostream(FullPath, E, sys::fs::F_RW);
|
||||
auto OS = CoveragePrinter::OwnedStream(RawStream);
|
||||
if (E)
|
||||
return errorCodeToError(E);
|
||||
return std::move(OS);
|
||||
}
|
||||
|
||||
std::unique_ptr<CoveragePrinter>
|
||||
CoveragePrinter::create(const CoverageViewOptions &Opts) {
|
||||
switch (Opts.Format) {
|
||||
case CoverageViewOptions::OutputFormat::Text:
|
||||
return llvm::make_unique<CoveragePrinterText>(Opts);
|
||||
}
|
||||
}
|
||||
|
||||
std::string SourceCoverageView::formatCount(uint64_t N) {
|
||||
std::string Number = utostr(N);
|
||||
int Len = Number.size();
|
||||
@ -36,49 +87,16 @@ 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.hasOutputDirectory())
|
||||
return OwnedStream(&outs());
|
||||
|
||||
return createFileInDirectory(Opts.ShowOutputDirectory,
|
||||
InToplevel ? "" : "coverage", Path, Extension);
|
||||
std::unique_ptr<SourceCoverageView>
|
||||
SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File,
|
||||
const CoverageViewOptions &Options,
|
||||
coverage::CoverageData &&CoverageInfo) {
|
||||
switch (Options.Format) {
|
||||
case CoverageViewOptions::OutputFormat::Text:
|
||||
return llvm::make_unique<SourceCoverageViewText>(SourceName, File, Options,
|
||||
std::move(CoverageInfo));
|
||||
}
|
||||
llvm_unreachable("Unknown coverage output format!");
|
||||
}
|
||||
|
||||
void SourceCoverageView::addExpansion(
|
||||
@ -93,18 +111,6 @@ void SourceCoverageView::addInstantiation(
|
||||
InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
|
||||
}
|
||||
|
||||
std::unique_ptr<SourceCoverageView>
|
||||
SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File,
|
||||
const CoverageViewOptions &Options,
|
||||
coverage::CoverageData &&CoverageInfo) {
|
||||
switch (Options.Format) {
|
||||
case CoverageViewOptions::OutputFormat::Text:
|
||||
return llvm::make_unique<SourceCoverageViewText>(SourceName, File, Options,
|
||||
std::move(CoverageInfo));
|
||||
}
|
||||
llvm_unreachable("Unknown coverage output format!");
|
||||
}
|
||||
|
||||
void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
|
||||
bool ShowSourceName, unsigned ViewDepth) {
|
||||
if (ShowSourceName)
|
||||
|
@ -97,11 +97,59 @@ struct LineCoverageStats {
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief A file manager that handles format-aware file creation.
|
||||
class CoveragePrinter {
|
||||
const CoverageViewOptions &Opts;
|
||||
|
||||
public:
|
||||
struct StreamDestructor {
|
||||
void operator()(raw_ostream *OS) const;
|
||||
};
|
||||
|
||||
using OwnedStream = std::unique_ptr<raw_ostream, StreamDestructor>;
|
||||
|
||||
protected:
|
||||
CoveragePrinter(const CoverageViewOptions &Opts) : Opts(Opts) {}
|
||||
|
||||
/// \brief Return `OutputDir/ToplevelDir/Path.Extension`.
|
||||
std::string getOutputPath(StringRef Path, StringRef Extension,
|
||||
bool InToplevel);
|
||||
|
||||
/// \brief If directory output is enabled, create a file in that directory
|
||||
/// at the path given by getOutputPath(). Otherwise, return stdout.
|
||||
Expected<OwnedStream> createOutputStream(StringRef Path, StringRef Extension,
|
||||
bool InToplevel);
|
||||
|
||||
/// \brief Return the sub-directory name for file coverage reports.
|
||||
static StringRef getCoverageDir() { return "coverage"; }
|
||||
|
||||
public:
|
||||
static std::unique_ptr<CoveragePrinter>
|
||||
create(const CoverageViewOptions &Opts);
|
||||
|
||||
virtual ~CoveragePrinter() {}
|
||||
|
||||
/// @name File Creation Interface
|
||||
/// @{
|
||||
|
||||
/// \brief Create a file to print a coverage view into.
|
||||
virtual Expected<OwnedStream> createViewFile(StringRef Path,
|
||||
bool InToplevel) = 0;
|
||||
|
||||
/// \brief Close a file which has been used to print a coverage view.
|
||||
virtual void closeViewFile(OwnedStream OS) = 0;
|
||||
|
||||
/// \brief Create an index which lists reports for the given source files.
|
||||
virtual Error createIndexFile(ArrayRef<StringRef> SourceFiles) = 0;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// \brief A code coverage view of a source file or function.
|
||||
///
|
||||
/// 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 both the File Creation and Rendering interfaces.
|
||||
/// renderer which implements the Rendering Interface.
|
||||
class SourceCoverageView {
|
||||
/// A function or file name.
|
||||
StringRef SourceName;
|
||||
@ -122,25 +170,6 @@ 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;
|
||||
@ -202,12 +231,6 @@ 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)
|
||||
|
@ -18,6 +18,28 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
Expected<CoveragePrinter::OwnedStream>
|
||||
CoveragePrinterText::createViewFile(StringRef Path, bool InToplevel) {
|
||||
return createOutputStream(Path, "txt", InToplevel);
|
||||
}
|
||||
|
||||
void CoveragePrinterText::closeViewFile(OwnedStream OS) {
|
||||
OS->operator<<('\n');
|
||||
}
|
||||
|
||||
Error CoveragePrinterText::createIndexFile(ArrayRef<StringRef> SourceFiles) {
|
||||
auto OSOrErr = createOutputStream("index", "txt", /*InToplevel=*/true);
|
||||
if (Error E = OSOrErr.takeError())
|
||||
return E;
|
||||
auto OS = std::move(OSOrErr.get());
|
||||
raw_ostream &OSRef = *OS.get();
|
||||
|
||||
for (StringRef SF : SourceFiles)
|
||||
OSRef << getOutputPath(SF, "txt", /*InToplevel=*/false) << '\n';
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
static const unsigned LineCoverageColumnWidth = 7;
|
||||
@ -37,15 +59,6 @@ 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";
|
||||
|
@ -18,15 +18,22 @@
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// \brief A coverage printer for text output.
|
||||
class CoveragePrinterText : public CoveragePrinter {
|
||||
public:
|
||||
Expected<OwnedStream> createViewFile(StringRef Path,
|
||||
bool InToplevel) override;
|
||||
|
||||
void closeViewFile(OwnedStream OS) override;
|
||||
|
||||
Error createIndexFile(ArrayRef<StringRef> SourceFiles) override;
|
||||
|
||||
CoveragePrinterText(const CoverageViewOptions &Opts)
|
||||
: CoveragePrinter(Opts) {}
|
||||
};
|
||||
|
||||
/// \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…
x
Reference in New Issue
Block a user