Coverage Report

Created: 2018-01-17 21:32

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/llvm-cov/SourceCoverageView.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- SourceCoverageView.cpp - Code coverage view for source code --------===//
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 class implements rendering for code coverage of source code.
11
///
12
//===----------------------------------------------------------------------===//
13
14
#include "SourceCoverageView.h"
15
#include "SourceCoverageViewHTML.h"
16
#include "SourceCoverageViewText.h"
17
#include "llvm/ADT/SmallString.h"
18
#include "llvm/ADT/StringExtras.h"
19
#include "llvm/Support/FileSystem.h"
20
#include "llvm/Support/LineIterator.h"
21
#include "llvm/Support/Path.h"
22
23
using namespace llvm;
24
25
97
void CoveragePrinter::StreamDestructor::operator()(raw_ostream *OS) const {
26
97
  if (OS == &outs())
27
40
    return;
28
57
  delete OS;
29
57
}
30
31
std::string CoveragePrinter::getOutputPath(StringRef Path, StringRef Extension,
32
                                           bool InToplevel,
33
96
                                           bool Relative) const {
34
96
  assert(Extension.size() && "The file extension may not be empty");
35
96
36
96
  SmallString<256> FullPath;
37
96
38
96
  if (!Relative)
39
57
    FullPath.append(Opts.ShowOutputDirectory);
40
96
41
96
  if (!InToplevel)
42
71
    sys::path::append(FullPath, getCoverageDir());
43
96
44
96
  SmallString<256> ParentPath = sys::path::parent_path(Path);
45
96
  sys::path::remove_dots(ParentPath, /*remove_dot_dots=*/true);
46
96
  sys::path::append(FullPath, sys::path::relative_path(ParentPath));
47
96
48
96
  auto PathFilename = (sys::path::filename(Path) + "." + Extension).str();
49
96
  sys::path::append(FullPath, PathFilename);
50
96
  sys::path::native(FullPath);
51
96
52
96
  return FullPath.str();
53
96
}
54
55
Expected<CoveragePrinter::OwnedStream>
56
CoveragePrinter::createOutputStream(StringRef Path, StringRef Extension,
57
97
                                    bool InToplevel) const {
58
97
  if (!Opts.hasOutputDirectory())
59
40
    return OwnedStream(&outs());
60
57
61
57
  std::string FullPath = getOutputPath(Path, Extension, InToplevel, false);
62
57
63
57
  auto ParentDir = sys::path::parent_path(FullPath);
64
57
  if (auto E = sys::fs::create_directories(ParentDir))
65
0
    return errorCodeToError(E);
66
57
67
57
  std::error_code E;
68
57
  raw_ostream *RawStream = new raw_fd_ostream(FullPath, E, sys::fs::F_RW);
69
57
  auto OS = CoveragePrinter::OwnedStream(RawStream);
70
57
  if (E)
71
1
    return errorCodeToError(E);
72
56
  return std::move(OS);
73
56
}
74
75
std::unique_ptr<CoveragePrinter>
76
39
CoveragePrinter::create(const CoverageViewOptions &Opts) {
77
39
  switch (Opts.Format) {
78
39
  case CoverageViewOptions::OutputFormat::Text:
79
28
    return llvm::make_unique<CoveragePrinterText>(Opts);
80
39
  case CoverageViewOptions::OutputFormat::HTML:
81
11
    return llvm::make_unique<CoveragePrinterHTML>(Opts);
82
0
  }
83
0
  llvm_unreachable("Unknown coverage output format!");
84
0
}
85
86
72
unsigned SourceCoverageView::getFirstUncoveredLineNo() {
87
436
  const auto MinSegIt = find_if(CoverageInfo, [](const CoverageSegment &S) {
88
436
    return S.HasCount && 
S.Count == 0392
;
89
436
  });
90
72
91
72
  // There is no uncovered line, return zero.
92
72
  if (MinSegIt == CoverageInfo.end())
93
39
    return 0;
94
33
95
33
  return (*MinSegIt).Line;
96
33
}
97
98
987
std::string SourceCoverageView::formatCount(uint64_t N) {
99
987
  std::string Number = utostr(N);
100
987
  int Len = Number.size();
101
987
  if (Len <= 3)
102
729
    return Number;
103
258
  int IntLen = Len % 3 == 0 ? 
360
:
Len % 3198
;
104
258
  std::string Result(Number.data(), IntLen);
105
258
  if (IntLen != 3) {
106
198
    Result.push_back('.');
107
198
    Result += Number.substr(IntLen, 3 - IntLen);
108
198
  }
109
258
  Result.push_back(" kMGTPEZY"[(Len - 1) / 3]);
110
258
  return Result;
111
258
}
112
113
bool SourceCoverageView::shouldRenderRegionMarkers(
114
2.08k
    const LineCoverageStats &LCS) const {
115
2.08k
  if (!getOptions().ShowRegionMarkers)
116
1.97k
    return false;
117
107
118
107
  CoverageSegmentArray Segments = LCS.getLineSegments();
119
107
  if (Segments.empty())
120
57
    return false;
121
94
  
for (unsigned I = 0, E = Segments.size() - 1; 50
I < E;
++I44
) {
122
46
    const auto *CurSeg = Segments[I];
123
46
    if (!CurSeg->IsRegionEntry || 
CurSeg->Count == LCS.getExecutionCount()30
)
124
44
      continue;
125
2
    return true;
126
2
  }
127
50
  
return false48
;
128
50
}
129
130
1.13k
bool SourceCoverageView::hasSubViews() const {
131
1.13k
  return !ExpansionSubViews.empty() || !InstantiationSubViews.empty();
132
1.13k
}
133
134
std::unique_ptr<SourceCoverageView>
135
SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File,
136
                           const CoverageViewOptions &Options,
