Skip to content

Commit

Permalink
[llvm-cov] Create directory structure when filtering using -name*= op…
Browse files Browse the repository at this point in the history
…tions

Before this change using any of the -name*= command line options with an output
directory would result in a single file (functions.txt/functions.html)
containing the coverage for those specific functions. Now you get the same
directory structure as when not using any -name*= options.

Differential Revision: https://reviews.llvm.org/D38280

llvm-svn: 314396
  • Loading branch information
SeanEveson committed Sep 28, 2017
1 parent 89d2be0 commit fa8ef35
Show file tree
Hide file tree
Showing 19 changed files with 215 additions and 64 deletions.
Binary file not shown.
32 changes: 32 additions & 0 deletions llvm/test/tools/llvm-cov/Inputs/dir-with-filtering.proftext
@@ -0,0 +1,32 @@
main
# Func Hash:
0
# Num Counters:
1
# Counter Values:
1

_Z2f1v
# Func Hash:
0
# Num Counters:
1
# Counter Values:
1

_Z2f2v
# Func Hash:
0
# Num Counters:
1
# Counter Values:
0

_Z2f3v
# Func Hash:
0
# Num Counters:
1
# Counter Values:
0

8 changes: 8 additions & 0 deletions llvm/test/tools/llvm-cov/Inputs/dir-with-filtering1.cpp
@@ -0,0 +1,8 @@
int f1() {
return 1;
}

int main() {
f1();
return 0;
}
8 changes: 8 additions & 0 deletions llvm/test/tools/llvm-cov/Inputs/dir-with-filtering2.cpp
@@ -0,0 +1,8 @@
int f2() {
return 2;
}

int f3() {
return 3;
}

69 changes: 69 additions & 0 deletions llvm/test/tools/llvm-cov/dir-with-filtering.test
@@ -0,0 +1,69 @@
RUN: llvm-profdata merge %S/Inputs/dir-with-filtering.proftext -o %t.profdata

// Test TEXT both files

RUN: llvm-cov show %S/Inputs/dir-with-filtering.covmapping -o %t.text -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main -name=f2

RUN: FileCheck -input-file=%t.text/index.txt %s -check-prefix=TEXT-INDEX
TEXT-INDEX: dir-with-filtering1.cpp 1 0 100.00% 1 0 100.00% 4 0 100.00%
TEXT-INDEX: dir-with-filtering2.cpp 1 1 0.00% 1 1 0.00% 3 3 0.00%

RUN: FileCheck -input-file=%t.text/coverage/tmp/dir-with-filtering1.cpp.txt %s -check-prefix=TEXT-FILE1
TEXT-FILE1: Coverage Report
TEXT-FILE1-NOT: _Z2f1v:
TEXT-FILE1: main:
TEXT-FILE1-NEXT: {{.*}}int main()
TEXT-FILE1-NOT: _Z2f1v:

RUN: FileCheck -input-file=%t.text/coverage/tmp/dir-with-filtering2.cpp.txt %s -check-prefix=TEXT-FILE2
TEXT-FILE2: Coverage Report
TEXT-FILE2-NOT: _Z2f3v:
TEXT-FILE2: _Z2f2v:
TEXT-FILE2-NEXT: {{.*}}int f2()
TEXT-FILE2-NOT: _Z2f3v:

// Test TEXT one file

RUN: llvm-cov show %S/Inputs/dir-with-filtering.covmapping -o %t.text_one_file -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main -name=f2 %S/Inputs/dir-with-filtering1.cpp

RUN: FileCheck -input-file=%t.text_one_file/index.txt %s -check-prefix=TEXT-INDEX-ONE-FILE
TEXT-INDEX-ONE-FILE: dir-with-filtering1.cpp 1 0 100.00% 1 0 100.00% 4 0 100.00%
TEXT-INDEX-ONE-FILE-NOT: dir-with-filtering2.cpp

RUN: FileCheck -input-file=%t.text_one_file/coverage/tmp/dir-with-filtering1.cpp.txt %s -check-prefix=TEXT-FILE1

// Test HTML both files

RUN: llvm-profdata merge %S/Inputs/dir-with-filtering.proftext -o %t.profdata
RUN: llvm-cov show %S/Inputs/dir-with-filtering.covmapping -format html -o %t.html -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main -name=f2

