blob: 4fdb895cca77e20b0b9f6d3c0b388ca2c74872b9 [file] [log] [blame]
Alex Lorenze82d89c2014-08-22 22:56:03 +00001//===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===//
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// The 'CodeCoverageTool' class implements a command line tool to analyze and
11// report coverage information using the profiling instrumentation and code
12// coverage mapping.
13//
14//===----------------------------------------------------------------------===//
15
Alex Lorenze82d89c2014-08-22 22:56:03 +000016#include "CoverageFilters.h"
Alex Lorenze82d89c2014-08-22 22:56:03 +000017#include "CoverageReport.h"
Chandler Carruthd9903882015-01-14 11:23:27 +000018#include "CoverageViewOptions.h"
Easwaran Ramandc707122016-04-29 18:53:05 +000019#include "RenderingSupport.h"
Chandler Carruthd9903882015-01-14 11:23:27 +000020#include "SourceCoverageView.h"
Alex Lorenze82d89c2014-08-22 22:56:03 +000021#include "llvm/ADT/SmallString.h"
Chandler Carruthd9903882015-01-14 11:23:27 +000022#include "llvm/ADT/StringRef.h"
Justin Bogner43795352015-03-11 02:30:51 +000023#include "llvm/ADT/Triple.h"
Easwaran Ramandc707122016-04-29 18:53:05 +000024#include "llvm/ProfileData/Coverage/CoverageMapping.h"
Chandler Carruthd9903882015-01-14 11:23:27 +000025#include "llvm/ProfileData/InstrProfReader.h"
Alex Lorenze82d89c2014-08-22 22:56:03 +000026#include "llvm/Support/CommandLine.h"
27#include "llvm/Support/FileSystem.h"
Alex Lorenze82d89c2014-08-22 22:56:03 +000028#include "llvm/Support/Format.h"
29#include "llvm/Support/Path.h"
Justin Bognercfb53e42015-03-19 00:02:23 +000030#include "llvm/Support/Process.h"
Alex Lorenze82d89c2014-08-22 22:56:03 +000031#include <functional>
Justin Bognere53be062014-09-09 05:32:18 +000032#include <system_error>
Alex Lorenze82d89c2014-08-22 22:56:03 +000033
34using namespace llvm;
35using namespace coverage;
36
37namespace {
Alex Lorenze82d89c2014-08-22 22:56:03 +000038/// \brief The implementation of the coverage tool.
39class CodeCoverageTool {
40public:
41 enum Command {
42 /// \brief The show command.
43 Show,
44 /// \brief The report command.
45 Report
46 };
47
48 /// \brief Print the error message to the error output stream.
49 void error(const Twine &Message, StringRef Whence = "");
50
Vedant Kumarcef440f2016-06-28 16:12:18 +000051 /// \brief Append a reference to a private copy of \p Path into SourceFiles.
52 void addCollectedPath(const std::string &Path);
53
Alex Lorenze82d89c2014-08-22 22:56:03 +000054 /// \brief Return a memory buffer for the given source file.
55 ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
56
Justin Bogner953e2402014-09-20 15:31:56 +000057 /// \brief Create source views for the expansions of the view.
58 void attachExpansionSubViews(SourceCoverageView &View,
59 ArrayRef<ExpansionRecord> Expansions,
60 CoverageMapping &Coverage);
Alex Lorenze82d89c2014-08-22 22:56:03 +000061
Justin Bogner953e2402014-09-20 15:31:56 +000062 /// \brief Create the source view of a particular function.
Justin Bogner5a6edad2014-09-19 19:07:17 +000063 std::unique_ptr<SourceCoverageView>
Justin Bogner953e2402014-09-20 15:31:56 +000064 createFunctionView(const FunctionRecord &Function, CoverageMapping &Coverage);
Alex Lorenze82d89c2014-08-22 22:56:03 +000065
66 /// \brief Create the main source view of a particular source file.
Justin Bogner5a6edad2014-09-19 19:07:17 +000067 std::unique_ptr<SourceCoverageView>
Justin Bogner953e2402014-09-20 15:31:56 +000068 createSourceFileView(StringRef SourceFile, CoverageMapping &Coverage);
Alex Lorenze82d89c2014-08-22 22:56:03 +000069
70 /// \brief Load the coverage mapping data. Return true if an error occured.
Justin Bogner953e2402014-09-20 15:31:56 +000071 std::unique_ptr<CoverageMapping> load();
Alex Lorenze82d89c2014-08-22 22:56:03 +000072
73 int run(Command Cmd, int argc, const char **argv);
74
Benjamin Kramerc321e532016-06-08 19:09:22 +000075 typedef llvm::function_ref<int(int, const char **)> CommandLineParserType;
Alex Lorenze82d89c2014-08-22 22:56:03 +000076
77 int show(int argc, const char **argv,
78 CommandLineParserType commandLineParser);
79
80 int report(int argc, const char **argv,
81 CommandLineParserType commandLineParser);
82
Justin Bognerf6c50552014-10-30 20:51:24 +000083 std::string ObjectFilename;
Alex Lorenze82d89c2014-08-22 22:56:03 +000084 CoverageViewOptions ViewOpts;
Justin Bogner953e2402014-09-20 15:31:56 +000085 std::string PGOFilename;
Alex Lorenze82d89c2014-08-22 22:56:03 +000086 CoverageFiltersMatchAll Filters;
Vedant Kumarcef440f2016-06-28 16:12:18 +000087 std::vector<StringRef> SourceFiles;
Alex Lorenze82d89c2014-08-22 22:56:03 +000088 std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
89 LoadedSourceFiles;
Alex Lorenze82d89c2014-08-22 22:56:03 +000090 bool CompareFilenamesOnly;
Justin Bogner116c1662014-09-19 08:13:12 +000091 StringMap<std::string> RemappedFilenames;
Frederic Rissebc162a2015-06-22 21:33:24 +000092 std::string CoverageArch;
Vedant Kumarcef440f2016-06-28 16:12:18 +000093
94private:
95 std::vector<std::string> CollectedPaths;
Alex Lorenze82d89c2014-08-22 22:56:03 +000096};
97}
98
99void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
100 errs() << "error: ";
101 if (!Whence.empty())
102 errs() << Whence << ": ";
103 errs() << Message << "\n";
104}
105
Vedant Kumarcef440f2016-06-28 16:12:18 +0000106void CodeCoverageTool::addCollectedPath(const std::string &Path) {
107 CollectedPaths.push_back(Path);
108 SourceFiles.emplace_back(CollectedPaths.back());
109}
110
Alex Lorenze82d89c2014-08-22 22:56:03 +0000111ErrorOr<const MemoryBuffer &>
112CodeCoverageTool::getSourceFile(StringRef SourceFile) {
Justin Bogner116c1662014-09-19 08:13:12 +0000113 // If we've remapped filenames, look up the real location for this file.
114 if (!RemappedFilenames.empty()) {
115 auto Loc = RemappedFilenames.find(SourceFile);
116 if (Loc != RemappedFilenames.end())
117 SourceFile = Loc->second;
Alex Lorenze82d89c2014-08-22 22:56:03 +0000118 }
Justin Bogner116c1662014-09-19 08:13:12 +0000119 for (const auto &Files : LoadedSourceFiles)
120 if (sys::fs::equivalent(SourceFile, Files.first))
121 return *Files.second;
Alex Lorenze82d89c2014-08-22 22:56:03 +0000122 auto Buffer = MemoryBuffer::getFile(SourceFile);
123 if (auto EC = Buffer.getError()) {
124 error(EC.message(), SourceFile);
125 return EC;
126 }
Benjamin Kramerf5e2fc42015-05-29 19:43:39 +0000127 LoadedSourceFiles.emplace_back(SourceFile, std::move(Buffer.get()));
Alex Lorenze82d89c2014-08-22 22:56:03 +0000128 return *LoadedSourceFiles.back().second;
129}
130
Justin Bogner953e2402014-09-20 15:31:56 +0000131void
132CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View,
133 ArrayRef<ExpansionRecord> Expansions,
134 CoverageMapping &Coverage) {
Alex Lorenze82d89c2014-08-22 22:56:03 +0000135 if (!ViewOpts.ShowExpandedRegions)
136 return;
Justin Bogner953e2402014-09-20 15:31:56 +0000137 for (const auto &Expansion : Expansions) {
138 auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
139 if (ExpansionCoverage.empty())
Alex Lorenze82d89c2014-08-22 22:56:03 +0000140 continue;
Justin Bogner953e2402014-09-20 15:31:56 +0000141 auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
142 if (!SourceBuffer)
Alex Lorenze82d89c2014-08-22 22:56:03 +0000143 continue;
Justin Bogner953e2402014-09-20 15:31:56 +0000144
145 auto SubViewExpansions = ExpansionCoverage.getExpansions();
Vedant Kumarf9151b92016-06-25 02:58:30 +0000146 auto SubView =
147 SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(),
148 ViewOpts, std::move(ExpansionCoverage));
Justin Bogner953e2402014-09-20 15:31:56 +0000149 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
150 View.addExpansion(Expansion.Region, std::move(SubView));
Alex Lorenze82d89c2014-08-22 22:56:03 +0000151 }
152}
153
Justin Bogner5a6edad2014-09-19 19:07:17 +0000154std::unique_ptr<SourceCoverageView>
Justin Bogner953e2402014-09-20 15:31:56 +0000155CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
156 CoverageMapping &Coverage) {
157 auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
158 if (FunctionCoverage.empty())
Justin Bogner5a6edad2014-09-19 19:07:17 +0000159 return nullptr;
Justin Bogner953e2402014-09-20 15:31:56 +0000160 auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
Justin Bogner5a6edad2014-09-19 19:07:17 +0000161 if (!SourceBuffer)
162 return nullptr;
Justin Bogner953e2402014-09-20 15:31:56 +0000163
164 auto Expansions = FunctionCoverage.getExpansions();
Vedant Kumarf9151b92016-06-25 02:58:30 +0000165 auto View = SourceCoverageView::create(Function.Name, SourceBuffer.get(),
166 ViewOpts, std::move(FunctionCoverage));
Justin Bogner953e2402014-09-20 15:31:56 +0000167 attachExpansionSubViews(*View, Expansions, Coverage);
168
169 return View;
Alex Lorenze82d89c2014-08-22 22:56:03 +0000170}
171
Justin Bogner953e2402014-09-20 15:31:56 +0000172std::unique_ptr<SourceCoverageView>
173CodeCoverageTool::createSourceFileView(StringRef SourceFile,
174 CoverageMapping &Coverage) {
Justin Bogner5a6edad2014-09-19 19:07:17 +0000175 auto SourceBuffer = getSourceFile(SourceFile);
176 if (!SourceBuffer)
177 return nullptr;
Justin Bogner953e2402014-09-20 15:31:56 +0000178 auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
179 if (FileCoverage.empty())
Justin Bogner5a6edad2014-09-19 19:07:17 +0000180 return nullptr;
Justin Bogner953e2402014-09-20 15:31:56 +0000181
182 auto Expansions = FileCoverage.getExpansions();
Vedant Kumarf9151b92016-06-25 02:58:30 +0000183 auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
184 ViewOpts, std::move(FileCoverage));
Justin Bogner953e2402014-09-20 15:31:56 +0000185 attachExpansionSubViews(*View, Expansions, Coverage);
186
187 for (auto Function : Coverage.getInstantiations(SourceFile)) {
188 auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
189 auto SubViewExpansions = SubViewCoverage.getExpansions();
Vedant Kumarf9151b92016-06-25 02:58:30 +0000190 auto SubView =
191 SourceCoverageView::create(Function->Name, SourceBuffer.get(), ViewOpts,
192 std::move(SubViewCoverage));
Justin Bogner953e2402014-09-20 15:31:56 +0000193 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
194
195 if (SubView) {
Justin Bogner5e1400a2014-09-17 05:33:20 +0000196 unsigned FileID = Function->CountedRegions.front().FileID;
197 unsigned Line = 0;
198 for (const auto &CR : Function->CountedRegions)
199 if (CR.FileID == FileID)
200 Line = std::max(CR.LineEnd, Line);
Justin Bogner953e2402014-09-20 15:31:56 +0000201 View->addInstantiation(Function->Name, Line, std::move(SubView));
Alex Lorenze82d89c2014-08-22 22:56:03 +0000202 }
203 }
Justin Bogner5a6edad2014-09-19 19:07:17 +0000204 return View;
Alex Lorenze82d89c2014-08-22 22:56:03 +0000205}
206
Justin Bogner65337d12015-05-04 04:09:38 +0000207static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
208 sys::fs::file_status Status;
209 if (sys::fs::status(LHS, Status))
210 return false;
211 auto LHSTime = Status.getLastModificationTime();
212 if (sys::fs::status(RHS, Status))
213 return false;
214 auto RHSTime = Status.getLastModificationTime();
215 return LHSTime > RHSTime;
216}
217
Justin Bogner953e2402014-09-20 15:31:56 +0000218std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
Justin Bogner65337d12015-05-04 04:09:38 +0000219 if (modifiedTimeGT(ObjectFilename, PGOFilename))
220 errs() << "warning: profile data may be out of date - object is newer\n";
Justin Bogner43795352015-03-11 02:30:51 +0000221 auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename,
222 CoverageArch);
Vedant Kumar9152fd12016-05-19 03:54:45 +0000223 if (Error E = CoverageOrErr.takeError()) {
Justin Bogner953e2402014-09-20 15:31:56 +0000224 colored_ostream(errs(), raw_ostream::RED)
Vedant Kumar9152fd12016-05-19 03:54:45 +0000225 << "error: Failed to load coverage: " << toString(std::move(E)) << "\n";
Justin Bogner953e2402014-09-20 15:31:56 +0000226 return nullptr;
227 }
228 auto Coverage = std::move(CoverageOrErr.get());
229 unsigned Mismatched = Coverage->getMismatchedCount();
230 if (Mismatched) {
231 colored_ostream(errs(), raw_ostream::RED)
232 << "warning: " << Mismatched << " functions have mismatched data. ";
233 errs() << "\n";
Alex Lorenze82d89c2014-08-22 22:56:03 +0000234 }
Justin Bogner116c1662014-09-19 08:13:12 +0000235
236 if (CompareFilenamesOnly) {
Justin Bogner953e2402014-09-20 15:31:56 +0000237 auto CoveredFiles = Coverage.get()->getUniqueSourceFiles();
Justin Bogner116c1662014-09-19 08:13:12 +0000238 for (auto &SF : SourceFiles) {
239 StringRef SFBase = sys::path::filename(SF);
240 for (const auto &CF : CoveredFiles)
241 if (SFBase == sys::path::filename(CF)) {
242 RemappedFilenames[CF] = SF;
243 SF = CF;
244 break;
245 }
246 }
247 }
248
Justin Bogner953e2402014-09-20 15:31:56 +0000249 return Coverage;
Alex Lorenze82d89c2014-08-22 22:56:03 +0000250}
251
252int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
Justin Bognerf6c50552014-10-30 20:51:24 +0000253 cl::opt<std::string, true> ObjectFilename(
254 cl::Positional, cl::Required, cl::location(this->ObjectFilename),
255 cl::desc("Covered executable or object file."));
256
Alex Lorenze82d89c2014-08-22 22:56:03 +0000257 cl::list<std::string> InputSourceFiles(
258 cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
259
Justin Bogner953e2402014-09-20 15:31:56 +0000260 cl::opt<std::string, true> PGOFilename(
261 "instr-profile", cl::Required, cl::location(this->PGOFilename),
Alex Lorenze82d89c2014-08-22 22:56:03 +0000262 cl::desc(
263 "File with the profile data obtained after an instrumented run"));
264
Justin Bogner43795352015-03-11 02:30:51 +0000265 cl::opt<std::string> Arch(
266 "arch", cl::desc("architecture of the coverage mapping binary"));
267
Alex Lorenze82d89c2014-08-22 22:56:03 +0000268 cl::opt<bool> DebugDump("dump", cl::Optional,
269 cl::desc("Show internal debug dump"));
270
Vedant Kumar8d74cb22016-06-29 00:38:21 +0000271 cl::opt<CoverageViewOptions::OutputFormat> Format(
272 "format", cl::desc("Output format for line-based coverage reports"),
273 cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
274 "Text output"),
275 clEnumValEnd),
276 cl::init(CoverageViewOptions::OutputFormat::Text));
277
Alex Lorenze82d89c2014-08-22 22:56:03 +0000278 cl::opt<bool> FilenameEquivalence(
279 "filename-equivalence", cl::Optional,
Justin Bogner116c1662014-09-19 08:13:12 +0000280 cl::desc("Treat source files as equivalent to paths in the coverage data "
281 "when the file names match, even if the full paths do not"));
Alex Lorenze82d89c2014-08-22 22:56:03 +0000282
283 cl::OptionCategory FilteringCategory("Function filtering options");
284
285 cl::list<std::string> NameFilters(
286 "name", cl::Optional,
287 cl::desc("Show code coverage only for functions with the given name"),
288 cl::ZeroOrMore, cl::cat(FilteringCategory));
289
290 cl::list<std::string> NameRegexFilters(
291 "name-regex", cl::Optional,
292 cl::desc("Show code coverage only for functions that match the given "
293 "regular expression"),
294 cl::ZeroOrMore, cl::cat(FilteringCategory));
295
296 cl::opt<double> RegionCoverageLtFilter(
297 "region-coverage-lt", cl::Optional,
298 cl::desc("Show code coverage only for functions with region coverage "
299 "less than the given threshold"),
300 cl::cat(FilteringCategory));
301
302 cl::opt<double> RegionCoverageGtFilter(
303 "region-coverage-gt", cl::Optional,
304 cl::desc("Show code coverage only for functions with region coverage "
305 "greater than the given threshold"),
306 cl::cat(FilteringCategory));
307
308 cl::opt<double> LineCoverageLtFilter(
309 "line-coverage-lt", cl::Optional,
310 cl::desc("Show code coverage only for functions with line coverage less "
311 "than the given threshold"),
312 cl::cat(FilteringCategory));
313
314 cl::opt<double> LineCoverageGtFilter(
315 "line-coverage-gt", cl::Optional,
316 cl::desc("Show code coverage only for functions with line coverage "
317 "greater than the given threshold"),
318 cl::cat(FilteringCategory));
319
Justin Bogner9deb1d42015-03-19 04:45:16 +0000320 cl::opt<cl::boolOrDefault> UseColor(
321 "use-color", cl::desc("Emit colored output (default=autodetect)"),
322 cl::init(cl::BOU_UNSET));
Justin Bognercfb53e42015-03-19 00:02:23 +0000323
Alex Lorenze82d89c2014-08-22 22:56:03 +0000324 auto commandLineParser = [&, this](int argc, const char **argv) -> int {
325 cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
326 ViewOpts.Debug = DebugDump;
327 CompareFilenamesOnly = FilenameEquivalence;
328
Vedant Kumar8d74cb22016-06-29 00:38:21 +0000329 ViewOpts.Format = Format;
330 switch (ViewOpts.Format) {
331 case CoverageViewOptions::OutputFormat::Text:
332 ViewOpts.Colors = UseColor == cl::BOU_UNSET
333 ? sys::Process::StandardOutHasColors()
334 : UseColor == cl::BOU_TRUE;
335 break;
336 }
Justin Bognercfb53e42015-03-19 00:02:23 +0000337
Alex Lorenze82d89c2014-08-22 22:56:03 +0000338 // Create the function filters
339 if (!NameFilters.empty() || !NameRegexFilters.empty()) {
340 auto NameFilterer = new CoverageFilters;
341 for (const auto &Name : NameFilters)
342 NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
343 for (const auto &Regex : NameRegexFilters)
344 NameFilterer->push_back(
345 llvm::make_unique<NameRegexCoverageFilter>(Regex));
346 Filters.push_back(std::unique_ptr<CoverageFilter>(NameFilterer));
347 }
348 if (RegionCoverageLtFilter.getNumOccurrences() ||
349 RegionCoverageGtFilter.getNumOccurrences() ||
350 LineCoverageLtFilter.getNumOccurrences() ||
351 LineCoverageGtFilter.getNumOccurrences()) {
352 auto StatFilterer = new CoverageFilters;
353 if (RegionCoverageLtFilter.getNumOccurrences())
354 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
355 RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
356 if (RegionCoverageGtFilter.getNumOccurrences())
357 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
358 RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
359 if (LineCoverageLtFilter.getNumOccurrences())
360 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
361 LineCoverageFilter::LessThan, LineCoverageLtFilter));
362 if (LineCoverageGtFilter.getNumOccurrences())
363 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
364 RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
365 Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
366 }
367
Frederic Rissebc162a2015-06-22 21:33:24 +0000368 if (!Arch.empty() &&
369 Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
370 errs() << "error: Unknown architecture: " << Arch << "\n";
371 return 1;
Justin Bogner43795352015-03-11 02:30:51 +0000372 }
Frederic Rissebc162a2015-06-22 21:33:24 +0000373 CoverageArch = Arch;
Justin Bogner43795352015-03-11 02:30:51 +0000374
Justin Bogner116c1662014-09-19 08:13:12 +0000375 for (const auto &File : InputSourceFiles) {
376 SmallString<128> Path(File);
Justin Bogner0ef7a2a2015-02-14 02:05:05 +0000377 if (!CompareFilenamesOnly)
378 if (std::error_code EC = sys::fs::make_absolute(Path)) {
379 errs() << "error: " << File << ": " << EC.message();
380 return 1;
381 }
Vedant Kumarcef440f2016-06-28 16:12:18 +0000382 addCollectedPath(Path.str());
Justin Bogner116c1662014-09-19 08:13:12 +0000383 }
Alex Lorenze82d89c2014-08-22 22:56:03 +0000384 return 0;
385 };
386
Alex Lorenze82d89c2014-08-22 22:56:03 +0000387 switch (Cmd) {
388 case Show:
389 return show(argc, argv, commandLineParser);
390 case Report:
391 return report(argc, argv, commandLineParser);
392 }
393 return 0;
394}
395
396int CodeCoverageTool::show(int argc, const char **argv,
397 CommandLineParserType commandLineParser) {
398
399 cl::OptionCategory ViewCategory("Viewing options");
400
401 cl::opt<bool> ShowLineExecutionCounts(
402 "show-line-counts", cl::Optional,
403 cl::desc("Show the execution counts for each line"), cl::init(true),
404 cl::cat(ViewCategory));
405
406 cl::opt<bool> ShowRegions(
407 "show-regions", cl::Optional,
408 cl::desc("Show the execution counts for each region"),
409 cl::cat(ViewCategory));
410
411 cl::opt<bool> ShowBestLineRegionsCounts(
412 "show-line-counts-or-regions", cl::Optional,
413 cl::desc("Show the execution counts for each line, or the execution "
414 "counts for each region on lines that have multiple regions"),
415 cl::cat(ViewCategory));
416
417 cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
418 cl::desc("Show expanded source regions"),
419 cl::cat(ViewCategory));
420
421 cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
422 cl::desc("Show function instantiations"),
423 cl::cat(ViewCategory));
424
Vedant Kumar7937ef32016-06-28 02:09:39 +0000425 cl::opt<std::string> ShowOutputDirectory(
426 "output-dir", cl::init(""),
427 cl::desc("Directory in which coverage information is written out"));
428 cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
429 cl::aliasopt(ShowOutputDirectory));
430
Alex Lorenze82d89c2014-08-22 22:56:03 +0000431 auto Err = commandLineParser(argc, argv);
432 if (Err)
433 return Err;
434
Alex Lorenze82d89c2014-08-22 22:56:03 +0000435 ViewOpts.ShowLineNumbers = true;
436 ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
437 !ShowRegions || ShowBestLineRegionsCounts;
438 ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
439 ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts;
440 ViewOpts.ShowExpandedRegions = ShowExpansions;
441 ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
Vedant Kumar7937ef32016-06-28 02:09:39 +0000442 ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
443
Vedant Kumar64d8a022016-06-28 16:12:20 +0000444 if (ViewOpts.hasOutputDirectory()) {
Vedant Kumar7937ef32016-06-28 02:09:39 +0000445 if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
446 error("Could not create output directory!", E.message());
447 return 1;
448 }
449 }
Alex Lorenze82d89c2014-08-22 22:56:03 +0000450
Justin Bogner953e2402014-09-20 15:31:56 +0000451 auto Coverage = load();
452 if (!Coverage)
Alex Lorenze82d89c2014-08-22 22:56:03 +0000453 return 1;
454
Vedant Kumar9cbad2c2016-06-28 16:12:24 +0000455 auto Printer = CoveragePrinter::create(ViewOpts);
456
Alex Lorenze82d89c2014-08-22 22:56:03 +0000457 if (!Filters.empty()) {
Vedant Kumar8d74cb22016-06-29 00:38:21 +0000458 auto OSOrErr = Printer->createViewFile("functions", /*InToplevel=*/true);
459 if (Error E = OSOrErr.takeError()) {
460 error(toString(std::move(E)));
461 return 1;
462 }
463 auto OS = std::move(OSOrErr.get());
464
465 // Show functions.
Justin Bogner953e2402014-09-20 15:31:56 +0000466 for (const auto &Function : Coverage->getCoveredFunctions()) {
467 if (!Filters.matches(Function))
Alex Lorenze82d89c2014-08-22 22:56:03 +0000468 continue;
Justin Bogner953e2402014-09-20 15:31:56 +0000469
470 auto mainView = createFunctionView(Function, *Coverage);
Justin Bogner5a6edad2014-09-19 19:07:17 +0000471 if (!mainView) {
Vedant Kumar2c96e882016-06-24 02:33:01 +0000472 ViewOpts.colored_ostream(errs(), raw_ostream::RED)
473 << "warning: Could not read coverage for '" << Function.Name << "'."
474 << "\n";
Justin Bogner5a6edad2014-09-19 19:07:17 +0000475 continue;
476 }
Vedant Kumar7937ef32016-06-28 02:09:39 +0000477
Vedant Kumar7937ef32016-06-28 02:09:39 +0000478 mainView->print(*OS.get(), /*WholeFile=*/false, /*ShowSourceName=*/true);
Alex Lorenze82d89c2014-08-22 22:56:03 +0000479 }
Vedant Kumar8d74cb22016-06-29 00:38:21 +0000480
481 Printer->closeViewFile(std::move(OS));
Alex Lorenze82d89c2014-08-22 22:56:03 +0000482 return 0;
483 }
484
485 // Show files
486 bool ShowFilenames = SourceFiles.size() != 1;
487
Justin Bogner116c1662014-09-19 08:13:12 +0000488 if (SourceFiles.empty())
Vedant Kumar64d8a022016-06-28 16:12:20 +0000489 // Get the source files from the function coverage mapping.
Justin Bogner953e2402014-09-20 15:31:56 +0000490 for (StringRef Filename : Coverage->getUniqueSourceFiles())
Alex Lorenze82d89c2014-08-22 22:56:03 +0000491 SourceFiles.push_back(Filename);
Alex Lorenze82d89c2014-08-22 22:56:03 +0000492
Vedant Kumar9cbad2c2016-06-28 16:12:24 +0000493 // Create an index out of the source files.
494 if (ViewOpts.hasOutputDirectory()) {
495 if (Error E = Printer->createIndexFile(SourceFiles)) {
496 error(toString(std::move(E)));
497 return 1;
498 }
499 }
500
Alex Lorenze82d89c2014-08-22 22:56:03 +0000501 for (const auto &SourceFile : SourceFiles) {
Justin Bogner953e2402014-09-20 15:31:56 +0000502 auto mainView = createSourceFileView(SourceFile, *Coverage);
Justin Bogner5a6edad2014-09-19 19:07:17 +0000503 if (!mainView) {
Vedant Kumar2c96e882016-06-24 02:33:01 +0000504 ViewOpts.colored_ostream(errs(), raw_ostream::RED)
Alex Lorenze82d89c2014-08-22 22:56:03 +0000505 << "warning: The file '" << SourceFile << "' isn't covered.";
Vedant Kumar2c96e882016-06-24 02:33:01 +0000506 errs() << "\n";
Alex Lorenze82d89c2014-08-22 22:56:03 +0000507 continue;
508 }
509
Vedant Kumar9cbad2c2016-06-28 16:12:24 +0000510 auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
Vedant Kumar7937ef32016-06-28 02:09:39 +0000511 if (Error E = OSOrErr.takeError()) {
Vedant Kumar72e0fe92016-06-28 03:37:56 +0000512 error(toString(std::move(E)));
Vedant Kumar7937ef32016-06-28 02:09:39 +0000513 return 1;
514 }
515 auto OS = std::move(OSOrErr.get());
516 mainView->print(*OS.get(), /*Wholefile=*/true,
Vedant Kumar727549e2016-06-28 00:18:51 +0000517 /*ShowSourceName=*/ShowFilenames);
Vedant Kumar9cbad2c2016-06-28 16:12:24 +0000518 Printer->closeViewFile(std::move(OS));
Alex Lorenze82d89c2014-08-22 22:56:03 +0000519 }
520
521 return 0;
522}
523
524int CodeCoverageTool::report(int argc, const char **argv,
525 CommandLineParserType commandLineParser) {
Alex Lorenze82d89c2014-08-22 22:56:03 +0000526 auto Err = commandLineParser(argc, argv);
527 if (Err)
528 return Err;
529
Justin Bogner953e2402014-09-20 15:31:56 +0000530 auto Coverage = load();
531 if (!Coverage)
Alex Lorenze82d89c2014-08-22 22:56:03 +0000532 return 1;
533
Justin Bognerf91bc6c2015-02-14 02:01:24 +0000534 CoverageReport Report(ViewOpts, std::move(Coverage));
Justin Bogner0ef7a2a2015-02-14 02:05:05 +0000535 if (SourceFiles.empty())
Alex Lorenze82d89c2014-08-22 22:56:03 +0000536 Report.renderFileReports(llvm::outs());
Justin Bogner0ef7a2a2015-02-14 02:05:05 +0000537 else
538 Report.renderFunctionReports(SourceFiles, llvm::outs());
Alex Lorenze82d89c2014-08-22 22:56:03 +0000539 return 0;
540}
541
Justin Bognerd249a3b2014-10-30 20:57:49 +0000542int showMain(int argc, const char *argv[]) {
Alex Lorenze82d89c2014-08-22 22:56:03 +0000543 CodeCoverageTool Tool;
544 return Tool.run(CodeCoverageTool::Show, argc, argv);
545}
546
Justin Bognerd249a3b2014-10-30 20:57:49 +0000547int reportMain(int argc, const char *argv[]) {
Alex Lorenze82d89c2014-08-22 22:56:03 +0000548 CodeCoverageTool Tool;
549 return Tool.run(CodeCoverageTool::Report, argc, argv);
550}