SourceCoverageViewText.cpp revision 303231
1//===- SourceCoverageViewText.cpp - A text-based code coverage view -------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file This file implements the text-based coverage renderer.
11///
12//===----------------------------------------------------------------------===//
13
14#include "SourceCoverageViewText.h"
15#include "llvm/ADT/Optional.h"
16#include "llvm/ADT/SmallString.h"
17#include "llvm/ADT/StringExtras.h"
18
19using namespace llvm;
20
21Expected<CoveragePrinter::OwnedStream>
22CoveragePrinterText::createViewFile(StringRef Path, bool InToplevel) {
23  return createOutputStream(Path, "txt", InToplevel);
24}
25
26void CoveragePrinterText::closeViewFile(OwnedStream OS) {
27  OS->operator<<('\n');
28}
29
30Error CoveragePrinterText::createIndexFile(ArrayRef<StringRef> SourceFiles) {
31  auto OSOrErr = createOutputStream("index", "txt", /*InToplevel=*/true);
32  if (Error E = OSOrErr.takeError())
33    return E;
34  auto OS = std::move(OSOrErr.get());
35  raw_ostream &OSRef = *OS.get();
36
37  for (StringRef SF : SourceFiles)
38    OSRef << getOutputPath(SF, "txt", /*InToplevel=*/false) << '\n';
39
40  return Error::success();
41}
42
43namespace {
44
45static const unsigned LineCoverageColumnWidth = 7;
46static const unsigned LineNumberColumnWidth = 5;
47
48/// \brief Get the width of the leading columns.
49unsigned getCombinedColumnWidth(const CoverageViewOptions &Opts) {
50  return (Opts.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) +
51         (Opts.ShowLineNumbers ? LineNumberColumnWidth + 1 : 0);
52}
53
54/// \brief The width of the line that is used to divide between the view and
55/// the subviews.
56unsigned getDividerWidth(const CoverageViewOptions &Opts) {
57  return getCombinedColumnWidth(Opts) + 4;
58}
59
60} // anonymous namespace
61
62void SourceCoverageViewText::renderViewHeader(raw_ostream &) {}
63
64void SourceCoverageViewText::renderViewFooter(raw_ostream &) {}
65
66void SourceCoverageViewText::renderSourceName(raw_ostream &OS) {
67  getOptions().colored_ostream(OS, raw_ostream::CYAN) << getSourceName()
68                                                      << ":\n";
69}
70
71void SourceCoverageViewText::renderLinePrefix(raw_ostream &OS,
72                                              unsigned ViewDepth) {
73  for (unsigned I = 0; I < ViewDepth; ++I)
74    OS << "  |";
75}
76
77void SourceCoverageViewText::renderLineSuffix(raw_ostream &, unsigned) {}
78
79void SourceCoverageViewText::renderViewDivider(raw_ostream &OS,
80                                               unsigned ViewDepth) {
81  assert(ViewDepth != 0 && "Cannot render divider at top level");
82  renderLinePrefix(OS, ViewDepth - 1);
83  OS.indent(2);
84  unsigned Length = getDividerWidth(getOptions());
85  for (unsigned I = 0; I < Length; ++I)
86    OS << '-';
87  OS << '\n';
88}
89
90void SourceCoverageViewText::renderLine(
91    raw_ostream &OS, LineRef L,
92    const coverage::CoverageSegment *WrappedSegment,
93    CoverageSegmentArray Segments, unsigned ExpansionCol, unsigned ViewDepth) {
94  StringRef Line = L.Line;
95  unsigned LineNumber = L.LineNo;
96
97  Optional<raw_ostream::Colors> Highlight;
98  SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges;
99
100  // The first segment overlaps from a previous line, so we treat it specially.
101  if (WrappedSegment && WrappedSegment->HasCount && WrappedSegment->Count == 0)
102    Highlight = raw_ostream::RED;
103
104  // Output each segment of the line, possibly highlighted.
105  unsigned Col = 1;
106  for (const auto *S : Segments) {
107    unsigned End = std::min(S->Col, static_cast<unsigned>(Line.size()) + 1);
108    colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
109                    getOptions().Colors && Highlight, /*Bold=*/false,
110                    /*BG=*/true)
111        << Line.substr(Col - 1, End - Col);
112    if (getOptions().Debug && Highlight)
113      HighlightedRanges.push_back(std::make_pair(Col, End));
114    Col = End;
115    if (Col == ExpansionCol)
116      Highlight = raw_ostream::CYAN;
117    else if (S->HasCount && S->Count == 0)
118      Highlight = raw_ostream::RED;
119    else
120      Highlight = None;
121  }
122
123  // Show the rest of the line.
124  colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
125                  getOptions().Colors && Highlight, /*Bold=*/false, /*BG=*/true)
126      << Line.substr(Col - 1, Line.size() - Col + 1);
127  OS << '\n';
128
129  if (getOptions().Debug) {
130    for (const auto &Range : HighlightedRanges)
131      errs() << "Highlighted line " << LineNumber << ", " << Range.first
132             << " -> " << Range.second << '\n';
133    if (Highlight)
134      errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n";
135  }
136}
137
138void SourceCoverageViewText::renderLineCoverageColumn(
139    raw_ostream &OS, const LineCoverageStats &Line) {
140  if (!Line.isMapped()) {
141    OS.indent(LineCoverageColumnWidth) << '|';
142    return;
143  }
144  std::string C = formatCount(Line.ExecutionCount);
145  OS.indent(LineCoverageColumnWidth - C.size());
146  colored_ostream(OS, raw_ostream::MAGENTA,
147                  Line.hasMultipleRegions() && getOptions().Colors)
148      << C;
149  OS << '|';
150}
151
152void SourceCoverageViewText::renderLineNumberColumn(raw_ostream &OS,
153                                                    unsigned LineNo) {
154  SmallString<32> Buffer;
155  raw_svector_ostream BufferOS(Buffer);
156  BufferOS << LineNo;
157  auto Str = BufferOS.str();
158  // Trim and align to the right.
159  Str = Str.substr(0, std::min(Str.size(), (size_t)LineNumberColumnWidth));
160  OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|';
161}
162
163void SourceCoverageViewText::renderRegionMarkers(
164    raw_ostream &OS, CoverageSegmentArray Segments, unsigned ViewDepth) {
165  renderLinePrefix(OS, ViewDepth);
166  OS.indent(getCombinedColumnWidth(getOptions()));
167
168  unsigned PrevColumn = 1;
169  for (const auto *S : Segments) {
170    if (!S->IsRegionEntry)
171      continue;
172    // Skip to the new region.
173    if (S->Col > PrevColumn)
174      OS.indent(S->Col - PrevColumn);
175    PrevColumn = S->Col + 1;
176    std::string C = formatCount(S->Count);
177    PrevColumn += C.size();
178    OS << '^' << C;
179  }
180  OS << '\n';
181
182  if (getOptions().Debug)
183    for (const auto *S : Segments)
184      errs() << "Marker at " << S->Line << ":" << S->Col << " = "
185             << formatCount(S->Count) << (S->IsRegionEntry ? "\n" : " (pop)\n");
186}
187
188void SourceCoverageViewText::renderExpansionSite(
189    raw_ostream &OS, LineRef L, const coverage::CoverageSegment *WrappedSegment,
190    CoverageSegmentArray Segments, unsigned ExpansionCol, unsigned ViewDepth) {
191  renderLinePrefix(OS, ViewDepth);
192  OS.indent(getCombinedColumnWidth(getOptions()) + (ViewDepth == 0 ? 0 : 1));
193  renderLine(OS, L, WrappedSegment, Segments, ExpansionCol, ViewDepth);
194}
195
196void SourceCoverageViewText::renderExpansionView(raw_ostream &OS,
197                                                 ExpansionView &ESV,
198                                                 unsigned ViewDepth) {
199  // Render the child subview.
200  if (getOptions().Debug)
201    errs() << "Expansion at line " << ESV.getLine() << ", " << ESV.getStartCol()
202           << " -> " << ESV.getEndCol() << '\n';
203  ESV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/false,
204                  ViewDepth + 1);
205}
206
207void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS,
208                                                     InstantiationView &ISV,
209                                                     unsigned ViewDepth) {
210  renderLinePrefix(OS, ViewDepth);
211  OS << ' ';
212  ISV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/true, ViewDepth);
213}
214