blob: 270a3408b7cf56510aefe3daeb3f32cb8ed5fb22 [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
271 cl::opt<bool> FilenameEquivalence(
272 "filename-equivalence", cl::Optional,
Justin Bogner116c1662014-09-19 08:13:12 +0000273 cl::desc("Treat source files as equivalent to paths in the coverage data "
274 "when the file names match, even if the full paths do not"));
Alex Lorenze82d89c2014-08-22 22:56:03 +0000275
276 cl::OptionCategory FilteringCategory("Function filtering options");
277
278 cl::list<std::string> NameFilters(
279 "name", cl::Optional,
280 cl::desc("Show code coverage only for functions with the given name"),
281 cl::ZeroOrMore, cl::cat(FilteringCategory));
282
283 cl::list<std::string> NameRegexFilters(
284 "name-regex", cl::Optional,
285 cl::desc("Show code coverage only for functions that match the given "
286 "regular expression"),
287 cl::ZeroOrMore, cl::cat(FilteringCategory));
288
289 cl::opt<double> RegionCoverageLtFilter(
290 "region-coverage-lt", cl::Optional,
291 cl::desc("Show code coverage only for functions with region coverage "
292 "less than the given threshold"),
293 cl::cat(FilteringCategory));
294
295 cl::opt<double> RegionCoverageGtFilter(
296 "region-coverage-gt", cl::Optional,
297 cl::desc("Show code coverage only for functions with region coverage "
298 "greater than the given threshold"),
299 cl::cat(FilteringCategory));
300
301 cl::opt<double> LineCoverageLtFilter(
302 "line-coverage-lt", cl::Optional,
303 cl::desc("Show code coverage only for functions with line coverage less "
304 "than the given threshold"),
305 cl::cat(FilteringCategory));
306
307 cl::opt<double> LineCoverageGtFilter(
308 "line-coverage-gt", cl::Optional,
309 cl::desc("Show code coverage only for functions with line coverage "
310 "greater than the given threshold"),
311 cl::cat(FilteringCategory));
312
Justin Bogner9deb1d42015-03-19 04:45:16 +0000313 cl::opt<cl::boolOrDefault> UseColor(
314 "use-color", cl::desc("Emit colored output (default=autodetect)"),
315 cl::init(cl::BOU_UNSET));
Justin Bognercfb53e42015-03-19 00:02:23 +0000316
Alex Lorenze82d89c2014-08-22 22:56:03 +0000317 auto commandLineParser = [&, this](int argc, const char **argv) -> int {
318 cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
319 ViewOpts.Debug = DebugDump;
320 CompareFilenamesOnly = FilenameEquivalence;
321
Justin Bogner9deb1d42015-03-19 04:45:16 +0000322 ViewOpts.Colors = UseColor == cl::BOU_UNSET
323 ? sys::Process::StandardOutHasColors()
324 : UseColor == cl::BOU_TRUE;
Justin Bognercfb53e42015-03-19 00:02:23 +0000325
Alex Lorenze82d89c2014-08-22 22:56:03 +0000326 // Create the function filters
327 if (!NameFilters.empty() || !NameRegexFilters.empty()) {
328 auto NameFilterer = new CoverageFilters;
329 for (const auto &Name : NameFilters)
330 NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
331 for (const auto &Regex : NameRegexFilters)
332 NameFilterer->push_back(
333 llvm::make_unique<NameRegexCoverageFilter>(Regex));
334 Filters.push_back(std::unique_ptr<CoverageFilter>(NameFilterer));
335 }
336 if (RegionCoverageLtFilter.getNumOccurrences() ||
337 RegionCoverageGtFilter.getNumOccurrences() ||
338 LineCoverageLtFilter.getNumOccurrences() ||
339 LineCoverageGtFilter.getNumOccurrences()) {
340 auto StatFilterer = new CoverageFilters;
341 if (RegionCoverageLtFilter.getNumOccurrences())
342 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
343 RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
344 if (RegionCoverageGtFilter.getNumOccurrences())
345 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
346 RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
347 if (LineCoverageLtFilter.getNumOccurrences())
348 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
349 LineCoverageFilter::LessThan, LineCoverageLtFilter));
350 if (LineCoverageGtFilter.getNumOccurrences())
351 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
352 RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
353 Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
354 }
355
Frederic Rissebc162a2015-06-22 21:33:24 +0000356 if (!Arch.empty() &&
357 Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
358 errs() << "error: Unknown architecture: " << Arch << "\n";
359 return 1;
Justin Bogner43795352015-03-11 02:30:51 +0000360 }
Frederic Rissebc162a2015-06-22 21:33:24 +0000361 CoverageArch = Arch;
Justin Bogner43795352015-03-11 02:30:51 +0000362
Justin Bogner116c1662014-09-19 08:13:12 +0000363 for (const auto &File : InputSourceFiles) {
364 SmallString<128> Path(File);
Justin Bogner0ef7a2a2015-02-14 02:05:05 +0000365 if (!CompareFilenamesOnly)
366 if (std::error_code EC = sys::fs::make_absolute(Path)) {
367 errs() << "error: " << File << ": " << EC.message();
368 return 1;
369 }
Vedant Kumarcef440f2016-06-28 16:12:18 +0000370 addCollectedPath(Path.str());
Justin Bogner116c1662014-09-19 08:13:12 +0000371 }
Alex Lorenze82d89c2014-08-22 22:56:03 +0000372 return 0;
373 };
374
Alex Lorenze82d89c2014-08-22 22:56:03 +0000375 switch (Cmd) {
376 case Show:
377 return show(argc, argv, commandLineParser);
378 case Report:
379 return report(argc, argv, commandLineParser);
380 }
381 return 0;
382}
383
384int CodeCoverageTool::show(int argc, const char **argv,
385 CommandLineParserType commandLineParser) {
386
387 cl::OptionCategory ViewCategory("Viewing options");
388
389 cl::opt<bool> ShowLineExecutionCounts(
390 "show-line-counts", cl::Optional,
391 cl::desc("Show the execution counts for each line"), cl::init(true),
392 cl::cat(ViewCategory));
393
394 cl::opt<bool> ShowRegions(
395 "show-regions", cl::Optional,
396 cl::desc("Show the execution counts for each region"),
397 cl::cat(ViewCategory));
398
399 cl::opt<bool> ShowBestLineRegionsCounts(
400 "show-line-counts-or-regions", cl::Optional,
401 cl::desc("Show the execution counts for each line, or the execution "
402 "counts for each region on lines that have multiple regions"),
403 cl::cat(ViewCategory));
404
405 cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
406 cl::desc("Show expanded source regions"),
407 cl::cat(ViewCategory));
408
409 cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
410 cl::desc("Show function instantiations"),
411 cl::cat(ViewCategory));
412
Vedant Kumarebe84012016-06-28 16:12:15 +0000413 cl::opt<CoverageViewOptions::OutputFormat> Format(
Vedant Kumar635c83c2016-06-28 00:15:54 +0000414 "format", cl::desc("Output format for line-based coverage reports"),
415 cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
416 "Text output"),
417 clEnumValEnd),
418 cl::init(CoverageViewOptions::OutputFormat::Text));
419
Vedant Kumar7937ef32016-06-28 02:09:39 +0000420 cl::opt<std::string> ShowOutputDirectory(
421 "output-dir", cl::init(""),
422 cl::desc("Directory in which coverage information is written out"));
423 cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
424 cl::aliasopt(ShowOutputDirectory));
425
Alex Lorenze82d89c2014-08-22 22:56:03 +0000426 auto Err = commandLineParser(argc, argv);
427 if (Err)
428 return Err;
429
Alex Lorenze82d89c2014-08-22 22:56:03 +0000430 ViewOpts.ShowLineNumbers = true;
431 ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
432 !ShowRegions || ShowBestLineRegionsCounts;
433 ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
434 ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts;
435 ViewOpts.ShowExpandedRegions = ShowExpansions;
436 ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
Vedant Kumarebe84012016-06-28 16:12:15 +0000437 ViewOpts.Format = Format;
Vedant Kumar7937ef32016-06-28 02:09:39 +0000438 ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
439
440 if (ViewOpts.ShowOutputDirectory != "") {
441 if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
442 error("Could not create output directory!", E.message());
443 return 1;
444 }
445 }
Alex Lorenze82d89c2014-08-22 22:56:03 +0000446
Justin Bogner953e2402014-09-20 15:31:56 +0000447 auto Coverage = load();
448 if (!Coverage)
Alex Lorenze82d89c2014-08-22 22:56:03 +0000449 return 1;
450
451 if (!Filters.empty()) {
452 // Show functions
Justin Bogner953e2402014-09-20 15:31:56 +0000453 for (const auto &Function : Coverage->getCoveredFunctions()) {
454 if (!Filters.matches(Function))
Alex Lorenze82d89c2014-08-22 22:56:03 +0000455 continue;
Justin Bogner953e2402014-09-20 15:31:56 +0000456
457 auto mainView = createFunctionView(Function, *Coverage);
Justin Bogner5a6edad2014-09-19 19:07:17 +0000458 if (!mainView) {
Vedant Kumar2c96e882016-06-24 02:33:01 +0000459 ViewOpts.colored_ostream(errs(), raw_ostream::RED)
460 << "warning: Could not read coverage for '" << Function.Name << "'."
461 << "\n";
Justin Bogner5a6edad2014-09-19 19:07:17 +0000462 continue;
463 }
Vedant Kumar7937ef32016-06-28 02:09:39 +0000464
465 auto OSOrErr =
466 mainView->createOutputFile("functions", /*InToplevel=*/true);
467 if (Error E = OSOrErr.takeError()) {
Vedant Kumar72e0fe92016-06-28 03:37:56 +0000468 error(toString(std::move(E)));
Vedant Kumar7937ef32016-06-28 02:09:39 +0000469 return 1;
470 }
471 auto OS = std::move(OSOrErr.get());
472 mainView->print(*OS.get(), /*WholeFile=*/false, /*ShowSourceName=*/true);
473 mainView->closeOutputFile(std::move(OS));
Alex Lorenze82d89c2014-08-22 22:56:03 +0000474 }
475 return 0;
476 }
477
478 // Show files
479 bool ShowFilenames = SourceFiles.size() != 1;
480
Justin Bogner116c1662014-09-19 08:13:12 +0000481 if (SourceFiles.empty())
Alex Lorenze82d89c2014-08-22 22:56:03 +0000482 // Get the source files from the function coverage mapping
Justin Bogner953e2402014-09-20 15:31:56 +0000483 for (StringRef Filename : Coverage->getUniqueSourceFiles())
Alex Lorenze82d89c2014-08-22 22:56:03 +0000484 SourceFiles.push_back(Filename);
Alex Lorenze82d89c2014-08-22 22:56:03 +0000485
486 for (const auto &SourceFile : SourceFiles) {
Justin Bogner953e2402014-09-20 15:31:56 +0000487 auto mainView = createSourceFileView(SourceFile, *Coverage);
Justin Bogner5a6edad2014-09-19 19:07:17 +0000488 if (!mainView) {
Vedant Kumar2c96e882016-06-24 02:33:01 +0000489 ViewOpts.colored_ostream(errs(), raw_ostream::RED)
Alex Lorenze82d89c2014-08-22 22:56:03 +0000490 << "warning: The file '" << SourceFile << "' isn't covered.";
Vedant Kumar2c96e882016-06-24 02:33:01 +0000491 errs() << "\n";
Alex Lorenze82d89c2014-08-22 22:56:03 +0000492 continue;
493 }
494
Vedant Kumar7937ef32016-06-28 02:09:39 +0000495 auto OSOrErr = mainView->createOutputFile(SourceFile, /*InToplevel=*/false);
496 if (Error E = OSOrErr.takeError()) {
Vedant Kumar72e0fe92016-06-28 03:37:56 +0000497 error(toString(std::move(E)));
Vedant Kumar7937ef32016-06-28 02:09:39 +0000498 return 1;
499 }
500 auto OS = std::move(OSOrErr.get());
501 mainView->print(*OS.get(), /*Wholefile=*/true,
Vedant Kumar727549e2016-06-28 00:18:51 +0000502 /*ShowSourceName=*/ShowFilenames);
Vedant Kumar7937ef32016-06-28 02:09:39 +0000503 mainView->closeOutputFile(std::move(OS));
Alex Lorenze82d89c2014-08-22 22:56:03 +0000504 }
505
506 return 0;
507}
508
509int CodeCoverageTool::report(int argc, const char **argv,
510 CommandLineParserType commandLineParser) {
Alex Lorenze82d89c2014-08-22 22:56:03 +0000511 auto Err = commandLineParser(argc, argv);
512 if (Err)
513 return Err;
514
Justin Bogner953e2402014-09-20 15:31:56 +0000515 auto Coverage = load();
516 if (!Coverage)
Alex Lorenze82d89c2014-08-22 22:56:03 +0000517 return 1;
518
Justin Bognerf91bc6c2015-02-14 02:01:24 +0000519 CoverageReport Report(ViewOpts, std::move(Coverage));
Justin Bogner0ef7a2a2015-02-14 02:05:05 +0000520 if (SourceFiles.empty())
Alex Lorenze82d89c2014-08-22 22:56:03 +0000521 Report.renderFileReports(llvm::outs());
Justin Bogner0ef7a2a2015-02-14 02:05:05 +0000522 else
523 Report.renderFunctionReports(SourceFiles, llvm::outs());
Alex Lorenze82d89c2014-08-22 22:56:03 +0000524 return 0;
525}
526
Justin Bognerd249a3b2014-10-30 20:57:49 +0000527int showMain(int argc, const char *argv[]) {
Alex Lorenze82d89c2014-08-22 22:56:03 +0000528 CodeCoverageTool Tool;
529 return Tool.run(CodeCoverageTool::Show, argc, argv);
530}
531
Justin Bognerd249a3b2014-10-30 20:57:49 +0000532int reportMain(int argc, const char *argv[]) {
Alex Lorenze82d89c2014-08-22 22:56:03 +0000533 CodeCoverageTool Tool;
534 return Tool.run(CodeCoverageTool::Report, argc, argv);
535}