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>
createViewFile(StringRef Path,bool InToplevel)250b57cec5SDimitry Andric CoveragePrinterText::createViewFile(StringRef Path, bool InToplevel) {
260b57cec5SDimitry Andric return createOutputStream(Path, "txt", InToplevel);
270b57cec5SDimitry Andric }
280b57cec5SDimitry Andric
closeViewFile(OwnedStream OS)290b57cec5SDimitry Andric void CoveragePrinterText::closeViewFile(OwnedStream OS) {
300b57cec5SDimitry Andric OS->operator<<('\n');
310b57cec5SDimitry Andric }
320b57cec5SDimitry Andric
createIndexFile(ArrayRef<std::string> SourceFiles,const CoverageMapping & Coverage,const CoverageFiltersMatchAll & Filters)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
ReporterCoveragePrinterTextDirectory::Reporter545f757f3fSDimitry 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
generateSubDirectoryReportCoveragePrinterTextDirectory::Reporter605f757f3fSDimitry 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
createIndexFile(ArrayRef<std::string> SourceFiles,const CoverageMapping & Coverage,const CoverageFiltersMatchAll & Filters)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.
getCombinedColumnWidth(const CoverageViewOptions & Opts)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.
getDividerWidth(const CoverageViewOptions & Opts)1270b57cec5SDimitry Andric unsigned getDividerWidth(const CoverageViewOptions &Opts) {
1280b57cec5SDimitry Andric return getCombinedColumnWidth(Opts) + 4;
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric } // anonymous namespace
1320b57cec5SDimitry Andric
renderViewHeader(raw_ostream &)1330b57cec5SDimitry Andric void SourceCoverageViewText::renderViewHeader(raw_ostream &) {}
1340b57cec5SDimitry Andric
renderViewFooter(raw_ostream &)1350b57cec5SDimitry Andric void SourceCoverageViewText::renderViewFooter(raw_ostream &) {}
1360b57cec5SDimitry Andric
renderSourceName(raw_ostream & OS,bool WholeFile)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
renderLinePrefix(raw_ostream & OS,unsigned ViewDepth)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
renderLineSuffix(raw_ostream &,unsigned)1480b57cec5SDimitry Andric void SourceCoverageViewText::renderLineSuffix(raw_ostream &, unsigned) {}
1490b57cec5SDimitry Andric
renderViewDivider(raw_ostream & OS,unsigned ViewDepth)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
renderLine(raw_ostream & OS,LineRef L,const LineCoverageStats & LCS,unsigned ExpansionCol,unsigned ViewDepth)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
renderLineCoverageColumn(raw_ostream & OS,const LineCoverageStats & Line)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
renderLineNumberColumn(raw_ostream & OS,unsigned LineNo)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
renderRegionMarkers(raw_ostream & OS,const LineCoverageStats & Line,unsigned ViewDepth)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
renderExpansionSite(raw_ostream & OS,LineRef L,const LineCoverageStats & LCS,unsigned ExpansionCol,unsigned ViewDepth)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
renderExpansionView(raw_ostream & OS,ExpansionView & ESV,unsigned ViewDepth)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
renderBranchView(raw_ostream & OS,BranchView & BRV,unsigned ViewDepth)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
renderMCDCView(raw_ostream & OS,MCDCView & MRV,unsigned ViewDepth)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
renderInstantiationView(raw_ostream & OS,InstantiationView & ISV,unsigned ViewDepth)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
renderTitle(raw_ostream & OS,StringRef Title)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
renderTableHeader(raw_ostream &,unsigned)417*0fca6ea1SDimitry Andric void SourceCoverageViewText::renderTableHeader(raw_ostream &, unsigned) {}
418