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