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