137
109
                           CoverageData &&CoverageInfo) {
138
109
  switch (Options.Format) {
139
109
  case CoverageViewOptions::OutputFormat::Text:
140
56
    return llvm::make_unique<SourceCoverageViewText>(
141
56
        SourceName, File, Options, std::move(CoverageInfo));
142
109
  case CoverageViewOptions::OutputFormat::HTML:
143
53
    return llvm::make_unique<SourceCoverageViewHTML>(
144
53
        SourceName, File, Options, std::move(CoverageInfo));
145
0
  }
146
0
  llvm_unreachable("Unknown coverage output format!");
147
0
}
148
149
98
std::string SourceCoverageView::getSourceName() const {
150
98
  SmallString<128> SourceText(SourceName);
151
98
  sys::path::remove_dots(SourceText, /*remove_dot_dots=*/true);
152
98
  sys::path::native(SourceText);
153
98
  return SourceText.str();
154
98
}
155
156
void SourceCoverageView::addExpansion(
157
    const CounterMappingRegion &Region,
158
3
    std::unique_ptr<SourceCoverageView> View) {
159
3
  ExpansionSubViews.emplace_back(Region, std::move(View));
160
3
}
161
162
void SourceCoverageView::addInstantiation(
163
    StringRef FunctionName, unsigned Line,
164
36
    std::unique_ptr<SourceCoverageView> View) {
165
36
  InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
166
36
}
167
168
void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
169
                               bool ShowSourceName, bool ShowTitle,
