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