summaryrefslogtreecommitdiff
path: root/tools/llvm-cov
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-16 16:01:22 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-16 16:01:22 +0000
commit71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch)
tree5343938942df402b49ec7300a1c25a2d4ccd5821 /tools/llvm-cov
parent31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff)
Notes
Diffstat (limited to 'tools/llvm-cov')
-rw-r--r--tools/llvm-cov/CodeCoverage.cpp42
-rw-r--r--tools/llvm-cov/CoverageReport.cpp69
-rw-r--r--tools/llvm-cov/CoverageReport.h6
-rw-r--r--tools/llvm-cov/CoverageSummaryInfo.h13
-rw-r--r--tools/llvm-cov/TestingSupport.cpp7
-rw-r--r--tools/llvm-cov/gcov.cpp2
6 files changed, 97 insertions, 42 deletions
diff --git a/tools/llvm-cov/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp
index 0a9807ab00334..6179c760d5b20 100644
--- a/tools/llvm-cov/CodeCoverage.cpp
+++ b/tools/llvm-cov/CodeCoverage.cpp
@@ -15,6 +15,7 @@
#include "CoverageFilters.h"
#include "CoverageReport.h"
+#include "CoverageSummaryInfo.h"
#include "CoverageViewOptions.h"
#include "RenderingSupport.h"
#include "SourceCoverageView.h"
@@ -98,9 +99,6 @@ private:
/// \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;
-
/// \brief Write out a source file view to the filesystem.
void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage,
CoveragePrinter *Printer, bool ShowFilenames);
@@ -136,10 +134,10 @@ private:
/// The architecture the coverage mapping data targets.
std::string CoverageArch;
- /// A cache for demangled symbol names.
- StringMap<std::string> DemangledNames;
+ /// A cache for demangled symbols.
+ DemangleCache DC;
- /// Errors and warnings which have not been printed.
+ /// A lock which guards printing to stderr.
std::mutex ErrsLock;
/// A container for input source file buffers.
@@ -267,7 +265,7 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
return nullptr;
auto Expansions = FunctionCoverage.getExpansions();
- auto View = SourceCoverageView::create(getSymbolForHumans(Function.Name),
+ auto View = SourceCoverageView::create(DC.demangle(Function.Name),
SourceBuffer.get(), ViewOpts,
std::move(FunctionCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
@@ -293,7 +291,7 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
for (const auto *Function : Coverage.getInstantiations(SourceFile)) {
std::unique_ptr<SourceCoverageView> SubView{nullptr};
- StringRef Funcname = getSymbolForHumans(Function->Name);
+ StringRef Funcname = DC.demangle(Function->Name);
if (Function->ExecutionCount > 0) {
auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
@@ -453,14 +451,9 @@ void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
// Cache the demangled names.
unsigned I = 0;
for (const auto &Function : Coverage.getCoveredFunctions())
- DemangledNames[Function.Name] = Symbols[I++];
-}
-
-StringRef CodeCoverageTool::getSymbolForHumans(StringRef Sym) const {
- const auto DemangledName = DemangledNames.find(Sym);
- if (DemangledName == DemangledNames.end())
- return Sym;
- return DemangledName->getValue();
+ // On Windows, lines in the demangler's output file end with "\r\n".
+ // Splitting by '\n' keeps '\r's, so cut them now.
+ DC.DemangledNames[Function.Name] = Symbols[I++].rtrim();
}
void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
@@ -817,22 +810,28 @@ int CodeCoverageTool::show(int argc, const char **argv,
int CodeCoverageTool::report(int argc, const char **argv,
CommandLineParserType commandLineParser) {
+ cl::opt<bool> ShowFunctionSummaries(
+ "show-functions", cl::Optional, cl::init(false),
+ cl::desc("Show coverage summaries for each function"));
+
auto Err = commandLineParser(argc, argv);
if (Err)
return Err;
- if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML)
+ if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
error("HTML output for summary reports is not yet supported.");
+ return 1;
+ }
auto Coverage = load();
if (!Coverage)
return 1;
CoverageReport Report(ViewOpts, *Coverage.get());
- if (SourceFiles.empty())
+ if (!ShowFunctionSummaries)
Report.renderFileReports(llvm::outs());
else
- Report.renderFunctionReports(SourceFiles, llvm::outs());
+ Report.renderFunctionReports(SourceFiles, DC, llvm::outs());
return 0;
}
@@ -843,6 +842,11 @@ int CodeCoverageTool::export_(int argc, const char **argv,
if (Err)
return Err;
+ if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) {
+ error("Coverage data can only be exported as textual JSON.");
+ return 1;
+ }
+
auto Coverage = load();
if (!Coverage) {
error("Could not load coverage information");
diff --git a/tools/llvm-cov/CoverageReport.cpp b/tools/llvm-cov/CoverageReport.cpp
index e88cb186acd66..c68bb9048df1b 100644
--- a/tools/llvm-cov/CoverageReport.cpp
+++ b/tools/llvm-cov/CoverageReport.cpp
@@ -118,19 +118,51 @@ raw_ostream::Colors determineCoveragePercentageColor(const T &Info) {
: raw_ostream::RED;
}
-/// \brief Determine the length of the longest common prefix of the strings in
-/// \p Strings.
-unsigned getLongestCommonPrefixLen(ArrayRef<std::string> Strings) {
- unsigned LCP = Strings[0].size();
- for (unsigned I = 1, E = Strings.size(); LCP > 0 && I < E; ++I) {
- unsigned Cursor;
- StringRef S = Strings[I];
- for (Cursor = 0; Cursor < LCP && Cursor < S.size(); ++Cursor)
- if (Strings[0][Cursor] != S[Cursor])
+/// \brief Get the number of redundant path components in each path in \p Paths.
+unsigned getNumRedundantPathComponents(ArrayRef<std::string> Paths) {
+ // To start, set the number of redundant path components to the maximum
+ // possible value.
+ SmallVector<StringRef, 8> FirstPathComponents{sys::path::begin(Paths[0]),
+ sys::path::end(Paths[0])};
+ unsigned NumRedundant = FirstPathComponents.size();
+
+ for (unsigned I = 1, E = Paths.size(); NumRedundant > 0 && I < E; ++I) {
+ StringRef Path = Paths[I];
+ for (const auto &Component :
+ enumerate(make_range(sys::path::begin(Path), sys::path::end(Path)))) {
+ // Do not increase the number of redundant components: that would remove
+ // useful parts of already-visited paths.
+ if (Component.index() >= NumRedundant)
break;
- LCP = std::min(LCP, Cursor);
+
+ // Lower the number of redundant components when there's a mismatch
+ // between the first path, and the path under consideration.
+ if (FirstPathComponents[Component.index()] != Component.value()) {
+ NumRedundant = Component.index();
+ break;
+ }
+ }
+ }
+
+ return NumRedundant;
+}
+
+/// \brief Determine the length of the longest redundant prefix of the paths in
+/// \p Paths.
+unsigned getRedundantPrefixLen(ArrayRef<std::string> Paths) {
+ // If there's at most one path, no path components are redundant.
+ if (Paths.size() <= 1)
+ return 0;
+
+ unsigned PrefixLen = 0;
+ unsigned NumRedundant = getNumRedundantPathComponents(Paths);
+ auto Component = sys::path::begin(Paths[0]);
+ for (unsigned I = 0; I < NumRedundant; ++I) {
+ auto LastComponent = Component;
+ ++Component;
+ PrefixLen += Component - LastComponent;
}
- return LCP;
+ return PrefixLen;
}
} // end anonymous namespace
@@ -200,12 +232,14 @@ void CoverageReport::render(const FileCoverageSummary &File,
}
void CoverageReport::render(const FunctionCoverageSummary &Function,
+ const DemangleCache &DC,
raw_ostream &OS) const {
auto FuncCoverageColor =
determineCoveragePercentageColor(Function.RegionCoverage);
auto LineCoverageColor =
determineCoveragePercentageColor(Function.LineCoverage);
- OS << column(Function.Name, FunctionReportColumns[0], Column::RightTrim)
+ OS << column(DC.demangle(Function.Name), FunctionReportColumns[0],
+ Column::RightTrim)
<< format("%*u", FunctionReportColumns[1],
(unsigned)Function.RegionCoverage.NumRegions);
Options.colored_ostream(OS, FuncCoverageColor)
@@ -230,6 +264,7 @@ void CoverageReport::render(const FunctionCoverageSummary &Function,
}
void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
+ const DemangleCache &DC,
raw_ostream &OS) {
bool isFirst = true;
for (StringRef Filename : Files) {
@@ -242,7 +277,7 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
std::vector<StringRef> Funcnames;
for (const auto &F : Functions)
- Funcnames.emplace_back(F.Name);
+ Funcnames.emplace_back(DC.demangle(F.Name));
adjustColumnWidths({}, Funcnames);
OS << "File '" << Filename << "':\n";
@@ -262,12 +297,12 @@ void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
++Totals.ExecutionCount;
Totals.RegionCoverage += Function.RegionCoverage;
Totals.LineCoverage += Function.LineCoverage;
- render(Function, OS);
+ render(Function, DC, OS);
}
if (Totals.ExecutionCount) {
renderDivider(FunctionReportColumns, OS);
OS << "\n";
- render(Totals, OS);
+ render(Totals, DC, OS);
}
}
}
@@ -277,9 +312,7 @@ CoverageReport::prepareFileReports(const coverage::CoverageMapping &Coverage,
FileCoverageSummary &Totals,
ArrayRef<std::string> Files) {
std::vector<FileCoverageSummary> FileReports;
- unsigned LCP = 0;
- if (Files.size() > 1)
- LCP = getLongestCommonPrefixLen(Files);
+ unsigned LCP = getRedundantPrefixLen(Files);
for (StringRef Filename : Files) {
FileCoverageSummary Summary(Filename.drop_front(LCP));
diff --git a/tools/llvm-cov/CoverageReport.h b/tools/llvm-cov/CoverageReport.h
index 7a416497e258e..071be2e21594c 100644
--- a/tools/llvm-cov/CoverageReport.h
+++ b/tools/llvm-cov/CoverageReport.h
@@ -25,14 +25,16 @@ class CoverageReport {
const coverage::CoverageMapping &Coverage;
void render(const FileCoverageSummary &File, raw_ostream &OS) const;
- void render(const FunctionCoverageSummary &Function, raw_ostream &OS) const;
+ void render(const FunctionCoverageSummary &Function, const DemangleCache &DC,
+ raw_ostream &OS) const;
public:
CoverageReport(const CoverageViewOptions &Options,
const coverage::CoverageMapping &Coverage)
: Options(Options), Coverage(Coverage) {}
- void renderFunctionReports(ArrayRef<std::string> Files, raw_ostream &OS);
+ void renderFunctionReports(ArrayRef<std::string> Files,
+ const DemangleCache &DC, raw_ostream &OS);
/// Prepare file reports for the files specified in \p Files.
static std::vector<FileCoverageSummary>
diff --git a/tools/llvm-cov/CoverageSummaryInfo.h b/tools/llvm-cov/CoverageSummaryInfo.h
index c04a4d42ccd74..680fc3757686f 100644
--- a/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/tools/llvm-cov/CoverageSummaryInfo.h
@@ -160,6 +160,19 @@ struct FileCoverageSummary {
}
};
+/// \brief A cache for demangled symbols.
+struct DemangleCache {
+ StringMap<std::string> DemangledNames;
+
+ /// \brief Demangle \p Sym if possible. Otherwise, just return \p Sym.
+ StringRef demangle(StringRef Sym) const {
+ const auto DemangledName = DemangledNames.find(Sym);
+ if (DemangledName == DemangledNames.end())
+ return Sym;
+ return DemangledName->getValue();
+ }
+};
+
} // namespace llvm
#endif // LLVM_COV_COVERAGESUMMARYINFO_H
diff --git a/tools/llvm-cov/TestingSupport.cpp b/tools/llvm-cov/TestingSupport.cpp
index 72768f4fd583f..4713d75f17dd4 100644
--- a/tools/llvm-cov/TestingSupport.cpp
+++ b/tools/llvm-cov/TestingSupport.cpp
@@ -48,13 +48,16 @@ int convertForTestingMain(int argc, const char *argv[]) {
// Look for the sections that we are interested in.
int FoundSectionCount = 0;
SectionRef ProfileNames, CoverageMapping;
+ auto ObjFormat = OF->getTripleObjectFormat();
for (const auto &Section : OF->sections()) {
StringRef Name;
if (Section.getName(Name))
return 1;
- if (Name == llvm::getInstrProfNameSectionName(false)) {
+ if (Name == llvm::getInstrProfSectionName(IPSK_name, ObjFormat,
+ /*AddSegmentInfo=*/false)) {
ProfileNames = Section;
- } else if (Name == llvm::getInstrProfCoverageSectionName(false)) {
+ } else if (Name == llvm::getInstrProfSectionName(
+ IPSK_covmap, ObjFormat, /*AddSegmentInfo=*/false)) {
CoverageMapping = Section;
} else
continue;
diff --git a/tools/llvm-cov/gcov.cpp b/tools/llvm-cov/gcov.cpp
index 4652fed2a384e..4df7f015fd188 100644
--- a/tools/llvm-cov/gcov.cpp
+++ b/tools/llvm-cov/gcov.cpp
@@ -74,7 +74,7 @@ static void reportCoverage(StringRef SourceFile, StringRef ObjectDir,
}
if (DumpGCOV)
- GF.dump();
+ GF.print(errs());
FileInfo FI(Options);
GF.collectLineCounts(FI);