xref: /freebsd-src/contrib/llvm-project/llvm/tools/llvm-cov/SourceCoverageViewText.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
175f757f3fSDimitry Andric #include "llvm/Support/FileSystem.h"
18e8d8bef9SDimitry Andric #include "llvm/Support/Format.h"
195f757f3fSDimitry 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 
515f757f3fSDimitry Andric struct CoveragePrinterTextDirectory::Reporter : public DirectoryCoverageReport {
525f757f3fSDimitry Andric   CoveragePrinterTextDirectory &Printer;
535f757f3fSDimitry Andric 
545f757f3fSDimitry Andric   Reporter(CoveragePrinterTextDirectory &Printer,
555f757f3fSDimitry Andric            const coverage::CoverageMapping &Coverage,
565f757f3fSDimitry Andric            const CoverageFiltersMatchAll &Filters)
575f757f3fSDimitry Andric       : DirectoryCoverageReport(Printer.Opts, Coverage, Filters),
585f757f3fSDimitry Andric         Printer(Printer) {}
595f757f3fSDimitry Andric 
605f757f3fSDimitry Andric   Error generateSubDirectoryReport(SubFileReports &&SubFiles,
615f757f3fSDimitry Andric                                    SubDirReports &&SubDirs,
625f757f3fSDimitry Andric                                    FileCoverageSummary &&SubTotals) override {
635f757f3fSDimitry Andric     auto &LCPath = SubTotals.Name;
645f757f3fSDimitry Andric     assert(Options.hasOutputDirectory() &&
655f757f3fSDimitry Andric            "No output directory for index file");
665f757f3fSDimitry Andric 
675f757f3fSDimitry Andric     SmallString<128> OSPath = LCPath;
685f757f3fSDimitry Andric     sys::path::append(OSPath, "index");
695f757f3fSDimitry Andric     auto OSOrErr = Printer.createOutputStream(OSPath, "txt",
705f757f3fSDimitry Andric                                               /*InToplevel=*/false);
715f757f3fSDimitry Andric     if (auto E = OSOrErr.takeError())
725f757f3fSDimitry Andric       return E;
735f757f3fSDimitry Andric     auto OS = std::move(OSOrErr.get());
745f757f3fSDimitry Andric     raw_ostream &OSRef = *OS.get();
755f757f3fSDimitry Andric 
765f757f3fSDimitry Andric     std::vector<FileCoverageSummary> Reports;
775f757f3fSDimitry Andric     for (auto &&SubDir : SubDirs)
785f757f3fSDimitry Andric       Reports.push_back(std::move(SubDir.second.first));
795f757f3fSDimitry Andric     for (auto &&SubFile : SubFiles)
805f757f3fSDimitry Andric       Reports.push_back(std::move(SubFile.second));
815f757f3fSDimitry Andric 
825f757f3fSDimitry Andric     CoverageReport Report(Options, Coverage);
835f757f3fSDimitry Andric     Report.renderFileReports(OSRef, Reports, SubTotals, Filters.empty());
845f757f3fSDimitry Andric 
855f757f3fSDimitry Andric     Options.colored_ostream(OSRef, raw_ostream::CYAN)
865f757f3fSDimitry Andric         << "\n"
875f757f3fSDimitry Andric         << Options.getLLVMVersionString();
885f757f3fSDimitry Andric 
895f757f3fSDimitry Andric     return Error::success();
905f757f3fSDimitry Andric   }
915f757f3fSDimitry Andric };
925f757f3fSDimitry Andric 
935f757f3fSDimitry Andric Error CoveragePrinterTextDirectory::createIndexFile(
945f757f3fSDimitry Andric     ArrayRef<std::string> SourceFiles, const CoverageMapping &Coverage,
955f757f3fSDimitry Andric     const CoverageFiltersMatchAll &Filters) {
965f757f3fSDimitry Andric   if (SourceFiles.size() <= 1)
975f757f3fSDimitry Andric     return CoveragePrinterText::createIndexFile(SourceFiles, Coverage, Filters);
985f757f3fSDimitry Andric 
995f757f3fSDimitry Andric   Reporter Report(*this, Coverage, Filters);
1005f757f3fSDimitry Andric   auto TotalsOrErr = Report.prepareDirectoryReports(SourceFiles);
1015f757f3fSDimitry Andric   if (auto E = TotalsOrErr.takeError())
1025f757f3fSDimitry Andric     return E;
1035f757f3fSDimitry Andric   auto &LCPath = TotalsOrErr->Name;
1045f757f3fSDimitry Andric 
1055f757f3fSDimitry Andric   auto TopIndexFilePath =
1065f757f3fSDimitry Andric       getOutputPath("index", "txt", /*InToplevel=*/true, /*Relative=*/false);
1075f757f3fSDimitry Andric   auto LCPIndexFilePath =
1085f757f3fSDimitry Andric       getOutputPath((LCPath + "index").str(), "txt", /*InToplevel=*/false,
1095f757f3fSDimitry Andric                     /*Relative=*/false);
1105f757f3fSDimitry Andric   return errorCodeToError(
1115f757f3fSDimitry Andric       sys::fs::copy_file(LCPIndexFilePath, TopIndexFilePath));
1125f757f3fSDimitry Andric }
1135f757f3fSDimitry 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;
3005f757f3fSDimitry Andric     // FIXME: It may overflow when the data is too large, but I have not
3015f757f3fSDimitry Andric     // encountered it in actual use, and not sure whether to use __uint128_t.
3025f757f3fSDimitry 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 
3405f757f3fSDimitry Andric void SourceCoverageViewText::renderMCDCView(raw_ostream &OS, MCDCView &MRV,
3415f757f3fSDimitry Andric                                             unsigned ViewDepth) {
3425f757f3fSDimitry Andric   for (auto &Record : MRV.Records) {
3435f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
3445f757f3fSDimitry Andric     OS << "---> MC/DC Decision Region (";
3455f757f3fSDimitry Andric     // Display Line + Column information.
3465f757f3fSDimitry Andric     const CounterMappingRegion &DecisionRegion = Record.getDecisionRegion();
3475f757f3fSDimitry Andric     OS << DecisionRegion.LineStart << ":";
3485f757f3fSDimitry Andric     OS << DecisionRegion.ColumnStart << ") to (";
3495f757f3fSDimitry Andric     OS << DecisionRegion.LineEnd << ":";
3505f757f3fSDimitry Andric     OS << DecisionRegion.ColumnEnd << ")\n";
3515f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
3525f757f3fSDimitry Andric     OS << "\n";
3535f757f3fSDimitry Andric 
3545f757f3fSDimitry Andric     // Display MC/DC Information.
3555f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
3565f757f3fSDimitry Andric     OS << "  Number of Conditions: " << Record.getNumConditions() << "\n";
3575f757f3fSDimitry Andric     for (unsigned i = 0; i < Record.getNumConditions(); i++) {
3585f757f3fSDimitry Andric       renderLinePrefix(OS, ViewDepth);
3595f757f3fSDimitry Andric       OS << "     " << Record.getConditionHeaderString(i);
3605f757f3fSDimitry Andric     }
3615f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
3625f757f3fSDimitry Andric     OS << "\n";
3635f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
3645f757f3fSDimitry Andric     OS << "  Executed MC/DC Test Vectors:\n";
3655f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
3665f757f3fSDimitry Andric     OS << "\n";
3675f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
3685f757f3fSDimitry Andric     OS << "     ";
3695f757f3fSDimitry Andric     OS << Record.getTestVectorHeaderString();
3705f757f3fSDimitry Andric     for (unsigned i = 0; i < Record.getNumTestVectors(); i++) {
3715f757f3fSDimitry Andric       renderLinePrefix(OS, ViewDepth);
3725f757f3fSDimitry Andric       OS << Record.getTestVectorString(i);
3735f757f3fSDimitry Andric     }
3745f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
3755f757f3fSDimitry Andric     OS << "\n";
3765f757f3fSDimitry Andric     for (unsigned i = 0; i < Record.getNumConditions(); i++) {
3775f757f3fSDimitry Andric       renderLinePrefix(OS, ViewDepth);
3785f757f3fSDimitry Andric       OS << Record.getConditionCoverageString(i);
3795f757f3fSDimitry Andric     }
3805f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
3815f757f3fSDimitry Andric     OS << "  MC/DC Coverage for Decision: ";
3825f757f3fSDimitry Andric     colored_ostream(OS, raw_ostream::RED,
3835f757f3fSDimitry Andric                     getOptions().Colors && Record.getPercentCovered() < 100.0,
3845f757f3fSDimitry Andric                     /*Bold=*/false, /*BG=*/true)
3854c2d3b02SDimitry Andric         << format("%0.2f", Record.getPercentCovered()) << "%";
3864c2d3b02SDimitry Andric     OS << "\n";
3875f757f3fSDimitry Andric     renderLinePrefix(OS, ViewDepth);
3885f757f3fSDimitry Andric     OS << "\n";
3895f757f3fSDimitry Andric   }
3905f757f3fSDimitry Andric }
3915f757f3fSDimitry Andric 
3920b57cec5SDimitry Andric void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS,
3930b57cec5SDimitry Andric                                                      InstantiationView &ISV,
3940b57cec5SDimitry Andric                                                      unsigned ViewDepth) {
3950b57cec5SDimitry Andric   renderLinePrefix(OS, ViewDepth);
3960b57cec5SDimitry Andric   OS << ' ';
3970b57cec5SDimitry Andric   if (!ISV.View)
3980b57cec5SDimitry Andric     getOptions().colored_ostream(OS, raw_ostream::RED)
3990b57cec5SDimitry Andric         << "Unexecuted instantiation: " << ISV.FunctionName << "\n";
4000b57cec5SDimitry Andric   else
4010b57cec5SDimitry Andric     ISV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/true,
4020b57cec5SDimitry Andric                     /*ShowTitle=*/false, ViewDepth);
4030b57cec5SDimitry Andric }
4040b57cec5SDimitry Andric 
4050b57cec5SDimitry Andric void SourceCoverageViewText::renderTitle(raw_ostream &OS, StringRef Title) {
4060b57cec5SDimitry Andric   if (getOptions().hasProjectTitle())
4070b57cec5SDimitry Andric     getOptions().colored_ostream(OS, raw_ostream::CYAN)
4080b57cec5SDimitry Andric         << getOptions().ProjectTitle << "\n";
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric   getOptions().colored_ostream(OS, raw_ostream::CYAN) << Title << "\n";
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric   if (getOptions().hasCreatedTime())
4130b57cec5SDimitry Andric     getOptions().colored_ostream(OS, raw_ostream::CYAN)
4140b57cec5SDimitry Andric         << getOptions().CreatedTimeStr << "\n";
4150b57cec5SDimitry Andric }
4160b57cec5SDimitry Andric 
417*0fca6ea1SDimitry Andric void SourceCoverageViewText::renderTableHeader(raw_ostream &, unsigned) {}
418