llvm-cov: Rework the API for getting the coverage of a file (NFC)
[oota-llvm.git] / tools / llvm-cov / CodeCoverage.cpp
1 //===- 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
16 #include "RenderingSupport.h"
17 #include "CoverageViewOptions.h"
18 #include "CoverageFilters.h"
19 #include "SourceCoverageDataManager.h"
20 #include "SourceCoverageView.h"
21 #include "CoverageSummary.h"
22 #include "CoverageReport.h"
23 #include "llvm/ADT/StringRef.h"
24 #include "llvm/ADT/SmallString.h"
25 #include "llvm/ADT/SmallSet.h"
26 #include "llvm/ADT/DenseSet.h"
27 #include "llvm/ProfileData/InstrProfReader.h"
28 #include "llvm/ProfileData/CoverageMapping.h"
29 #include "llvm/ProfileData/CoverageMappingReader.h"
30 #include "llvm/Support/CommandLine.h"
31 #include "llvm/Support/FileSystem.h"
32 #include "llvm/Support/ManagedStatic.h"
33 #include "llvm/Support/MemoryObject.h"
34 #include "llvm/Support/Format.h"
35 #include "llvm/Support/Path.h"
36 #include "llvm/Support/Signals.h"
37 #include "llvm/Support/PrettyStackTrace.h"
38 #include <functional>
39 #include <system_error>
40 #include <unordered_map>
41
42 using namespace llvm;
43 using namespace coverage;
44
45 namespace {
46 /// \brief Distribute the functions into instantiation sets.
47 /// An instantiation set is a collection of functions
48 /// that have the same source code, e.g.
49 /// template functions specializations.
50 class FunctionInstantiationSetCollector {
51   ArrayRef<FunctionCoverageMapping> FunctionMappings;
52   typedef uint64_t KeyType;
53   typedef std::vector<const FunctionCoverageMapping *> SetType;
54   std::unordered_map<uint64_t, SetType> InstantiatedFunctions;
55
56   static KeyType getKey(const CountedRegion &R) {
57     return uint64_t(R.LineStart) | uint64_t(R.ColumnStart) << 32;
58   }
59
60 public:
61   void insert(const FunctionCoverageMapping &Function, unsigned FileID) {
62     KeyType Key = 0;
63     for (const auto &R : Function.CountedRegions) {
64       if (R.FileID == FileID) {
65         Key = getKey(R);
66         break;
67       }
68     }
69     auto I = InstantiatedFunctions.find(Key);
70     if (I == InstantiatedFunctions.end()) {
71       SetType Set;
72       Set.push_back(&Function);
73       InstantiatedFunctions.insert(std::make_pair(Key, Set));
74     } else
75       I->second.push_back(&Function);
76   }
77
78   std::unordered_map<KeyType, SetType>::iterator begin() {
79     return InstantiatedFunctions.begin();
80   }
81
82   std::unordered_map<KeyType, SetType>::iterator end() {
83     return InstantiatedFunctions.end();
84   }
85 };
86
87 /// \brief The implementation of the coverage tool.
88 class CodeCoverageTool {
89 public:
90   enum Command {
91     /// \brief The show command.
92     Show,
93     /// \brief The report command.
94     Report
95   };
96
97   /// \brief Print the error message to the error output stream.
98   void error(const Twine &Message, StringRef Whence = "");
99
100   /// \brief Return a memory buffer for the given source file.
101   ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
102
103   /// \brief Return true if two filepaths refer to the same file.
104   bool equivalentFiles(StringRef A, StringRef B);
105
106   /// \brief Collect a set of function's file ids which correspond to the
107   /// given source file. Return false if the set is empty.
108   bool gatherInterestingFileIDs(StringRef SourceFile,
109                                 const FunctionCoverageMapping &Function,
110                                 SmallSet<unsigned, 8> &InterestingFileIDs);
111
112   /// \brief Find the file id which is not an expanded file id.
113   bool findMainViewFileID(StringRef SourceFile,
114                           const FunctionCoverageMapping &Function,
115                           unsigned &MainViewFileID);
116
117   bool findMainViewFileID(const FunctionCoverageMapping &Function,
118                           unsigned &MainViewFileID);
119
120   /// \brief Create a source view which shows coverage for an expansion
121   /// of a file.
122   void createExpansionSubView(const CountedRegion &ExpandedRegion,
123                               const FunctionCoverageMapping &Function,
124                               SourceCoverageView &Parent);
125
126   void createExpansionSubViews(SourceCoverageView &View, unsigned ViewFileID,
127                                const FunctionCoverageMapping &Function);
128
129   /// \brief Create a source view which shows coverage for an instantiation
130   /// of a funciton.
131   void createInstantiationSubView(StringRef SourceFile,
132                                   const FunctionCoverageMapping &Function,
133                                   SourceCoverageView &View);
134
135   /// \brief Create the main source view of a particular source file.
136   /// Return true if this particular source file is not covered.
137   bool
138   createSourceFileView(StringRef SourceFile, SourceCoverageView &View,
139                        ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
140                        bool UseOnlyRegionsInMainFile = false);
141
142   /// \brief Load the coverage mapping data. Return true if an error occured.
143   bool load();
144
145   int run(Command Cmd, int argc, const char **argv);
146
147   typedef std::function<int(int, const char **)> CommandLineParserType;
148
149   int show(int argc, const char **argv,
150            CommandLineParserType commandLineParser);
151
152   int report(int argc, const char **argv,
153              CommandLineParserType commandLineParser);
154
155   StringRef ObjectFilename;
156   CoverageViewOptions ViewOpts;
157   std::unique_ptr<IndexedInstrProfReader> PGOReader;
158   CoverageFiltersMatchAll Filters;
159   std::vector<std::string> SourceFiles;
160   std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
161       LoadedSourceFiles;
162   std::vector<FunctionCoverageMapping> FunctionMappingRecords;
163   bool CompareFilenamesOnly;
164 };
165 }
166
167 void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
168   errs() << "error: ";
169   if (!Whence.empty())
170     errs() << Whence << ": ";
171   errs() << Message << "\n";
172 }
173
174 ErrorOr<const MemoryBuffer &>
175 CodeCoverageTool::getSourceFile(StringRef SourceFile) {
176   SmallString<256> Path(SourceFile);
177   sys::fs::make_absolute(Path);
178   for (const auto &Files : LoadedSourceFiles) {
179     if (equivalentFiles(Path.str(), Files.first)) {
180       return *Files.second;
181     }
182   }
183   auto Buffer = MemoryBuffer::getFile(SourceFile);
184   if (auto EC = Buffer.getError()) {
185     error(EC.message(), SourceFile);
186     return EC;
187   }
188   LoadedSourceFiles.push_back(std::make_pair(
189       std::string(Path.begin(), Path.end()), std::move(Buffer.get())));
190   return *LoadedSourceFiles.back().second;
191 }
192
193 /// \brief Return a line start - line end range which contains
194 /// all the mapping regions of a given function with a particular file id.
195 std::pair<unsigned, unsigned>
196 findExpandedFileInterestingLineRange(unsigned FileID,
197                                      const FunctionCoverageMapping &Function) {
198   unsigned LineStart = std::numeric_limits<unsigned>::max();
199   unsigned LineEnd = 0;
200   for (const auto &CR : Function.CountedRegions) {
201     if (CR.FileID != FileID)
202       continue;
203     LineStart = std::min(CR.LineStart, LineStart);
204     LineEnd = std::max(CR.LineEnd, LineEnd);
205   }
206   return std::make_pair(LineStart, LineEnd);
207 }
208
209 bool CodeCoverageTool::equivalentFiles(StringRef A, StringRef B) {
210   if (CompareFilenamesOnly)
211     return sys::path::filename(A).equals_lower(sys::path::filename(B));
212   return sys::fs::equivalent(A, B);
213 }
214
215 bool CodeCoverageTool::gatherInterestingFileIDs(
216     StringRef SourceFile, const FunctionCoverageMapping &Function,
217     SmallSet<unsigned, 8> &InterestingFileIDs) {
218   bool Interesting = false;
219   for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
220     if (equivalentFiles(SourceFile, Function.Filenames[I])) {
221       InterestingFileIDs.insert(I);
222       Interesting = true;
223     }
224   }
225   return Interesting;
226 }
227
228 bool
229 CodeCoverageTool::findMainViewFileID(StringRef SourceFile,
230                                      const FunctionCoverageMapping &Function,
231                                      unsigned &MainViewFileID) {
232   llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false);
233   llvm::SmallVector<bool, 8> FilenameEquivalence(Function.Filenames.size(),
234                                                  false);
235   for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
236     if (equivalentFiles(SourceFile, Function.Filenames[I]))
237       FilenameEquivalence[I] = true;
238   }
239   for (const auto &CR : Function.CountedRegions) {
240     if (CR.Kind == CounterMappingRegion::ExpansionRegion &&
241         FilenameEquivalence[CR.FileID])
242       IsExpandedFile[CR.ExpandedFileID] = true;
243   }
244   for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
245     if (!FilenameEquivalence[I] || IsExpandedFile[I])
246       continue;
247     MainViewFileID = I;
248     return false;
249   }
250   return true;
251 }
252
253 bool
254 CodeCoverageTool::findMainViewFileID(const FunctionCoverageMapping &Function,
255                                      unsigned &MainViewFileID) {
256   llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false);
257   for (const auto &CR : Function.CountedRegions) {
258     if (CR.Kind == CounterMappingRegion::ExpansionRegion)
259       IsExpandedFile[CR.ExpandedFileID] = true;
260   }
261   for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
262     if (IsExpandedFile[I])
263       continue;
264     MainViewFileID = I;
265     return false;
266   }
267   return true;
268 }
269
270 void CodeCoverageTool::createExpansionSubView(
271     const CountedRegion &ExpandedRegion,
272     const FunctionCoverageMapping &Function, SourceCoverageView &Parent) {
273   auto ExpandedLines = findExpandedFileInterestingLineRange(
274       ExpandedRegion.ExpandedFileID, Function);
275   if (ViewOpts.Debug)
276     llvm::errs() << "Expansion of " << ExpandedRegion.ExpandedFileID << ":"
277                  << ExpandedLines.first << " -> " << ExpandedLines.second
278                  << " @ " << ExpandedRegion.FileID << ", "
279                  << ExpandedRegion.LineStart << ":"
280                  << ExpandedRegion.ColumnStart << "\n";
281   auto SourceBuffer =
282       getSourceFile(Function.Filenames[ExpandedRegion.ExpandedFileID]);
283   if (!SourceBuffer)
284     return;
285   auto SubView = llvm::make_unique<SourceCoverageView>(SourceBuffer.get(),
286                                                        Parent.getOptions());
287   auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
288   for (const auto &CR : Function.CountedRegions) {
289     if (CR.FileID == ExpandedRegion.ExpandedFileID)
290       RegionManager->insert(CR);
291   }
292   SubView->load(std::move(RegionManager));
293   createExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID, Function);
294   Parent.addExpansion(ExpandedRegion, std::move(SubView));
295 }
296
297 void CodeCoverageTool::createExpansionSubViews(
298     SourceCoverageView &View, unsigned ViewFileID,
299     const FunctionCoverageMapping &Function) {
300   if (!ViewOpts.ShowExpandedRegions)
301     return;
302   for (const auto &CR : Function.CountedRegions) {
303     if (CR.Kind != CounterMappingRegion::ExpansionRegion)
304       continue;
305     if (CR.FileID != ViewFileID)
306       continue;
307     createExpansionSubView(CR, Function, View);
308   }
309 }
310
311 void CodeCoverageTool::createInstantiationSubView(
312     StringRef SourceFile, const FunctionCoverageMapping &Function,
313     SourceCoverageView &View) {
314   auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
315   SmallSet<unsigned, 8> InterestingFileIDs;
316   if (!gatherInterestingFileIDs(SourceFile, Function, InterestingFileIDs))
317     return;
318   // Get the interesting regions
319   for (const auto &CR : Function.CountedRegions) {
320     if (InterestingFileIDs.count(CR.FileID))
321       RegionManager->insert(CR);
322   }
323   View.load(std::move(RegionManager));
324   unsigned MainFileID;
325   if (findMainViewFileID(SourceFile, Function, MainFileID))
326     return;
327   createExpansionSubViews(View, MainFileID, Function);
328 }
329
330 bool CodeCoverageTool::createSourceFileView(
331     StringRef SourceFile, SourceCoverageView &View,
332     ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
333     bool UseOnlyRegionsInMainFile) {
334   auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
335   FunctionInstantiationSetCollector InstantiationSetCollector;
336
337   for (const auto &Function : FunctionMappingRecords) {
338     unsigned MainFileID;
339     if (findMainViewFileID(SourceFile, Function, MainFileID))
340       continue;
341     SmallSet<unsigned, 8> InterestingFileIDs;
342     if (UseOnlyRegionsInMainFile) {
343       InterestingFileIDs.insert(MainFileID);
344     } else if (!gatherInterestingFileIDs(SourceFile, Function,
345                                          InterestingFileIDs))
346       continue;
347     // Get the interesting regions
348     for (const auto &CR : Function.CountedRegions) {
349       if (InterestingFileIDs.count(CR.FileID))
350         RegionManager->insert(CR);
351     }
352     InstantiationSetCollector.insert(Function, MainFileID);
353     createExpansionSubViews(View, MainFileID, Function);
354   }
355   if (RegionManager->getCoverageSegments().empty())
356     return true;
357   View.load(std::move(RegionManager));
358   // Show instantiations
359   if (!ViewOpts.ShowFunctionInstantiations)
360     return false;
361   for (const auto &InstantiationSet : InstantiationSetCollector) {
362     if (InstantiationSet.second.size() < 2)
363       continue;
364     for (auto Function : InstantiationSet.second) {
365       unsigned FileID = Function->CountedRegions.front().FileID;
366       unsigned Line = 0;
367       for (const auto &CR : Function->CountedRegions)
368         if (CR.FileID == FileID)
369           Line = std::max(CR.LineEnd, Line);
370       auto SourceBuffer = getSourceFile(Function->Filenames[FileID]);
371       if (!SourceBuffer)
372         continue;
373       auto SubView = llvm::make_unique<SourceCoverageView>(SourceBuffer.get(),
374                                                            View.getOptions());
375       createInstantiationSubView(SourceFile, *Function, *SubView);
376       View.addInstantiation(Function->Name, Line, std::move(SubView));
377     }
378   }
379   return false;
380 }
381
382 bool CodeCoverageTool::load() {
383   auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename);
384   if (auto EC = CounterMappingBuff.getError()) {
385     error(EC.message(), ObjectFilename);
386     return true;
387   }
388   ObjectFileCoverageMappingReader MappingReader(CounterMappingBuff.get());
389   if (auto EC = MappingReader.readHeader()) {
390     error(EC.message(), ObjectFilename);
391     return true;
392   }
393
394   std::vector<uint64_t> Counts;
395   for (const auto &I : MappingReader) {
396     FunctionCoverageMapping Function(I.FunctionName, I.Filenames);
397
398     // Create the mapping regions with evaluated execution counts
399     Counts.clear();
400     PGOReader->getFunctionCounts(Function.Name, I.FunctionHash, Counts);
401
402     // Get the biggest referenced counters
403     bool RegionError = false;
404     CounterMappingContext Ctx(I.Expressions, Counts);
405     for (const auto &R : I.MappingRegions) {
406       // Compute the values of mapped regions
407       if (ViewOpts.Debug) {
408         errs() << "File " << R.FileID << "| " << R.LineStart << ":"
409                << R.ColumnStart << " -> " << R.LineEnd << ":" << R.ColumnEnd
410                << " = ";
411         Ctx.dump(R.Count);
412         if (R.Kind == CounterMappingRegion::ExpansionRegion) {
413           errs() << " (Expanded file id = " << R.ExpandedFileID << ") ";
414         }
415         errs() << "\n";
416       }
417       ErrorOr<int64_t> ExecutionCount = Ctx.evaluate(R.Count);
418       if (ExecutionCount) {
419         Function.CountedRegions.push_back(CountedRegion(R, *ExecutionCount));
420       } else if (!RegionError) {
421         colored_ostream(errs(), raw_ostream::RED)
422             << "error: Regions and counters don't match in a function '"
423             << Function.Name << "' (re-run the instrumented binary).";
424         errs() << "\n";
425         RegionError = true;
426       }
427     }
428
429     if (RegionError || !Filters.matches(Function))
430       continue;
431
432     FunctionMappingRecords.push_back(Function);
433   }
434   return false;
435 }
436
437 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
438   // Print a stack trace if we signal out.
439   sys::PrintStackTraceOnErrorSignal();
440   PrettyStackTraceProgram X(argc, argv);
441   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
442
443   cl::list<std::string> InputSourceFiles(
444       cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
445
446   cl::opt<std::string> PGOFilename(
447       "instr-profile", cl::Required,
448       cl::desc(
449           "File with the profile data obtained after an instrumented run"));
450
451   cl::opt<bool> DebugDump("dump", cl::Optional,
452                           cl::desc("Show internal debug dump"));
453
454   cl::opt<bool> FilenameEquivalence(
455       "filename-equivalence", cl::Optional,
456       cl::desc("Compare the filenames instead of full filepaths"));
457
458   cl::OptionCategory FilteringCategory("Function filtering options");
459
460   cl::list<std::string> NameFilters(
461       "name", cl::Optional,
462       cl::desc("Show code coverage only for functions with the given name"),
463       cl::ZeroOrMore, cl::cat(FilteringCategory));
464
465   cl::list<std::string> NameRegexFilters(
466       "name-regex", cl::Optional,
467       cl::desc("Show code coverage only for functions that match the given "
468                "regular expression"),
469       cl::ZeroOrMore, cl::cat(FilteringCategory));
470
471   cl::opt<double> RegionCoverageLtFilter(
472       "region-coverage-lt", cl::Optional,
473       cl::desc("Show code coverage only for functions with region coverage "
474                "less than the given threshold"),
475       cl::cat(FilteringCategory));
476
477   cl::opt<double> RegionCoverageGtFilter(
478       "region-coverage-gt", cl::Optional,
479       cl::desc("Show code coverage only for functions with region coverage "
480                "greater than the given threshold"),
481       cl::cat(FilteringCategory));
482
483   cl::opt<double> LineCoverageLtFilter(
484       "line-coverage-lt", cl::Optional,
485       cl::desc("Show code coverage only for functions with line coverage less "
486                "than the given threshold"),
487       cl::cat(FilteringCategory));
488
489   cl::opt<double> LineCoverageGtFilter(
490       "line-coverage-gt", cl::Optional,
491       cl::desc("Show code coverage only for functions with line coverage "
492                "greater than the given threshold"),
493       cl::cat(FilteringCategory));
494
495   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
496     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
497     ViewOpts.Debug = DebugDump;
498     CompareFilenamesOnly = FilenameEquivalence;
499
500     if (auto EC = IndexedInstrProfReader::create(PGOFilename, PGOReader)) {
501       error(EC.message(), PGOFilename);
502       return 1;
503     }
504
505     // Create the function filters
506     if (!NameFilters.empty() || !NameRegexFilters.empty()) {
507       auto NameFilterer = new CoverageFilters;
508       for (const auto &Name : NameFilters)
509         NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
510       for (const auto &Regex : NameRegexFilters)
511         NameFilterer->push_back(
512             llvm::make_unique<NameRegexCoverageFilter>(Regex));
513       Filters.push_back(std::unique_ptr<CoverageFilter>(NameFilterer));
514     }
515     if (RegionCoverageLtFilter.getNumOccurrences() ||
516         RegionCoverageGtFilter.getNumOccurrences() ||
517         LineCoverageLtFilter.getNumOccurrences() ||
518         LineCoverageGtFilter.getNumOccurrences()) {
519       auto StatFilterer = new CoverageFilters;
520       if (RegionCoverageLtFilter.getNumOccurrences())
521         StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
522             RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
523       if (RegionCoverageGtFilter.getNumOccurrences())
524         StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
525             RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
526       if (LineCoverageLtFilter.getNumOccurrences())
527         StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
528             LineCoverageFilter::LessThan, LineCoverageLtFilter));
529       if (LineCoverageGtFilter.getNumOccurrences())
530         StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
531             RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
532       Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
533     }
534
535     SourceFiles = InputSourceFiles;
536     return 0;
537   };
538
539   // Parse the object filename
540   if (argc > 1) {
541     StringRef Arg(argv[1]);
542     if (Arg.equals_lower("-help") || Arg.equals_lower("-version")) {
543       cl::ParseCommandLineOptions(2, argv, "LLVM code coverage tool\n");
544       return 0;
545     }
546     ObjectFilename = Arg;
547
548     argv[1] = argv[0];
549     --argc;
550     ++argv;
551   } else {
552     errs() << sys::path::filename(argv[0]) << ": No executable file given!\n";
553     return 1;
554   }
555
556   switch (Cmd) {
557   case Show:
558     return show(argc, argv, commandLineParser);
559   case Report:
560     return report(argc, argv, commandLineParser);
561   }
562   return 0;
563 }
564
565 int CodeCoverageTool::show(int argc, const char **argv,
566                            CommandLineParserType commandLineParser) {
567
568   cl::OptionCategory ViewCategory("Viewing options");
569
570   cl::opt<bool> ShowLineExecutionCounts(
571       "show-line-counts", cl::Optional,
572       cl::desc("Show the execution counts for each line"), cl::init(true),
573       cl::cat(ViewCategory));
574
575   cl::opt<bool> ShowRegions(
576       "show-regions", cl::Optional,
577       cl::desc("Show the execution counts for each region"),
578       cl::cat(ViewCategory));
579
580   cl::opt<bool> ShowBestLineRegionsCounts(
581       "show-line-counts-or-regions", cl::Optional,
582       cl::desc("Show the execution counts for each line, or the execution "
583                "counts for each region on lines that have multiple regions"),
584       cl::cat(ViewCategory));
585
586   cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
587                                cl::desc("Show expanded source regions"),
588                                cl::cat(ViewCategory));
589
590   cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
591                                    cl::desc("Show function instantiations"),
592                                    cl::cat(ViewCategory));
593
594   cl::opt<bool> NoColors("no-colors", cl::Optional,
595                          cl::desc("Don't show text colors"), cl::init(false),
596                          cl::cat(ViewCategory));
597
598   auto Err = commandLineParser(argc, argv);
599   if (Err)
600     return Err;
601
602   ViewOpts.Colors = !NoColors;
603   ViewOpts.ShowLineNumbers = true;
604   ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
605                            !ShowRegions || ShowBestLineRegionsCounts;
606   ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
607   ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts;
608   ViewOpts.ShowExpandedRegions = ShowExpansions;
609   ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
610
611   if (load())
612     return 1;
613
614   if (!Filters.empty()) {
615     // Show functions
616     for (const auto &Function : FunctionMappingRecords) {
617       unsigned MainFileID;
618       if (findMainViewFileID(Function, MainFileID))
619         continue;
620       StringRef SourceFile = Function.Filenames[MainFileID];
621       auto SourceBuffer = getSourceFile(SourceFile);
622       if (!SourceBuffer)
623         return 1;
624       SourceCoverageView mainView(SourceBuffer.get(), ViewOpts);
625       createSourceFileView(SourceFile, mainView, Function, true);
626       ViewOpts.colored_ostream(outs(), raw_ostream::CYAN)
627           << Function.Name << " from " << SourceFile << ":";
628       outs() << "\n";
629       mainView.render(outs(), /*WholeFile=*/false);
630       if (FunctionMappingRecords.size() > 1)
631         outs() << "\n";
632     }
633     return 0;
634   }
635
636   // Show files
637   bool ShowFilenames = SourceFiles.size() != 1;
638
639   if (SourceFiles.empty()) {
640     // Get the source files from the function coverage mapping
641     std::set<StringRef> UniqueFilenames;
642     for (const auto &Function : FunctionMappingRecords) {
643       for (const auto &Filename : Function.Filenames)
644         UniqueFilenames.insert(Filename);
645     }
646     for (const auto &Filename : UniqueFilenames)
647       SourceFiles.push_back(Filename);
648   }
649
650   for (const auto &SourceFile : SourceFiles) {
651     auto SourceBuffer = getSourceFile(SourceFile);
652     if (!SourceBuffer)
653       return 1;
654     SourceCoverageView mainView(SourceBuffer.get(), ViewOpts);
655     if (createSourceFileView(SourceFile, mainView, FunctionMappingRecords)) {
656       ViewOpts.colored_ostream(outs(), raw_ostream::RED)
657           << "warning: The file '" << SourceFile << "' isn't covered.";
658       outs() << "\n";
659       continue;
660     }
661
662     if (ShowFilenames) {
663       ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":";
664       outs() << "\n";
665     }
666     mainView.render(outs(), /*Wholefile=*/true);
667     if (SourceFiles.size() > 1)
668       outs() << "\n";
669   }
670
671   return 0;
672 }
673
674 int CodeCoverageTool::report(int argc, const char **argv,
675                              CommandLineParserType commandLineParser) {
676   cl::opt<bool> NoColors("no-colors", cl::Optional,
677                          cl::desc("Don't show text colors"), cl::init(false));
678
679   auto Err = commandLineParser(argc, argv);
680   if (Err)
681     return Err;
682
683   ViewOpts.Colors = !NoColors;
684
685   if (load())
686     return 1;
687
688   CoverageSummary Summarizer;
689   Summarizer.createSummaries(FunctionMappingRecords);
690   CoverageReport Report(ViewOpts, Summarizer);
691   if (SourceFiles.empty() && Filters.empty()) {
692     Report.renderFileReports(llvm::outs());
693     return 0;
694   }
695
696   Report.renderFunctionReports(llvm::outs());
697   return 0;
698 }
699
700 int show_main(int argc, const char **argv) {
701   CodeCoverageTool Tool;
702   return Tool.run(CodeCoverageTool::Show, argc, argv);
703 }
704
705 int report_main(int argc, const char **argv) {
706   CodeCoverageTool Tool;
707   return Tool.run(CodeCoverageTool::Report, argc, argv);
708 }