170
109
                               unsigned ViewDepth) {
171
109
  if (ShowTitle)
172
32
    renderTitle(OS, "Coverage Report");
173
109
174
109
  renderViewHeader(OS);
175
109
176
109
  if (ShowSourceName)
177
98
    renderSourceName(OS, WholeFile);
178
109
179
109
  renderTableHeader(OS, (ViewDepth > 0) ? 
037
:
getFirstUncoveredLineNo()72
,
180
109
                    ViewDepth);
181
109
182
109
  // We need the expansions and instantiations sorted so we can go through them
183
109
  // while we iterate lines.
184
109
  std::stable_sort(ExpansionSubViews.begin(), ExpansionSubViews.end());
185
109
  std::stable_sort(InstantiationSubViews.begin(), InstantiationSubViews.end());
186
109
  auto NextESV = ExpansionSubViews.begin();
187
109
  auto EndESV = ExpansionSubViews.end();
188
109
  auto NextISV = InstantiationSubViews.begin();
189
109
  auto EndISV = InstantiationSubViews.end();
190
109
191
109
  // Get the coverage information for the file.
192
109
  auto StartSegment = CoverageInfo.begin();
193
109
  auto EndSegment = CoverageInfo.end();
194
109
  LineCoverageIterator LCI{CoverageInfo, 1};
195
109
  LineCoverageIterator LCIEnd = LCI.getEnd();
196
109
197
109
  unsigned FirstLine = StartSegment != EndSegment ? StartSegment->Line : 
00
;
198
1.76k
  for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof();
199
1.67k
       
++LI, ++LCI1.65k
) {
200
1.67k
    // If we aren't rendering the whole file, we need to filter out the prologue
201
1.67k
    // and epilogue.
202
1.67k
    if (!WholeFile) {
203
504
      if (LCI == LCIEnd)
204
17
        break;
205
487
      else if (LI.line_number() < FirstLine)
206
118
        continue;
207
1.53k
    }
208
1.53k
209
1.53k
    renderLinePrefix(OS, ViewDepth);
210
1.53k
    if (getOptions().ShowLineNumbers)
211
1.53k
      renderLineNumberColumn(OS, LI.line_number());
212
1.53k
213
1.53k
    if (getOptions().ShowLineStats)
214
1.53k
      renderLineCoverageColumn(OS, *LCI);
215
1.53k
216
1.53k
    // If there are expansion subviews, we want to highlight the first one.
217
1.53k
    unsigned ExpansionColumn = 0;
218
1.53k
    if (NextESV != EndESV && 
NextESV->getLine() == LI.line_number()29
&&
219
1.53k
        
getOptions().Colors3
)
220
0
      ExpansionColumn = NextESV->getStartCol();
221
1.53k
222
1.53k
    // Display the source code for the current line.
223
1.53k
    renderLine(OS, {*LI, LI.line_number()}, *LCI, ExpansionColumn, ViewDepth);
224
1.53k
225
1.53k
    // Show the region markers.
226
1.53k
    if (shouldRenderRegionMarkers(*LCI))
227
2
      renderRegionMarkers(OS, *LCI, ViewDepth);
228
1.53k
229
1.53k
    // Show the expansions and instantiations for this line.
230
1.53k
    bool RenderedSubView = false;
231
1.54k
    for (; NextESV != EndESV && 
NextESV->getLine() == LI.line_number()30
;
232
1.53k
         
++NextESV3
) {
233
3
      renderViewDivider(OS, ViewDepth + 1);
234
3
235
3
      // Re-render the current line and highlight the expansion range for
236
3
      // this subview.
237
3
      if (RenderedSubView) {
238
0
        ExpansionColumn = NextESV->getStartCol();
239
0
        renderExpansionSite(OS, {*LI, LI.line_number()}, *LCI, ExpansionColumn,
240
0
                            ViewDepth);
241
0
        renderViewDivider(OS, ViewDepth + 1);
242
0
      }
243
3
244
3
      renderExpansionView(OS, *NextESV, ViewDepth + 1);
245
3
      RenderedSubView = true;
246
3
    }
247
1.57k
    for (; NextISV != EndISV && 
NextISV->Line == LI.line_number()162
;
++NextISV36
) {
248
36
      renderViewDivider(OS, ViewDepth + 1);
249
36
      renderInstantiationView(OS, *NextISV, ViewDepth + 1);
250
36
      RenderedSubView = true;
251
36
    }
252
1.53k
    if (RenderedSubView)
253
18
      renderViewDivider(OS, ViewDepth + 1);
254
1.53k
    renderLineSuffix(OS, ViewDepth);
255
1.53k
  }
256
109
257
109
  renderViewFooter(OS);
258
109
}