xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- SourceCoverageViewText.cpp - A text-based code coverage view -------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file This file implements the text-based coverage renderer.
100b57cec5SDimitry Andric ///
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "SourceCoverageViewText.h"
14e8d8bef9SDimitry Andric #include "CoverageReport.h"
150b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
160b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
17*5f757f3fSDimitry Andric #include "llvm/Support/FileSystem.h"
18e8d8bef9SDimitry Andric #include "llvm/Support/Format.h"
19*5f757f3fSDimitry Andric #include "llvm/Support/Path.h"
20bdd1243dSDimitry Andric #include <optional>
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric using namespace llvm;
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric Expected<CoveragePrinter::OwnedStream>
250b57cec5SDimitry Andric CoveragePrinterText::createViewFile(StringRef Path, bool InToplevel) {
260b57cec5SDimitry Andric   return createOutputStream(Path, "txt", InToplevel);
270b57cec5SDimitry Andric }
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric void CoveragePrinterText::closeViewFile(OwnedStream OS) {
300b57cec5SDimitry Andric   OS->operator<<('\n');
310b57cec5SDimitry Andric }
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric Error CoveragePrinterText::createIndexFile(
340b57cec5SDimitry Andric     ArrayRef<std::string> SourceFiles, const CoverageMapping &Coverage,
350b57cec5SDimitry Andric     const CoverageFiltersMatchAll &Filters) {
360b57cec5SDimitry Andric   auto OSOrErr = createOutputStream("index", "txt", /*InToplevel=*/true);
370b57cec5SDimitry Andric   if (Error E = OSOrErr.takeError())
380b57cec5SDimitry Andric     return E;
390b57cec5SDimitry Andric   auto OS = std::move(OSOrErr.get());
400b57cec5SDimitry Andric   raw_ostream &OSRef = *OS.get();
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   CoverageReport Report(Opts, Coverage);
430b57cec5SDimitry Andric   Report.renderFileReports(OSRef, SourceFiles, Filters);
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   Opts.colored_ostream(OSRef, raw_ostream::CYAN) << "\n"
460b57cec5SDimitry Andric                                                  << Opts.getLLVMVersionString();
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   return Error::success();
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
51*5f757f3fSDimitry Andric struct CoveragePrinterTextDirectory::Reporter : public DirectoryCoverageReport {
52*5f757f3fSDimitry Andric   CoveragePrinterTextDirectory &Printer;
53*5f757f3fSDimitry Andric 
54*5f757f3fSDimitry Andric   Reporter(CoveragePrinterTextDirectory &Printer,
55*5f757f3fSDimitry Andric            const coverage::CoverageMapping &Coverage,
56*5f757f3fSDimitry Andric            const CoverageFiltersMatchAll &Filters)
57*5f757f3fSDimitry Andric       : DirectoryCoverageReport(Printer.Opts, Coverage, Filters),
58*5f757f3fSDimitry Andric         Printer(Printer) {}
59*5f757f3fSDimitry Andric 
60*5f757f3fSDimitry Andric   Error generateSubDirectoryReport(SubFileReports &&SubFiles,
61*5f757f3fSDimitry Andric                                    SubDirReports &&SubDirs,
62*5f757f3fSDimitry Andric                                    FileCoverageSummary &&SubTotals) override {
63*5f757f3fSDimitry Andric     auto &LCPath = SubTotals.Name;
64*5f757f3fSDimitry Andric     assert(Options.hasOutputDirectory() &&
65*5f757f3fSDimitry Andric            "No output directory for index file");
66*5f757f3fSDimitry Andric 
67*5f757f3fSDimitry Andric     SmallString<128> OSPath = LCPath;
68*5f757f3fSDimitry Andric     sys::path::append(OSPath, "index");
69*5f757f3fSDimitry Andric     auto OSOrErr = Printer.createOutputStream(OSPath, "txt",
70*5f757f3fSDimitry Andric                                               /*InToplevel=*/false);
71*5f757f3fSDimitry Andric     if (auto E = OSOrErr.takeError())
72*5f757f3fSDimitry Andric       return E;
73*5f757f3fSDimitry Andric     auto OS = std::move(OSOrErr.get());
74*5f757f3fSDimitry Andric     raw_ostream &OSRef = *OS.get();
75*5f757f3fSDimitry Andric 
76*5f757f3fSDimitry Andric     std::vector<FileCoverageSummary> Reports;
77*5f757f3fSDimitry Andric     for (auto &&SubDir : SubDirs)
78*5f757f3fSDimitry Andric       Reports.push_back(std::move(SubDir.second.first));
79*5f757f3fSDimitry Andric     for (auto &&SubFile : SubFiles)
80*5f757f3fSDimitry Andric       Reports.push_back(std::move(SubFile.second));
81*5f757f3fSDimitry Andric 
82*5f757f3fSDimitry Andric     CoverageReport Report(Options, Coverage);
83*5f757f3fSDimitry Andric     Report.renderFileReports(OSRef, Reports, SubTotals, Filters.empty());
84*5f757f3fSDimitry Andric 
85*5f757f3fSDimitry Andric     Options.colored_ostream(OSRef, raw_ostream::CYAN)
86*5f757f3fSDimitry Andric         << "\n"
87*5f757f3fSDimitry Andric         << Options.getLLVMVersionString();
88*5f757f3fSDimitry Andric 
89*5f757f3fSDimitry Andric     return Error::success();
90*5f757f3fSDimitry Andric   }
91*5f757f3fSDimitry Andric };
92*5f757f3fSDimitry Andric 
93*5f757f3fSDimitry Andric Error CoveragePrinterTextDirectory::createIndexFile(
94*5f757f3fSDimitry Andric     ArrayRef<std::string> SourceFiles, const CoverageMapping &Coverage,
95*5f757f3fSDimitry Andric     const CoverageFiltersMatchAll &Filters) {
96*5f757f3fSDimitry Andric   if (SourceFiles.size() <= 1)
97*5f757f3fSDimitry Andric     return CoveragePrinterText::createIndexFile(SourceFiles, Coverage, Filters);
98*5f757f3fSDimitry Andric 
99*5f757f3fSDimitry Andric   Reporter Report(*this, Coverage, Filters);
100*5f757f3fSDimitry Andric   auto TotalsOrErr = Report.prepareDirectoryReports(SourceFiles);
101*5f757f3fSDimitry Andric   if (auto E = TotalsOrErr.takeError())
102*5f757f3fSDimitry Andric     return E;
103*5f757f3fSDimitry Andric   auto &LCPath = TotalsOrErr->Name;
104*5f757f3fSDimitry Andric 
105*5f757f3fSDimitry Andric   auto TopIndexFilePath =
106*5f757f3fSDimitry Andric       getOutputPath("index", "txt", /*InToplevel=*/true, /*Relative=*/false);
107*5f757f3fSDimitry Andric   auto LCPIndexFilePath =
108*5f757f3fSDimitry Andric       getOutputPath((LCPath + "index").str(), "txt", /*InToplevel=*/false,
109*5f757f3fSDimitry Andric                     /*Relative=*/false);
110*5f757f3fSDimitry Andric   return errorCodeToError(
111*5f757f3fSDimitry Andric       sys::fs::copy_file(LCPIndexFilePath, TopIndexFilePath));
112*5f757f3fSDimitry Andric }
113*5f757f3fSDimitry Andric 
1140b57cec5SDimitry Andric namespace {
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric static const unsigned LineCoverageColumnWidth = 7;
1170b57cec5SDimitry Andric static const unsigned LineNumberColumnWidth = 5;
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric /// Get the width of the leading columns.
1200b57cec5SDimitry Andric unsigned getCombinedColumnWidth(const CoverageViewOptions &Opts) {
1210b57cec5SDimitry Andric   return (Opts.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) +
1220b57cec5SDimitry Andric          (Opts.ShowLineNumbers ? LineNumberColumnWidth + 1 : 0);
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric /// The width of the line that is used to divide between the view and
1260b57cec5SDimitry Andric /// the subviews.
1270b57cec5SDimitry Andric unsigned getDividerWidth(const CoverageViewOptions &Opts) {
1280b57cec5SDimitry Andric   return getCombinedColumnWidth(Opts) + 4;
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric } // anonymous namespace
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric void SourceCoverageViewText::renderViewHeader(raw_ostream &) {}
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric void SourceCoverageViewText::renderViewFooter(raw_ostream &) {}
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric void SourceCoverageViewText::renderSourceName(raw_ostream &OS, bool WholeFile) {
1380b57cec5SDimitry Andric   getOptions().colored_ostream(OS, raw_ostream::CYAN) << getSourceName()
1390b57cec5SDimitry Andric                                                       << ":\n";
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric void SourceCoverageViewText::renderLinePrefix(raw_ostream &OS,
1430b57cec5SDimitry Andric                                               unsigned ViewDepth) {
1440b57cec5SDimitry Andric   for (unsigned I = 0; I < ViewDepth; ++I)
1450b57cec5SDimitry Andric     OS << "  |";
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric void SourceCoverageViewText::renderLineSuffix(raw_ostream &, unsigned) {}
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric void SourceCoverageViewText::renderViewDivider(raw_ostream &OS,
1510b57cec5SDimitry Andric                                                unsigned ViewDepth) {
1520b57cec5SDimitry Andric   assert(ViewDepth != 0 && "Cannot render divider at top level");
1530b57cec5SDimitry Andric   renderLinePrefix(OS, ViewDepth - 1);
1540b57cec5SDimitry Andric   OS.indent(2);
1550b57cec5SDimitry Andric   unsigned Length = getDividerWidth(getOptions());
1560b57cec5SDimitry Andric   for (unsigned I = 0; I < Length; ++I)
1570b57cec5SDimitry Andric     OS << '-';
1580b57cec5SDimitry Andric   OS << '\n';
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric void SourceCoverageViewText::renderLine(raw_ostream &OS, LineRef L,
1620b57cec5SDimitry Andric                                         const LineCoverageStats &LCS,
1630b57cec5SDimitry Andric                                         unsigned ExpansionCol,
1640b57cec5SDimitry Andric                                         unsigned ViewDepth) {
1650b57cec5SDimitry Andric   StringRef Line = L.Line;
1660b57cec5SDimitry Andric   unsigned LineNumber = L.LineNo;
1670b57cec5SDimitry Andric   auto *WrappedSegment = LCS.getWrappedSegment();
1680b57cec5SDimitry Andric   CoverageSegmentArray Segments = LCS.getLineSegments();
1690b57cec5SDimitry Andric 
170bdd1243dSDimitry Andric   std::optional<raw_ostream::Colors> Highlight;
1710b57cec5SDimitry Andric   SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges;
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   // The first segment overlaps from a previous line, so we treat it specially.
1740b57cec5SDimitry Andric   if (WrappedSegment && !WrappedSegment->IsGapRegion &&
1750b57cec5SDimitry Andric       WrappedSegment->HasCount && WrappedSegment->Count == 0)
1760b57cec5SDimitry Andric     Highlight = raw_ostream::RED;
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   // Output each segment of the line, possibly highlighted.
1790b57cec5SDimitry Andric   unsigned Col = 1;
1800b57cec5SDimitry Andric   for (const auto *S : Segments) {
1810b57cec5SDimitry Andric     unsigned End = std::min(S->Col, static_cast<unsigned>(Line.size()) + 1);
1820b57cec5SDimitry Andric     colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
1830b57cec5SDimitry Andric                     getOptions().Colors && Highlight, /*Bold=*/false,
1840b57cec5SDimitry Andric                     /*BG=*/true)
1850b57cec5SDimitry Andric         << Line.substr(Col - 1, End - Col);
1860b57cec5SDimitry Andric     if (getOptions().Debug && Highlight)
1870b57cec5SDimitry Andric       HighlightedRanges.push_back(std::make_pair(Col, End));
1880b57cec5SDimitry Andric     Col = End;
1890b57cec5SDimitry Andric     if ((!S->IsGapRegion || (Highlight && *Highlight == raw_ostream::RED)) &&
1900b57cec5SDimitry Andric         S->HasCount && S->Count == 0)
1910b57cec5SDimitry Andric       Highlight = raw_ostream::RED;
1920b57cec5SDimitry Andric     else if (Col == ExpansionCol)
1930b57cec5SDimitry Andric       Highlight = raw_ostream::CYAN;
1940b57cec5SDimitry Andric     else
195bdd1243dSDimitry Andric       Highlight = std::nullopt;
1960b57cec5SDimitry Andric   }
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric   // Show the rest of the line.
1990b57cec5SDimitry Andric   colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
2000b57cec5SDimitry Andric                   getOptions().Colors && Highlight, /*Bold=*/false, /*BG=*/true)
2010b57cec5SDimitry Andric       << Line.substr(Col - 1, Line.size() - Col + 1);
2020b57cec5SDimitry Andric   OS << '\n';
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   if (getOptions().Debug) {
2050b57cec5SDimitry Andric     for (const auto &Range : HighlightedRanges)
2060b57cec5SDimitry Andric       errs() << "Highlighted line " << LineNumber << ", " << Range.first
2070b57cec5SDimitry Andric              << " -> " << Range.second << '\n';
2080b57cec5SDimitry Andric     if (Highlight)
2090b57cec5SDimitry Andric       errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n";
2100b57cec5SDimitry Andric   }
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric void SourceCoverageViewText::renderLineCoverageColumn(
2140b57cec5SDimitry Andric     raw_ostream &OS, const LineCoverageStats &Line) {
2150b57cec5SDimitry Andric   if (!Line.isMapped()) {
2160b57cec5SDimitry Andric     OS.indent(LineCoverageColumnWidth) << '|';
2170b57cec5SDimitry Andric     return;
2180b57cec5SDimitry Andric   }
2190b57cec5SDimitry Andric   std::string C = formatCount(Line.getExecutionCount());
2200b57cec5SDimitry Andric   OS.indent(LineCoverageColumnWidth - C.size());
2210b57cec5SDimitry Andric   colored_ostream(OS, raw_ostream::MAGENTA,
2220b57cec5SDimitry Andric                   Line.hasMultipleRegions() && getOptions().Colors)
2230b57cec5SDimitry Andric       << C;
2240b57cec5SDimitry Andric   OS << '|';
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric void SourceCoverageViewText::renderLineNumberColumn(raw_ostream &OS,
2280b57cec5SDimitry Andric                                                     unsigned LineNo) {
2290b57cec5SDimitry Andric   SmallString<32> Buffer;
2300b57cec5SDimitry Andric   raw_svector_ostream BufferOS(Buffer);
2310b57cec5SDimitry Andric   BufferOS << LineNo;
2320b57cec5SDimitry Andric   auto Str = BufferOS.str();
2330b57cec5SDimitry Andric   // Trim and align to the right.
2340b57cec5SDimitry Andric   Str = Str.substr(0, std::min(Str.size(), (size_t)LineNumberColumnWidth));
2350b57cec5SDimitry Andric   OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|';
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric void SourceCoverageViewText::renderRegionMarkers(raw_ostream &OS,
2390b57cec5SDimitry Andric                                                  const LineCoverageStats &Line,
2400b57cec5SDimitry Andric                                                  unsigned ViewDepth) {
2410b57cec5SDimitry Andric   renderLinePrefix(OS, ViewDepth);
2420b57cec5SDimitry Andric   OS.indent(getCombinedColumnWidth(getOptions()));
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   CoverageSegmentArray Segments = Line.getLineSegments();
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric   // Just consider the segments which start *and* end on this line.
2470b57cec5SDimitry Andric   if (Segments.size() > 1)
2480b57cec5SDimitry Andric     Segments = Segments.drop_back();
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   unsigned PrevColumn = 1;
2510b57cec5SDimitry Andric   for (const auto *S : Segments) {
2520b57cec5SDimitry Andric     if (!S->IsRegionEntry)
2530b57cec5SDimitry Andric       continue;
2540b57cec5SDimitry Andric     if (S->Count == Line.getExecutionCount())
2550b57cec5SDimitry Andric       continue;
2560b57cec5SDimitry Andric     // Skip to the new region.
2570b57cec5SDimitry Andric     if (S->Col > PrevColumn)
2580b57cec5SDimitry Andric       OS.indent(S->Col - PrevColumn);
2590b57cec5SDimitry Andric     PrevColumn = S->Col + 1;
2600b57cec5SDimitry Andric     std::string C = formatCount(S->Count);
2610b57cec5SDimitry Andric     PrevColumn += C.size();
2620b57cec5SDimitry Andric     OS << '^' << C;
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric     if (getOptions().Debug)
2650b57cec5SDimitry Andric       errs() << "Marker at " << S->Line << ":" << S->Col << " = "
2660b57cec5SDimitry Andric             << formatCount(S->Count) << "\n";
2670b57cec5SDimitry Andric   }
2680b57cec5SDimitry Andric   OS << '\n';
2690b57cec5SDimitry Andric }
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric void SourceCoverageViewText::renderExpansionSite(raw_ostream &OS, LineRef L,
2720b57cec5SDimitry Andric                                                  const LineCoverageStats &LCS,
2730b57cec5SDimitry Andric                                                  unsigned ExpansionCol,
2740b57cec5SDimitry Andric                                                  unsigned ViewDepth) {
2750b57cec5SDimitry Andric   renderLinePrefix(OS, ViewDepth);
2760b57cec5SDimitry Andric   OS.indent(getCombinedColumnWidth(getOptions()) + (ViewDepth == 0 ? 0 : 1));
2770b57cec5SDimitry Andric   renderLine(OS, L, LCS, ExpansionCol, ViewDepth);
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric void SourceCoverageViewText::renderExpansionView(raw_ostream &OS,
2810b57cec5SDimitry Andric                                                  ExpansionView &ESV,
2820b57cec5SDimitry Andric                                                  unsigned ViewDepth) {
2830b57cec5SDimitry Andric   // Render the child subview.
2840b57cec5SDimitry Andric   if (getOptions().Debug)
2850b57cec5SDimitry Andric     errs() << "Expansion at line " << ESV.getLine() << ", " << ESV.getStartCol()
2860b57cec5SDimitry Andric            << " -> " << ESV.getEndCol() << '\n';
2870b57cec5SDimitry Andric   ESV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/false,
2880b57cec5SDimitry Andric                   /*ShowTitle=*/false, ViewDepth + 1);
2890b57cec5SDimitry Andric }
2900b57cec5SDimitry Andric 
291e8d8bef9SDimitry Andric void SourceCoverageViewText::renderBranchView(raw_ostream &OS, BranchView &BRV,
292e8d8bef9SDimitry Andric                                               unsigned ViewDepth) {
293e8d8bef9SDimitry Andric   // Render the child subview.
294e8d8bef9SDimitry Andric   if (getOptions().Debug)
295e8d8bef9SDimitry Andric     errs() << "Branch at line " << BRV.getLine() << '\n';
296e8d8bef9SDimitry Andric 
297e8d8bef9SDimitry Andric   for (const auto &R : BRV.Regions) {
298e8d8bef9SDimitry Andric     double TruePercent = 0.0;
299e8d8bef9SDimitry Andric     double FalsePercent = 0.0;
300*5f757f3fSDimitry Andric     // FIXME: It may overflow when the data is too large, but I have not
301*5f757f3fSDimitry Andric     // encountered it in actual use, and not sure whether to use __uint128_t.
302*5f757f3fSDimitry Andric     uint64_t Total = R.ExecutionCount + R.FalseExecutionCount;
303e8d8bef9SDimitry Andric 
304e8d8bef9SDimitry Andric     if (!getOptions().ShowBranchCounts && Total != 0) {
305e8d8bef9SDimitry Andric       TruePercent = ((double)(R.ExecutionCount) / (double)Total) * 100.0;
306e8d8bef9SDimitry Andric       FalsePercent = ((double)(R.FalseExecutionCount) / (double)Total) * 100.0;
307e8d8bef9SDimitry Andric     }
308e8d8bef9SDimitry Andric 
309e8d8bef9SDimitry Andric     renderLinePrefix(OS, ViewDepth);
310e8d8bef9SDimitry Andric     OS << "  Branch (" << R.LineStart << ":" << R.ColumnStart << "): [";
311e8d8bef9SDimitry Andric 
312e8d8bef9SDimitry Andric     if (R.Folded) {
313e8d8bef9SDimitry Andric       OS << "Folded - Ignored]\n";
314e8d8bef9SDimitry Andric       continue;
315e8d8bef9SDimitry Andric     }
316e8d8bef9SDimitry Andric 
317e8d8bef9SDimitry Andric     colored_ostream(OS, raw_ostream::RED,
318e8d8bef9SDimitry Andric                     getOptions().Colors && !R.ExecutionCount,
319e8d8bef9SDimitry Andric                     /*Bold=*/false, /*BG=*/true)
320e8d8bef9SDimitry Andric         << "True";
321e8d8bef9SDimitry Andric 
322e8d8bef9SDimitry Andric     if (getOptions().ShowBranchCounts)
323e8d8bef9SDimitry Andric       OS << ": " << formatCount(R.ExecutionCount) << ", ";
324e8d8bef9SDimitry Andric     else
325e8d8bef9SDimitry Andric       OS << ": " << format("%0.2f", TruePercent) << "%, ";
326e8d8bef9SDimitry Andric 
327e8d8bef9SDimitry Andric     colored_ostream(OS, raw_ostream::RED,
328e8d8bef9SDimitry Andric                     getOptions().Colors && !R.FalseExecutionCount,
329e8d8bef9SDimitry Andric                     /*Bold=*/false, /*BG=*/true)
330e8d8bef9SDimitry Andric         << "False";
331e8d8bef9SDimitry Andric 
332e8d8bef9SDimitry Andric     if (getOptions().ShowBranchCounts)
333e8d8bef9SDimitry Andric       OS << ": " << formatCount(R.FalseExecutionCount);
334e8d8bef9SDimitry Andric     else
335e8d8bef9SDimitry Andric       OS << ": " << format("%0.2f", FalsePercent) << "%";
336e8d8bef9SDimitry Andric     OS << "]\n";
337e8d8bef9SDimitry Andric   }
338e8d8bef9SDimitry Andric }
339e8d8bef9SDimitry Andric 
340*5f757f3fSDimitry Andric void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
341*5f757f3fSDimitry Andric                                             unsigned ViewDepth) {
342*5f757f3fSDimitry Andric   for (auto &Record : MRV.Records) {
343*5f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
344*5f757f3fSDimitry Andric     OS << "---> MC/DC Decision Region (";
345*5f757f3fSDimitry Andric     // Display Line + Column information.
346*5f757f3fSDimitry Andric     const CounterMappingRegion &DecisionRegion = Record.getDecisionRegion();
347*5f757f3fSDimitry Andric     OS << DecisionRegion.LineStart << ":";
348*5f757f3fSDimitry Andric     OS << DecisionRegion.ColumnStart << ") to (";
349*5f757f3fSDimitry Andric     OS << DecisionRegion.LineEnd << ":";
350*5f757f3fSDimitry Andric     OS << DecisionRegion.ColumnEnd << ")\n";
351*5f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
352*5f757f3fSDimitry Andric     OS << "\n";
353*5f757f3fSDimitry Andric 
354*5f757f3fSDimitry Andric     // Display MC/DC Information.
355*5f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
356*5f757f3fSDimitry Andric     OS << "  Number of Conditions: " << Record.getNumConditions() << "\n";
357*5f757f3fSDimitry Andric     for (unsigned i = 0; i < Record.getNumConditions(); i++) {
358*5f757f3fSDimitry Andric       renderLinePrefix(OS, ViewDepth);
359*5f757f3fSDimitry Andric       OS << "     " << Record.getConditionHeaderString(i);
360*5f757f3fSDimitry Andric     }
361*5f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
362*5f757f3fSDimitry Andric     OS << "\n";
363*5f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
364*5f757f3fSDimitry Andric     OS << "  Executed MC/DC Test Vectors:\n";
365*5f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
366*5f757f3fSDimitry Andric     OS << "\n";
367*5f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
368*5f757f3fSDimitry Andric     OS << "     ";
369*5f757f3fSDimitry Andric     OS << Record.getTestVectorHeaderString();
370*5f757f3fSDimitry Andric     for (unsigned i = 0; i < Record.getNumTestVectors(); i++) {
371*5f757f3fSDimitry Andric       renderLinePrefix(OS, ViewDepth);
372*5f757f3fSDimitry Andric       OS << Record.getTestVectorString(i);
373*5f757f3fSDimitry Andric     }
374*5f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
375*5f757f3fSDimitry Andric     OS << "\n";
376*5f757f3fSDimitry Andric     for (unsigned i = 0; i < Record.getNumConditions(); i++) {
377*5f757f3fSDimitry Andric       renderLinePrefix(OS, ViewDepth);
378*5f757f3fSDimitry Andric       OS << Record.getConditionCoverageString(i);
379*5f757f3fSDimitry Andric     }
380*5f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
381*5f757f3fSDimitry Andric     OS << "  MC/DC Coverage for Decision: ";
382*5f757f3fSDimitry Andric     colored_ostream(OS, raw_ostream::RED,
383*5f757f3fSDimitry Andric                     getOptions().Colors && Record.getPercentCovered() < 100.0,
384*5f757f3fSDimitry Andric                     /*Bold=*/false, /*BG=*/true)
385*5f757f3fSDimitry Andric         << format("%0.2f", Record.getPercentCovered()) << "%\n";
386*5f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
387*5f757f3fSDimitry Andric     OS << "\n";
388*5f757f3fSDimitry Andric   }
389*5f757f3fSDimitry Andric }
390*5f757f3fSDimitry Andric 
3910b57cec5SDimitry Andric void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS,
3920b57cec5SDimitry Andric                                                      InstantiationView &ISV,
3930b57cec5SDimitry Andric                                                      unsigned ViewDepth) {
3940b57cec5SDimitry Andric   renderLinePrefix(OS, ViewDepth);
3950b57cec5SDimitry Andric   OS << ' ';
3960b57cec5SDimitry Andric   if (!ISV.View)
3970b57cec5SDimitry Andric     getOptions().colored_ostream(OS, raw_ostream::RED)
3980b57cec5SDimitry Andric         << "Unexecuted instantiation: " << ISV.FunctionName << "\n";
3990b57cec5SDimitry Andric   else
4000b57cec5SDimitry Andric     ISV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/true,
4010b57cec5SDimitry Andric                     /*ShowTitle=*/false, ViewDepth);
4020b57cec5SDimitry Andric }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric void SourceCoverageViewText::renderTitle(raw_ostream &OS, StringRef Title) {
4050b57cec5SDimitry Andric   if (getOptions().hasProjectTitle())
4060b57cec5SDimitry Andric     getOptions().colored_ostream(OS, raw_ostream::CYAN)
4070b57cec5SDimitry Andric         << getOptions().ProjectTitle << "\n";
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric   getOptions().colored_ostream(OS, raw_ostream::CYAN) << Title << "\n";
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric   if (getOptions().hasCreatedTime())
4120b57cec5SDimitry Andric     getOptions().colored_ostream(OS, raw_ostream::CYAN)
4130b57cec5SDimitry Andric         << getOptions().CreatedTimeStr << "\n";
4140b57cec5SDimitry Andric }
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric void SourceCoverageViewText::renderTableHeader(raw_ostream &, unsigned,
4170b57cec5SDimitry Andric                                                unsigned) {}
418