Coverage Report

Created: 2019-05-19 14:56

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