RUN: FileCheck -input-file=%t.html/index.html %s -check-prefix=HTML-INDEX
HTML-INDEX: <h2>Coverage Report</h2>
HTML-INDEX: dir-with-filtering1.cpp{{.*}}100.00% (1/1){{.*}}100.00% (4/4){{.*}}100.00% (1/1)
HTML-INDEX: dir-with-filtering2.cpp{{.*}}0.00% (0/1){{.*}}0.00% (0/3){{.*}}0.00% (0/1)

RUN: FileCheck -input-file=%t.html/coverage/tmp/dir-with-filtering1.cpp.html %s -check-prefix=HTML-FILE1
HTML-FILE1-NOT: <pre>f1</pre>
HTML-FILE1: <pre>main</pre>
HTML-FILE1-NOT: <pre>f1</pre>
HTML-FILE1: int main()
HTML-FILE1-NOT: <pre>f1</pre>

RUN: FileCheck -input-file=%t.html/coverage/tmp/dir-with-filtering2.cpp.html %s -check-prefix=HTML-FILE2
HTML-FILE2-NOT: <pre>f3</pre>
HTML-FILE2: <pre>_Z2f2v</pre>
HTML-FILE2-NOT: <pre>f3</pre>
HTML-FILE2: int f2()
HTML-FILE2-NOT: <pre>f3</pre>

// Test HTML one file

RUN: llvm-profdata merge %S/Inputs/dir-with-filtering.proftext -o %t.profdata
RUN: llvm-cov show %S/Inputs/dir-with-filtering.covmapping -format html -o %t.html_one_file -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs -name=main -name=f2 %S/Inputs/dir-with-filtering1.cpp

RUN: FileCheck -input-file=%t.html_one_file/index.html %s -check-prefix=HTML-INDEX-ONE-FILE
HTML-INDEX-ONE-FILE: <h2>Coverage Report</h2>
HTML-INDEX-ONE-FILE: dir-with-filtering1.cpp{{.*}}100.00% (1/1){{.*}}100.00% (4/4){{.*}}100.00% (1/1)
HTML-INDEX-ONE-FILE-NOT: dir-with-filtering2.cpp

