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