Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 1 | //===- CoverageReport.cpp - Code coverage report -------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This class implements rendering of a code coverage report. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "CoverageReport.h" |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 15 | #include "RenderingSupport.h" |
Vedant Kumar | 016111f | 2016-09-19 00:38:23 +0000 | [diff] [blame] | 16 | #include "llvm/ADT/DenseMap.h" |
Chandler Carruth | d990388 | 2015-01-14 11:23:27 +0000 | [diff] [blame] | 17 | #include "llvm/Support/Format.h" |
Vedant Kumar | d938dfb | 2016-09-09 17:37:11 +0000 | [diff] [blame] | 18 | #include "llvm/Support/Path.h" |
Max Moroz | cc254ba | 2018-01-05 16:15:07 +0000 | [diff] [blame] | 19 | #include "llvm/Support/ThreadPool.h" |
| 20 | #include "llvm/Support/Threading.h" |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 21 | #include <numeric> |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 22 | |
| 23 | using namespace llvm; |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 24 | |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 25 | namespace { |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 26 | |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 27 | /// \brief Helper struct which prints trimmed and aligned columns. |
| 28 | struct Column { |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 29 | enum TrimKind { NoTrim, WidthTrim, RightTrim }; |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 30 | |
| 31 | enum AlignmentKind { LeftAlignment, RightAlignment }; |
| 32 | |
| 33 | StringRef Str; |
| 34 | unsigned Width; |
| 35 | TrimKind Trim; |
| 36 | AlignmentKind Alignment; |
| 37 | |
| 38 | Column(StringRef Str, unsigned Width) |
Vedant Kumar | c3c39e7 | 2015-09-14 23:26:36 +0000 | [diff] [blame] | 39 | : Str(Str), Width(Width), Trim(WidthTrim), Alignment(LeftAlignment) {} |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 40 | |
| 41 | Column &set(TrimKind Value) { |
| 42 | Trim = Value; |
| 43 | return *this; |
| 44 | } |
| 45 | |
| 46 | Column &set(AlignmentKind Value) { |
| 47 | Alignment = Value; |
| 48 | return *this; |
| 49 | } |
| 50 | |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 51 | void render(raw_ostream &OS) const { |
| 52 | if (Str.size() <= Width) { |
| 53 | if (Alignment == RightAlignment) { |
| 54 | OS.indent(Width - Str.size()); |
| 55 | OS << Str; |
| 56 | return; |
| 57 | } |
| 58 | OS << Str; |
| 59 | OS.indent(Width - Str.size()); |
| 60 | return; |
| 61 | } |
| 62 | |
| 63 | switch (Trim) { |
| 64 | case NoTrim: |
| 65 | OS << Str; |
| 66 | break; |
| 67 | case WidthTrim: |
| 68 | OS << Str.substr(0, Width); |
| 69 | break; |
| 70 | case RightTrim: |
| 71 | OS << Str.substr(0, Width - 3) << "..."; |
| 72 | break; |
| 73 | } |
| 74 | } |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 75 | }; |
Vedant Kumar | c3c39e7 | 2015-09-14 23:26:36 +0000 | [diff] [blame] | 76 | |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 77 | raw_ostream &operator<<(raw_ostream &OS, const Column &Value) { |
| 78 | Value.render(OS); |
| 79 | return OS; |
| 80 | } |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 81 | |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 82 | Column column(StringRef Str, unsigned Width) { return Column(Str, Width); } |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 83 | |
| 84 | template <typename T> |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 85 | Column column(StringRef Str, unsigned Width, const T &Value) { |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 86 | return Column(Str, Width).set(Value); |
| 87 | } |
| 88 | |
Ying Yi | e59ee43 | 2016-07-22 12:46:13 +0000 | [diff] [blame] | 89 | // Specify the default column widths. |
Vedant Kumar | 016111f | 2016-09-19 00:38:23 +0000 | [diff] [blame] | 90 | size_t FileReportColumns[] = {25, 12, 18, 10, 12, 18, 10, |
| 91 | 16, 16, 10, 12, 18, 10}; |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 92 | size_t FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8}; |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 93 | |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 94 | /// \brief Adjust column widths to fit long file paths and function names. |
Vedant Kumar | dab0ec1 | 2016-09-19 00:38:16 +0000 | [diff] [blame] | 95 | void adjustColumnWidths(ArrayRef<StringRef> Files, |
| 96 | ArrayRef<StringRef> Functions) { |
| 97 | for (StringRef Filename : Files) |
Vedant Kumar | aaead33 | 2015-10-21 16:03:32 +0000 | [diff] [blame] | 98 | FileReportColumns[0] = std::max(FileReportColumns[0], Filename.size()); |
Vedant Kumar | dab0ec1 | 2016-09-19 00:38:16 +0000 | [diff] [blame] | 99 | for (StringRef Funcname : Functions) |
| 100 | FunctionReportColumns[0] = |
| 101 | std::max(FunctionReportColumns[0], Funcname.size()); |
Vedant Kumar | aaead33 | 2015-10-21 16:03:32 +0000 | [diff] [blame] | 102 | } |
| 103 | |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 104 | /// \brief Prints a horizontal divider long enough to cover the given column |
| 105 | /// widths. |
| 106 | void renderDivider(ArrayRef<size_t> ColumnWidths, raw_ostream &OS) { |
| 107 | size_t Length = std::accumulate(ColumnWidths.begin(), ColumnWidths.end(), 0); |
| 108 | for (size_t I = 0; I < Length; ++I) |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 109 | OS << '-'; |
| 110 | } |
| 111 | |
Vedant Kumar | 5053b11 | 2016-09-06 22:46:00 +0000 | [diff] [blame] | 112 | /// \brief Return the color which correponds to the coverage percentage of a |
| 113 | /// certain metric. |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 114 | template <typename T> |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 115 | raw_ostream::Colors determineCoveragePercentageColor(const T &Info) { |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 116 | if (Info.isFullyCovered()) |
| 117 | return raw_ostream::GREEN; |
| 118 | return Info.getPercentCovered() >= 80.0 ? raw_ostream::YELLOW |
| 119 | : raw_ostream::RED; |
| 120 | } |
| 121 | |
Vedant Kumar | 1181328 | 2017-02-23 22:20:32 +0000 | [diff] [blame] | 122 | /// \brief Get the number of redundant path components in each path in \p Paths. |
| 123 | unsigned getNumRedundantPathComponents(ArrayRef<std::string> Paths) { |
| 124 | // To start, set the number of redundant path components to the maximum |
| 125 | // possible value. |
| 126 | SmallVector<StringRef, 8> FirstPathComponents{sys::path::begin(Paths[0]), |
| 127 | sys::path::end(Paths[0])}; |
| 128 | unsigned NumRedundant = FirstPathComponents.size(); |
| 129 | |
| 130 | for (unsigned I = 1, E = Paths.size(); NumRedundant > 0 && I < E; ++I) { |
| 131 | StringRef Path = Paths[I]; |
| 132 | for (const auto &Component : |
| 133 | enumerate(make_range(sys::path::begin(Path), sys::path::end(Path)))) { |
| 134 | // Do not increase the number of redundant components: that would remove |
| 135 | // useful parts of already-visited paths. |
Zachary Turner | 368c3fa | 2017-03-13 16:32:08 +0000 | [diff] [blame] | 136 | if (Component.index() >= NumRedundant) |
Vedant Kumar | 5cd496b | 2016-09-26 17:57:13 +0000 | [diff] [blame] | 137 | break; |
Vedant Kumar | 1181328 | 2017-02-23 22:20:32 +0000 | [diff] [blame] | 138 | |
| 139 | // Lower the number of redundant components when there's a mismatch |
| 140 | // between the first path, and the path under consideration. |
Zachary Turner | 368c3fa | 2017-03-13 16:32:08 +0000 | [diff] [blame] | 141 | if (FirstPathComponents[Component.index()] != Component.value()) { |
| 142 | NumRedundant = Component.index(); |
Vedant Kumar | 1181328 | 2017-02-23 22:20:32 +0000 | [diff] [blame] | 143 | break; |
| 144 | } |
| 145 | } |
Vedant Kumar | fa75437 | 2016-09-08 00:56:43 +0000 | [diff] [blame] | 146 | } |
Vedant Kumar | 1181328 | 2017-02-23 22:20:32 +0000 | [diff] [blame] | 147 | |
| 148 | return NumRedundant; |
| 149 | } |
| 150 | |
| 151 | /// \brief Determine the length of the longest redundant prefix of the paths in |
| 152 | /// \p Paths. |
| 153 | unsigned getRedundantPrefixLen(ArrayRef<std::string> Paths) { |
| 154 | // If there's at most one path, no path components are redundant. |
| 155 | if (Paths.size() <= 1) |
| 156 | return 0; |
| 157 | |
| 158 | unsigned PrefixLen = 0; |
| 159 | unsigned NumRedundant = getNumRedundantPathComponents(Paths); |
| 160 | auto Component = sys::path::begin(Paths[0]); |
| 161 | for (unsigned I = 0; I < NumRedundant; ++I) { |
| 162 | auto LastComponent = Component; |
| 163 | ++Component; |
| 164 | PrefixLen += Component - LastComponent; |
| 165 | } |
| 166 | return PrefixLen; |
Vedant Kumar | fa75437 | 2016-09-08 00:56:43 +0000 | [diff] [blame] | 167 | } |
| 168 | |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 169 | } // end anonymous namespace |
| 170 | |
| 171 | namespace llvm { |
| 172 | |
Vedant Kumar | 627887b6 | 2016-09-09 01:32:49 +0000 | [diff] [blame] | 173 | void CoverageReport::render(const FileCoverageSummary &File, |
| 174 | raw_ostream &OS) const { |
Vedant Kumar | 5053b11 | 2016-09-06 22:46:00 +0000 | [diff] [blame] | 175 | auto FileCoverageColor = |
| 176 | determineCoveragePercentageColor(File.RegionCoverage); |
| 177 | auto FuncCoverageColor = |
| 178 | determineCoveragePercentageColor(File.FunctionCoverage); |
Vedant Kumar | 016111f | 2016-09-19 00:38:23 +0000 | [diff] [blame] | 179 | auto InstantiationCoverageColor = |
| 180 | determineCoveragePercentageColor(File.InstantiationCoverage); |
Vedant Kumar | 5053b11 | 2016-09-06 22:46:00 +0000 | [diff] [blame] | 181 | auto LineCoverageColor = determineCoveragePercentageColor(File.LineCoverage); |
Vedant Kumar | d938dfb | 2016-09-09 17:37:11 +0000 | [diff] [blame] | 182 | SmallString<256> FileName = File.Name; |
| 183 | sys::path::remove_dots(FileName, /*remove_dot_dots=*/true); |
| 184 | sys::path::native(FileName); |
Eli Friedman | 50479f6 | 2017-09-11 22:56:20 +0000 | [diff] [blame] | 185 | OS << column(FileName, FileReportColumns[0], Column::NoTrim); |
| 186 | |
| 187 | if (Options.ShowRegionSummary) { |
| 188 | OS << format("%*u", FileReportColumns[1], |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 189 | (unsigned)File.RegionCoverage.getNumRegions()); |
| 190 | Options.colored_ostream(OS, FileCoverageColor) |
| 191 | << format("%*u", FileReportColumns[2], |
| 192 | (unsigned)(File.RegionCoverage.getNumRegions() - |
| 193 | File.RegionCoverage.getCovered())); |
| 194 | if (File.RegionCoverage.getNumRegions()) |
Eli Friedman | 50479f6 | 2017-09-11 22:56:20 +0000 | [diff] [blame] | 195 | Options.colored_ostream(OS, FileCoverageColor) |
| 196 | << format("%*.2f", FileReportColumns[3] - 1, |
| 197 | File.RegionCoverage.getPercentCovered()) |
| 198 | << '%'; |
| 199 | else |
| 200 | OS << column("-", FileReportColumns[3], Column::RightAlignment); |
| 201 | } |
| 202 | |
NAKAMURA Takumi | 46d2e0e | 2014-10-01 00:29:26 +0000 | [diff] [blame] | 203 | OS << format("%*u", FileReportColumns[4], |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 204 | (unsigned)File.FunctionCoverage.getNumFunctions()); |
Ying Yi | e59ee43 | 2016-07-22 12:46:13 +0000 | [diff] [blame] | 205 | OS << format("%*u", FileReportColumns[5], |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 206 | (unsigned)(File.FunctionCoverage.getNumFunctions() - |
| 207 | File.FunctionCoverage.getExecuted())); |
| 208 | if (File.FunctionCoverage.getNumFunctions()) |
Alex Lorenz | 35369c1 | 2016-11-21 14:00:04 +0000 | [diff] [blame] | 209 | Options.colored_ostream(OS, FuncCoverageColor) |
| 210 | << format("%*.2f", FileReportColumns[6] - 1, |
| 211 | File.FunctionCoverage.getPercentCovered()) |
| 212 | << '%'; |
| 213 | else |
| 214 | OS << column("-", FileReportColumns[6], Column::RightAlignment); |
Eli Friedman | 50479f6 | 2017-09-11 22:56:20 +0000 | [diff] [blame] | 215 | |
| 216 | if (Options.ShowInstantiationSummary) { |
| 217 | OS << format("%*u", FileReportColumns[7], |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 218 | (unsigned)File.InstantiationCoverage.getNumFunctions()); |
Eli Friedman | 50479f6 | 2017-09-11 22:56:20 +0000 | [diff] [blame] | 219 | OS << format("%*u", FileReportColumns[8], |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 220 | (unsigned)(File.InstantiationCoverage.getNumFunctions() - |
| 221 | File.InstantiationCoverage.getExecuted())); |
| 222 | if (File.InstantiationCoverage.getNumFunctions()) |
Eli Friedman | 50479f6 | 2017-09-11 22:56:20 +0000 | [diff] [blame] | 223 | Options.colored_ostream(OS, InstantiationCoverageColor) |
| 224 | << format("%*.2f", FileReportColumns[9] - 1, |
| 225 | File.InstantiationCoverage.getPercentCovered()) |
| 226 | << '%'; |
| 227 | else |
| 228 | OS << column("-", FileReportColumns[9], Column::RightAlignment); |
| 229 | } |
| 230 | |
Vedant Kumar | 016111f | 2016-09-19 00:38:23 +0000 | [diff] [blame] | 231 | OS << format("%*u", FileReportColumns[10], |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 232 | (unsigned)File.LineCoverage.getNumLines()); |
Vedant Kumar | 5053b11 | 2016-09-06 22:46:00 +0000 | [diff] [blame] | 233 | Options.colored_ostream(OS, LineCoverageColor) << format( |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 234 | "%*u", FileReportColumns[11], (unsigned)(File.LineCoverage.getNumLines() - |
| 235 | File.LineCoverage.getCovered())); |
| 236 | if (File.LineCoverage.getNumLines()) |
Alex Lorenz | 35369c1 | 2016-11-21 14:00:04 +0000 | [diff] [blame] | 237 | Options.colored_ostream(OS, LineCoverageColor) |
| 238 | << format("%*.2f", FileReportColumns[12] - 1, |
| 239 | File.LineCoverage.getPercentCovered()) |
| 240 | << '%'; |
| 241 | else |
| 242 | OS << column("-", FileReportColumns[12], Column::RightAlignment); |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 243 | OS << "\n"; |
| 244 | } |
| 245 | |
| 246 | void CoverageReport::render(const FunctionCoverageSummary &Function, |
Vedant Kumar | f2b067c | 2017-02-05 20:11:03 +0000 | [diff] [blame] | 247 | const DemangleCache &DC, |
Vedant Kumar | 627887b6 | 2016-09-09 01:32:49 +0000 | [diff] [blame] | 248 | raw_ostream &OS) const { |
Vedant Kumar | 5053b11 | 2016-09-06 22:46:00 +0000 | [diff] [blame] | 249 | auto FuncCoverageColor = |
| 250 | determineCoveragePercentageColor(Function.RegionCoverage); |
| 251 | auto LineCoverageColor = |
| 252 | determineCoveragePercentageColor(Function.LineCoverage); |
Vedant Kumar | f2b067c | 2017-02-05 20:11:03 +0000 | [diff] [blame] | 253 | OS << column(DC.demangle(Function.Name), FunctionReportColumns[0], |
| 254 | Column::RightTrim) |
NAKAMURA Takumi | 46d2e0e | 2014-10-01 00:29:26 +0000 | [diff] [blame] | 255 | << format("%*u", FunctionReportColumns[1], |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 256 | (unsigned)Function.RegionCoverage.getNumRegions()); |
Vedant Kumar | 5053b11 | 2016-09-06 22:46:00 +0000 | [diff] [blame] | 257 | Options.colored_ostream(OS, FuncCoverageColor) |
NAKAMURA Takumi | 46d2e0e | 2014-10-01 00:29:26 +0000 | [diff] [blame] | 258 | << format("%*u", FunctionReportColumns[2], |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 259 | (unsigned)(Function.RegionCoverage.getNumRegions() - |
| 260 | Function.RegionCoverage.getCovered())); |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 261 | Options.colored_ostream( |
| 262 | OS, determineCoveragePercentageColor(Function.RegionCoverage)) |
| 263 | << format("%*.2f", FunctionReportColumns[3] - 1, |
Vedant Kumar | 5053b11 | 2016-09-06 22:46:00 +0000 | [diff] [blame] | 264 | Function.RegionCoverage.getPercentCovered()) |
| 265 | << '%'; |
NAKAMURA Takumi | 46d2e0e | 2014-10-01 00:29:26 +0000 | [diff] [blame] | 266 | OS << format("%*u", FunctionReportColumns[4], |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 267 | (unsigned)Function.LineCoverage.getNumLines()); |
Vedant Kumar | 5053b11 | 2016-09-06 22:46:00 +0000 | [diff] [blame] | 268 | Options.colored_ostream(OS, LineCoverageColor) |
NAKAMURA Takumi | 46d2e0e | 2014-10-01 00:29:26 +0000 | [diff] [blame] | 269 | << format("%*u", FunctionReportColumns[5], |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 270 | (unsigned)(Function.LineCoverage.getNumLines() - |
| 271 | Function.LineCoverage.getCovered())); |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 272 | Options.colored_ostream( |
| 273 | OS, determineCoveragePercentageColor(Function.LineCoverage)) |
| 274 | << format("%*.2f", FunctionReportColumns[6] - 1, |
Vedant Kumar | 5053b11 | 2016-09-06 22:46:00 +0000 | [diff] [blame] | 275 | Function.LineCoverage.getPercentCovered()) |
| 276 | << '%'; |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 277 | OS << "\n"; |
| 278 | } |
| 279 | |
Vedant Kumar | bc64798 | 2016-09-23 18:57:32 +0000 | [diff] [blame] | 280 | void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files, |
Vedant Kumar | f2b067c | 2017-02-05 20:11:03 +0000 | [diff] [blame] | 281 | const DemangleCache &DC, |
Justin Bogner | 0ef7a2a | 2015-02-14 02:05:05 +0000 | [diff] [blame] | 282 | raw_ostream &OS) { |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 283 | bool isFirst = true; |
Justin Bogner | 0ef7a2a | 2015-02-14 02:05:05 +0000 | [diff] [blame] | 284 | for (StringRef Filename : Files) { |
Vedant Kumar | dab0ec1 | 2016-09-19 00:38:16 +0000 | [diff] [blame] | 285 | auto Functions = Coverage.getCoveredFunctions(Filename); |
| 286 | |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 287 | if (isFirst) |
| 288 | isFirst = false; |
| 289 | else |
| 290 | OS << "\n"; |
Vedant Kumar | dab0ec1 | 2016-09-19 00:38:16 +0000 | [diff] [blame] | 291 | |
| 292 | std::vector<StringRef> Funcnames; |
| 293 | for (const auto &F : Functions) |
Vedant Kumar | f2b067c | 2017-02-05 20:11:03 +0000 | [diff] [blame] | 294 | Funcnames.emplace_back(DC.demangle(F.Name)); |
Vedant Kumar | dab0ec1 | 2016-09-19 00:38:16 +0000 | [diff] [blame] | 295 | adjustColumnWidths({}, Funcnames); |
| 296 | |
Justin Bogner | f91bc6c | 2015-02-14 02:01:24 +0000 | [diff] [blame] | 297 | OS << "File '" << Filename << "':\n"; |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 298 | OS << column("Name", FunctionReportColumns[0]) |
| 299 | << column("Regions", FunctionReportColumns[1], Column::RightAlignment) |
| 300 | << column("Miss", FunctionReportColumns[2], Column::RightAlignment) |
| 301 | << column("Cover", FunctionReportColumns[3], Column::RightAlignment) |
| 302 | << column("Lines", FunctionReportColumns[4], Column::RightAlignment) |
| 303 | << column("Miss", FunctionReportColumns[5], Column::RightAlignment) |
| 304 | << column("Cover", FunctionReportColumns[6], Column::RightAlignment); |
| 305 | OS << "\n"; |
| 306 | renderDivider(FunctionReportColumns, OS); |
| 307 | OS << "\n"; |
Justin Bogner | f91bc6c | 2015-02-14 02:01:24 +0000 | [diff] [blame] | 308 | FunctionCoverageSummary Totals("TOTAL"); |
Vedant Kumar | dab0ec1 | 2016-09-19 00:38:16 +0000 | [diff] [blame] | 309 | for (const auto &F : Functions) { |
Vedant Kumar | b7fdaf2 | 2017-09-19 02:00:12 +0000 | [diff] [blame] | 310 | auto Function = FunctionCoverageSummary::get(Coverage, F); |
Justin Bogner | f91bc6c | 2015-02-14 02:01:24 +0000 | [diff] [blame] | 311 | ++Totals.ExecutionCount; |
| 312 | Totals.RegionCoverage += Function.RegionCoverage; |
| 313 | Totals.LineCoverage += Function.LineCoverage; |
Vedant Kumar | f2b067c | 2017-02-05 20:11:03 +0000 | [diff] [blame] | 314 | render(Function, DC, OS); |
Justin Bogner | f91bc6c | 2015-02-14 02:01:24 +0000 | [diff] [blame] | 315 | } |
| 316 | if (Totals.ExecutionCount) { |
| 317 | renderDivider(FunctionReportColumns, OS); |
| 318 | OS << "\n"; |
Vedant Kumar | f2b067c | 2017-02-05 20:11:03 +0000 | [diff] [blame] | 319 | render(Totals, DC, OS); |
Justin Bogner | f91bc6c | 2015-02-14 02:01:24 +0000 | [diff] [blame] | 320 | } |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 321 | } |
| 322 | } |
| 323 | |
Max Moroz | cc254ba | 2018-01-05 16:15:07 +0000 | [diff] [blame] | 324 | void CoverageReport::prepareSingleFileReport(const StringRef Filename, |
| 325 | const coverage::CoverageMapping *Coverage, |
| 326 | const CoverageViewOptions &Options, const unsigned LCP, |
| 327 | FileCoverageSummary *FileReport, const CoverageFilter *Filters) { |
| 328 | for (const auto &Group : Coverage->getInstantiationGroups(Filename)) { |
| 329 | std::vector<FunctionCoverageSummary> InstantiationSummaries; |
| 330 | for (const coverage::FunctionRecord *F : Group.getInstantiations()) { |
| 331 | if (!Filters->matches(*Coverage, *F)) |
| 332 | continue; |
| 333 | auto InstantiationSummary = FunctionCoverageSummary::get(*Coverage, *F); |
| 334 | FileReport->addInstantiation(InstantiationSummary); |
| 335 | InstantiationSummaries.push_back(InstantiationSummary); |
| 336 | } |
| 337 | if (InstantiationSummaries.empty()) |
| 338 | continue; |
| 339 | |
| 340 | auto GroupSummary = |
| 341 | FunctionCoverageSummary::get(Group, InstantiationSummaries); |
| 342 | |
| 343 | if (Options.Debug) |
| 344 | outs() << "InstantiationGroup: " << GroupSummary.Name << " with " |
| 345 | << "size = " << Group.size() << "\n"; |
| 346 | |
| 347 | FileReport->addFunction(GroupSummary); |
| 348 | } |
| 349 | } |
| 350 | |
Vedant Kumar | 72c3a11 | 2017-09-08 18:44:49 +0000 | [diff] [blame] | 351 | std::vector<FileCoverageSummary> CoverageReport::prepareFileReports( |
| 352 | const coverage::CoverageMapping &Coverage, FileCoverageSummary &Totals, |
Sean Eveson | fa8ef35 | 2017-09-28 10:07:30 +0000 | [diff] [blame] | 353 | ArrayRef<std::string> Files, const CoverageViewOptions &Options, |
| 354 | const CoverageFilter &Filters) { |
Vedant Kumar | 1181328 | 2017-02-23 22:20:32 +0000 | [diff] [blame] | 355 | unsigned LCP = getRedundantPrefixLen(Files); |
Max Moroz | cc254ba | 2018-01-05 16:15:07 +0000 | [diff] [blame] | 356 | auto NumThreads = Options.NumThreads; |
| 357 | |
| 358 | // If NumThreads is not specified, auto-detect a good default. |
| 359 | if (NumThreads == 0) |
| 360 | NumThreads = |
| 361 | std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(), |
| 362 | unsigned(Files.size()))); |
| 363 | |
| 364 | ThreadPool Pool(NumThreads); |
| 365 | |
| 366 | std::vector<FileCoverageSummary> FileReports; |
| 367 | FileReports.reserve(Files.size()); |
Vedant Kumar | 627887b6 | 2016-09-09 01:32:49 +0000 | [diff] [blame] | 368 | |
| 369 | for (StringRef Filename : Files) { |
Max Moroz | cc254ba | 2018-01-05 16:15:07 +0000 | [diff] [blame] | 370 | FileReports.emplace_back(Filename.drop_front(LCP)); |
| 371 | Pool.async(&CoverageReport::prepareSingleFileReport, Filename, |
| 372 | &Coverage, Options, LCP, &FileReports.back(), &Filters); |
Vedant Kumar | 627887b6 | 2016-09-09 01:32:49 +0000 | [diff] [blame] | 373 | } |
Max Moroz | cc254ba | 2018-01-05 16:15:07 +0000 | [diff] [blame] | 374 | Pool.wait(); |
| 375 | |
| 376 | for (const auto &FileReport : FileReports) |
| 377 | Totals += FileReport; |
Vedant Kumar | 627887b6 | 2016-09-09 01:32:49 +0000 | [diff] [blame] | 378 | |
| 379 | return FileReports; |
| 380 | } |
| 381 | |
| 382 | void CoverageReport::renderFileReports(raw_ostream &OS) const { |
Vedant Kumar | bc64798 | 2016-09-23 18:57:32 +0000 | [diff] [blame] | 383 | std::vector<std::string> UniqueSourceFiles; |
| 384 | for (StringRef SF : Coverage.getUniqueSourceFiles()) |
| 385 | UniqueSourceFiles.emplace_back(SF.str()); |
Max Moroz | 4a4bfa4 | 2017-10-13 14:44:51 +0000 | [diff] [blame] | 386 | renderFileReports(OS, UniqueSourceFiles); |
| 387 | } |
| 388 | |
| 389 | void CoverageReport::renderFileReports( |
| 390 | raw_ostream &OS, ArrayRef<std::string> Files) const { |
| 391 | renderFileReports(OS, Files, CoverageFiltersMatchAll()); |
Vedant Kumar | 627887b6 | 2016-09-09 01:32:49 +0000 | [diff] [blame] | 392 | } |
| 393 | |
Sean Eveson | d932b2d | 2017-10-03 11:05:28 +0000 | [diff] [blame] | 394 | void CoverageReport::renderFileReports( |
| 395 | raw_ostream &OS, ArrayRef<std::string> Files, |
| 396 | const CoverageFiltersMatchAll &Filters) const { |
Vedant Kumar | dab0ec1 | 2016-09-19 00:38:16 +0000 | [diff] [blame] | 397 | FileCoverageSummary Totals("TOTAL"); |
Sean Eveson | fa8ef35 | 2017-09-28 10:07:30 +0000 | [diff] [blame] | 398 | auto FileReports = |
| 399 | prepareFileReports(Coverage, Totals, Files, Options, Filters); |
Vedant Kumar | dab0ec1 | 2016-09-19 00:38:16 +0000 | [diff] [blame] | 400 | |
| 401 | std::vector<StringRef> Filenames; |
| 402 | for (const FileCoverageSummary &FCS : FileReports) |
| 403 | Filenames.emplace_back(FCS.Name); |
| 404 | adjustColumnWidths(Filenames, {}); |
| 405 | |
Eli Friedman | 50479f6 | 2017-09-11 22:56:20 +0000 | [diff] [blame] | 406 | OS << column("Filename", FileReportColumns[0]); |
| 407 | if (Options.ShowRegionSummary) |
| 408 | OS << column("Regions", FileReportColumns[1], Column::RightAlignment) |
| 409 | << column("Missed Regions", FileReportColumns[2], Column::RightAlignment) |
| 410 | << column("Cover", FileReportColumns[3], Column::RightAlignment); |
| 411 | OS << column("Functions", FileReportColumns[4], Column::RightAlignment) |
Vedant Kumar | 5053b11 | 2016-09-06 22:46:00 +0000 | [diff] [blame] | 412 | << column("Missed Functions", FileReportColumns[5], Column::RightAlignment) |
Eli Friedman | 50479f6 | 2017-09-11 22:56:20 +0000 | [diff] [blame] | 413 | << column("Executed", FileReportColumns[6], Column::RightAlignment); |
| 414 | if (Options.ShowInstantiationSummary) |
| 415 | OS << column("Instantiations", FileReportColumns[7], Column::RightAlignment) |
| 416 | << column("Missed Insts.", FileReportColumns[8], Column::RightAlignment) |
| 417 | << column("Executed", FileReportColumns[9], Column::RightAlignment); |
| 418 | OS << column("Lines", FileReportColumns[10], Column::RightAlignment) |
Vedant Kumar | 016111f | 2016-09-19 00:38:23 +0000 | [diff] [blame] | 419 | << column("Missed Lines", FileReportColumns[11], Column::RightAlignment) |
| 420 | << column("Cover", FileReportColumns[12], Column::RightAlignment) << "\n"; |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 421 | renderDivider(FileReportColumns, OS); |
| 422 | OS << "\n"; |
Vedant Kumar | c3c39e7 | 2015-09-14 23:26:36 +0000 | [diff] [blame] | 423 | |
Eli Friedman | c0c182c | 2017-08-09 20:43:31 +0000 | [diff] [blame] | 424 | bool EmptyFiles = false; |
| 425 | for (const FileCoverageSummary &FCS : FileReports) { |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 426 | if (FCS.FunctionCoverage.getNumFunctions()) |
Eli Friedman | c0c182c | 2017-08-09 20:43:31 +0000 | [diff] [blame] | 427 | render(FCS, OS); |
| 428 | else |
| 429 | EmptyFiles = true; |
| 430 | } |
| 431 | |
Sean Eveson | d932b2d | 2017-10-03 11:05:28 +0000 | [diff] [blame] | 432 | if (EmptyFiles && Filters.empty()) { |
Eli Friedman | c0c182c | 2017-08-09 20:43:31 +0000 | [diff] [blame] | 433 | OS << "\n" |
| 434 | << "Files which contain no functions:\n"; |
| 435 | |
| 436 | for (const FileCoverageSummary &FCS : FileReports) |
Vedant Kumar | c445e65 | 2017-09-15 23:00:01 +0000 | [diff] [blame] | 437 | if (!FCS.FunctionCoverage.getNumFunctions()) |
Eli Friedman | c0c182c | 2017-08-09 20:43:31 +0000 | [diff] [blame] | 438 | render(FCS, OS); |
| 439 | } |
Vedant Kumar | 627887b6 | 2016-09-09 01:32:49 +0000 | [diff] [blame] | 440 | |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 441 | renderDivider(FileReportColumns, OS); |
| 442 | OS << "\n"; |
Justin Bogner | f91bc6c | 2015-02-14 02:01:24 +0000 | [diff] [blame] | 443 | render(Totals, OS); |
Alex Lorenz | e82d89c | 2014-08-22 22:56:03 +0000 | [diff] [blame] | 444 | } |
Vedant Kumar | 702bb9d | 2016-09-06 22:45:57 +0000 | [diff] [blame] | 445 | |
| 446 | } // end namespace llvm |