RUN: FileCheck -input-file=%t.html_one_file/coverage/tmp/dir-with-filtering1.cpp.html %s -check-prefix=HTML-FILE1
2 changes: 1 addition & 1 deletion llvm/test/tools/llvm-cov/report.cpp
Expand Up @@ -40,7 +40,7 @@ int main() {

// Test that listing multiple functions in a function view works.
// RUN: llvm-cov show -o %t.dir %S/Inputs/report.covmapping -instr-profile=%S/Inputs/report.profdata -path-equivalence=,%S -name-regex=".*" %s
// RUN: FileCheck -check-prefix=FUNCTIONS -input-file %t.dir/functions.txt %s
// RUN: FileCheck -check-prefix=FUNCTIONS -input-file %t.dir/coverage/report.cpp.txt %s
// FUNCTIONS: _Z3foob
// FUNCTIONS: _Z3barv
// FUNCTIONS: _Z4func
8 changes: 4 additions & 4 deletions llvm/test/tools/llvm-cov/showLineExecutionCounts.cpp
Expand Up @@ -31,19 +31,19 @@ int main() { // TEXT: [[@LINE]]| 161|int main(

// Test -output-dir.
// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -o %t.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %s
// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S -name=main %s
// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.filtered.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S -name=main %s
// RUN: FileCheck -check-prefixes=TEXT,WHOLE-FILE -input-file %t.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %s
// RUN: FileCheck -check-prefixes=TEXT,FILTER -input-file %t.dir/functions.txt %s
// RUN: FileCheck -check-prefixes=TEXT,FILTER -input-file %t.filtered.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %s
//
// RUN: llvm-cov export %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -name=main 2>/dev/null > %t.export.json
// RUN: FileCheck -input-file %t.export.json %S/Inputs/lineExecutionCounts.json
// RUN: cat %t.export.json | %python -c "import json, sys; json.loads(sys.stdin.read())"
//
// Test html output.
// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S %s
// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S -name=main %s
// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -format html -o %t.html.filtered.dir -instr-profile %t.profdata -path-equivalence=/tmp,%S -name=main %s
// RUN: FileCheck -check-prefixes=HTML,HTML-WHOLE-FILE -input-file %t.html.dir/coverage/tmp/showLineExecutionCounts.cpp.html %s
// RUN: FileCheck -check-prefixes=HTML,HTML-FILTER -input-file %t.html.dir/functions.html %s
// RUN: FileCheck -check-prefixes=HTML,HTML-FILTER -input-file %t.html.filtered.dir/coverage/tmp/showLineExecutionCounts.cpp.html %s
//
// HTML-WHOLE-FILE: <td class='line-number'><a name='L[[@LINE-44]]' href='#L[[@LINE-44]]'><pre>[[@LINE-44]]</pre></a></td><td class='uncovered-line'></td><td class='code'><pre>// before
// HTML-FILTER-NOT: <td class='line-number'><a name='L[[@LINE-45]]' href='#L[[@LINE-45]]'><pre>[[@LINE-45]]</pre></a></td><td class='uncovered-line'></td><td class='code'><pre>// before
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/tools/llvm-cov/showProjectSummary.cpp
Expand Up @@ -24,5 +24,5 @@ int main(int argc, char ** argv) {
// RUN: llvm-cov show %S/Inputs/showProjectSummary.covmapping -format=html -o %t.dir -instr-profile %t.profdata -project-title "Test Suite" -path-equivalence=/tmp,%S %s
// RUN: FileCheck -check-prefixes=HTML-TITLE,HTML,HTML-FILE,HTML-HEADER -input-file %t.dir/coverage/tmp/showProjectSummary.cpp.html %S/Inputs/showProjectSummary.test
// RUN: FileCheck -check-prefixes=HTML-TITLE,HTML,HTML-FOOTER -input-file %t.dir/index.html %S/Inputs/showProjectSummary.test
// RUN: llvm-cov show %S/Inputs/showProjectSummary.covmapping -format=html -o %t.dir -instr-profile %t.profdata -project-title "Test Suite" -path-equivalence=/tmp,%S -name=main %s
// RUN: FileCheck -check-prefixes=HTML-FUNCTION,HTML-HEADER -input-file %t.dir/functions.html %S/Inputs/showProjectSummary.test
// RUN: llvm-cov show %S/Inputs/showProjectSummary.covmapping -format=html -o %t.filtered.dir -instr-profile %t.profdata -project-title "Test Suite" -path-equivalence=/tmp,%S -name=main %s
// RUN: FileCheck -check-prefixes=HTML-TITLE,HTML,HTML-FOOTER -input-file %t.filtered.dir/index.html %S/Inputs/showProjectSummary.test
4 changes: 2 additions & 2 deletions llvm/test/tools/llvm-cov/showTemplateInstantiations.cpp
Expand Up @@ -41,9 +41,9 @@ int main() { // ALL: [[@LINE]]| 1|int main() {

// Test html output.
// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -path-equivalence=/tmp,%S %s -format html -o %t.html.dir
// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -path-equivalence=/tmp,%S -name=_Z4funcIbEiT_ %s -format html -o %t.html.dir
// RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -path-equivalence=/tmp,%S -name=_Z4funcIbEiT_ %s -format html -o %t.html.filtered.dir
// RUN: FileCheck -check-prefixes=HTML-SHARED,HTML-ALL -input-file=%t.html.dir/coverage/tmp/showTemplateInstantiations.cpp.html %s
// RUN: FileCheck -check-prefixes=HTML-SHARED,HTML-FILTER -input-file=%t.html.dir/functions.html %s
// RUN: FileCheck -check-prefixes=HTML-SHARED,HTML-FILTER -input-file=%t.html.filtered.dir/coverage/tmp/showTemplateInstantiations.cpp.html %s

// HTML-ALL: <td class='line-number'><a name='L[[@LINE-44]]' href='#L[[@LINE-44]]'><pre>[[@LINE-44]]</pre></a></td><td class='uncovered-line'></td><td class='code'><pre>// before
// HTML-FILTER-NOT: <td class='line-number'><a name='L[[@LINE-45]]' href='#L[[@LINE-45]]'><pre>[[@LINE-45]]</pre></a></td><td class='uncovered-line'></td><td class='code'><pre>// before
Expand Down
7 changes: 5 additions & 2 deletions llvm/test/tools/llvm-cov/style.test
@@ -1,14 +1,17 @@
RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -path-equivalence=/tmp,%S %S/showTemplateInstantiations.cpp -format html -o %t.dir

RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -path-equivalence=/tmp,%S -name=_Z4funcIbEiT_ %S/showTemplateInstantiations.cpp -format html -o %t.dir
RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -path-equivalence=/tmp,%S -name=_Z4funcIbEiT_ %S/showTemplateInstantiations.cpp -format html -o %t.filtered.dir

RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -path-equivalence=/tmp,%S %S/showTemplateInstantiations.cpp -format html | FileCheck %s -check-prefix=NODIR

RUN: FileCheck %s -input-file=%t.dir/style.css -check-prefix=STYLE
RUN: FileCheck %s -input-file=%t.dir/functions.html -check-prefix=TOPLEVEL
RUN: FileCheck %s -input-file=%t.dir/index.html -check-prefix=TOPLEVEL
RUN: FileCheck %s -input-file=%t.dir/coverage/tmp/showTemplateInstantiations.cpp.html -check-prefix=FILEVIEW

RUN: FileCheck %s -input-file=%t.filtered.dir/style.css -check-prefix=STYLE
RUN: FileCheck %s -input-file=%t.filtered.dir/index.html -check-prefix=TOPLEVEL
RUN: FileCheck %s -input-file=%t.filtered.dir/coverage/tmp/showTemplateInstantiations.cpp.html -check-prefix=FILEVIEW

STYLE-DAG: .red
STYLE-DAG: .cyan
STYLE-DAG: .source-name-title
Expand Down
77 changes: 46 additions & 31 deletions llvm/tools/llvm-cov/CodeCoverage.cpp
Expand Up @@ -35,7 +35,9 @@
#include "llvm/Support/Threading.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/ToolOutputFile.h"

#include <functional>
#include <map>
#include <system_error>

using namespace llvm;
Expand Down Expand Up @@ -526,7 +528,8 @@ void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
auto OS = std::move(OSOrErr.get());

View->print(*OS.get(), /*Wholefile=*/true,
/*ShowSourceName=*/ShowFilenames);
/*ShowSourceName=*/ShowFilenames,
/*ShowTitle=*/ViewOpts.hasOutputDirectory());
Printer->closeViewFile(std::move(OS));
}

Expand Down Expand Up @@ -845,29 +848,54 @@ int CodeCoverageTool::show(int argc, const char **argv,

auto Printer = CoveragePrinter::create(ViewOpts);

if (!Filters.empty()) {
auto OSOrErr = Printer->createViewFile("functions", /*InToplevel=*/true);
if (Error E = OSOrErr.takeError()) {
error("Could not create view file!", toString(std::move(E)));
if (SourceFiles.empty())
// Get the source files from the function coverage mapping.
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, *Coverage, Filters)) {
error("Could not create index file!", toString(std::move(E)));
return 1;
}
auto OS = std::move(OSOrErr.get());

// Show functions.
for (const auto &Function : Coverage->getCoveredFunctions()) {
if (!Filters.matches(*Coverage.get(), Function))
continue;
}

auto mainView = createFunctionView(Function, *Coverage);
if (!mainView) {
warning("Could not read coverage for '" + Function.Name + "'.");
continue;
if (!Filters.empty()) {
// Build the map of filenames to functions.
std::map<llvm::StringRef, std::vector<const FunctionRecord *>>
FilenameFunctionMap;
for (const auto &SourceFile : SourceFiles)
for (const auto &Function : Coverage->getCoveredFunctions(SourceFile))
if (Filters.matches(*Coverage.get(), Function))
FilenameFunctionMap[SourceFile].push_back(&Function);

// Only print filter matching functions for each file.
for (const auto &FileFunc : FilenameFunctionMap) {
StringRef File = FileFunc.first;
const auto &Functions = FileFunc.second;

auto OSOrErr = Printer->createViewFile(File, /*InToplevel=*/false);
if (Error E = OSOrErr.takeError()) {
error("Could not create view file!", toString(std::move(E)));
return 1;
}
auto OS = std::move(OSOrErr.get());

bool ShowTitle = true;
for (const auto *Function : Functions) {
auto FunctionView = createFunctionView(*Function, *Coverage);
if (!FunctionView) {
warning("Could not read coverage for '" + Function->Name + "'.");
continue;
}
FunctionView->print(*OS.get(), /*WholeFile=*/false,
/*ShowSourceName=*/true, ShowTitle);
ShowTitle = false;
}

mainView->print(*OS.get(), /*WholeFile=*/false, /*ShowSourceName=*/true);
Printer->closeViewFile(std::move(OS));
}

Printer->closeViewFile(std::move(OS));
return 0;
}

Expand All @@ -876,19 +904,6 @@ int CodeCoverageTool::show(int argc, const char **argv,
(SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() ||
(ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML);

if (SourceFiles.empty())
// Get the source files from the function coverage mapping.
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, *Coverage)) {
error("Could not create index file!", toString(std::move(E)));
return 1;
}
}

// If NumThreads is not specified, auto-detect a good default.
if (NumThreads == 0)
NumThreads =
Expand Down
15 changes: 11 additions & 4 deletions llvm/tools/llvm-cov/CoverageReport.cpp
Expand Up @@ -322,7 +322,8 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,

std::vector<FileCoverageSummary> CoverageReport::prepareFileReports(
const coverage::CoverageMapping &Coverage, FileCoverageSummary &Totals,
ArrayRef<std::string> Files, const CoverageViewOptions &Options) {
ArrayRef<std::string> Files, const CoverageViewOptions &Options,
const CoverageFilter &Filters) {
std::vector<FileCoverageSummary> FileReports;
unsigned LCP = getRedundantPrefixLen(Files);

Expand All @@ -332,11 +333,15 @@ std::vector<FileCoverageSummary> CoverageReport::prepareFileReports(
for (const auto &Group : Coverage.getInstantiationGroups(Filename)) {
std::vector<FunctionCoverageSummary> InstantiationSummaries;
for (const coverage::FunctionRecord *F : Group.getInstantiations()) {
if (!Filters.matches(Coverage, *F))
continue;
auto InstantiationSummary = FunctionCoverageSummary::get(Coverage, *F);
Summary.addInstantiation(InstantiationSummary);
Totals.addInstantiation(InstantiationSummary);
InstantiationSummaries.push_back(InstantiationSummary);
}
if (InstantiationSummaries.empty())
continue;

auto GroupSummary =
FunctionCoverageSummary::get(Group, InstantiationSummaries);
Expand All @@ -359,13 +364,15 @@ void CoverageReport::renderFileReports(raw_ostream &OS) const {
std::vector<std::string> UniqueSourceFiles;
for (StringRef SF : Coverage.getUniqueSourceFiles())
UniqueSourceFiles.emplace_back(SF.str());
renderFileReports(OS, UniqueSourceFiles);
renderFileReports(OS, UniqueSourceFiles, CoverageFiltersMatchAll());
}

void CoverageReport::renderFileReports(raw_ostream &OS,
ArrayRef<std::string> Files) const {
ArrayRef<std::string> Files,
const CoverageFilter &Filters) const {
FileCoverageSummary Totals("TOTAL");
auto FileReports = prepareFileReports(Coverage, Totals, Files, Options);
auto FileReports =
prepareFileReports(Coverage, Totals, Files, Options, Filters);

std::vector<StringRef> Filenames;
for (const FileCoverageSummary &FCS : FileReports)
Expand Down
10 changes: 7 additions & 3 deletions llvm/tools/llvm-cov/CoverageReport.h
Expand Up @@ -14,6 +14,7 @@
#ifndef LLVM_COV_COVERAGEREPORT_H
#define LLVM_COV_COVERAGEREPORT_H

#include "CoverageFilters.h"
#include "CoverageSummaryInfo.h"
#include "CoverageViewOptions.h"

Expand All @@ -40,13 +41,16 @@ class CoverageReport {
static std::vector<FileCoverageSummary>
prepareFileReports(const coverage::CoverageMapping &Coverage,
FileCoverageSummary &Totals, ArrayRef<std::string> Files,
const CoverageViewOptions &Options);
const CoverageViewOptions &Options,
const CoverageFilter &Filters = CoverageFiltersMatchAll());

/// Render file reports for every unique file in the coverage mapping.
void renderFileReports(raw_ostream &OS) const;

/// Render file reports for the files specified in \p Files.
void renderFileReports(raw_ostream &OS, ArrayRef<std::string> Files) const;
/// Render file reports for the files specified in \p Files and the functions
/// in \p Filters.
void renderFileReports(raw_ostream &OS, ArrayRef<std::string> Files,
const CoverageFilter &Filters) const;
};

} // end namespace llvm
Expand Down
5 changes: 3 additions & 2 deletions llvm/tools/llvm-cov/SourceCoverageView.cpp
Expand Up @@ -164,8 +164,9 @@ void SourceCoverageView::addInstantiation(
}

void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
bool ShowSourceName, unsigned ViewDepth) {
if (WholeFile && getOptions().hasOutputDirectory())
bool ShowSourceName, bool ShowTitle,
unsigned ViewDepth) {
if (ShowTitle)
renderTitle(OS, "Coverage Report");

renderViewHeader(OS);
Expand Down

0 comments on commit fa8ef35

Please sign in to comment.