llvm-cov: Rename MappingRegion to coverage::CountedRegion (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 "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 <system_error>
40 #include <functional>
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 (sys::fs::equivalent(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::outs() << "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>(
286       SourceBuffer.get(), Parent.getOptions(), ExpandedLines.first,
287       ExpandedLines.second, ExpandedRegion);
288   SourceCoverageDataManager RegionManager;
289   for (const auto &CR : Function.CountedRegions) {
290     if (CR.FileID == ExpandedRegion.ExpandedFileID)
291       RegionManager.insert(CR);
292   }
293   SubView->load(RegionManager);
294   createExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID, Function);
295   Parent.addChild(std::move(SubView));
296 }
297
298 void CodeCoverageTool::createExpansionSubViews(
299     SourceCoverageView &View, unsigned ViewFileID,
300     const FunctionCoverageMapping &Function) {
301   if (!ViewOpts.ShowExpandedRegions)
302     return;
303   for (const auto &CR : Function.CountedRegions) {
304     if (CR.Kind != CounterMappingRegion::ExpansionRegion)
305       continue;
306     if (CR.FileID != ViewFileID)
307       continue;
308     createExpansionSubView(CR, Function, View);
309   }
310 }
311
312 void CodeCoverageTool::createInstantiationSubView(
313     StringRef SourceFile, const FunctionCoverageMapping &Function,
314     SourceCoverageView &View) {
315   SourceCoverageDataManager RegionManager;
316   SmallSet<unsigned, 8> InterestingFileIDs;
317   if (!gatherInterestingFileIDs(SourceFile, Function, InterestingFileIDs))
318     return;
319   // Get the interesting regions
320   for (const auto &CR : Function.CountedRegions) {
321     if (InterestingFileIDs.count(CR.FileID))
322       RegionManager.insert(CR);
323   }
324   View.load(RegionManager);
325   unsigned MainFileID;
326   if (findMainViewFileID(SourceFile, Function, MainFileID))
327     return;
328   createExpansionSubViews(View, MainFileID, Function);
329 }
330
331 bool CodeCoverageTool::createSourceFileView(
332     StringRef SourceFile, SourceCoverageView &View,
333     ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
334     bool UseOnlyRegionsInMainFile) {
335   SourceCoverageDataManager RegionManager;
336   FunctionInstantiationSetCollector InstantiationSetCollector;
337
338   for (const auto &Function : FunctionMappingRecords) {
339     unsigned MainFileID;
340     if (findMainViewFileID(SourceFile, Function, MainFileID))
341       continue;
342     SmallSet<unsigned, 8> InterestingFileIDs;
343     if (UseOnlyRegionsInMainFile) {
344       InterestingFileIDs.insert(MainFileID);
345     } else if (!gatherInterestingFileIDs(SourceFile, Function,
346                                          InterestingFileIDs))
347       continue;
348     // Get the interesting regions
349     for (const auto &CR : Function.CountedRegions) {
350       if (InterestingFileIDs.count(CR.FileID))
351         RegionManager.insert(CR);
352     }
353     InstantiationSetCollector.insert(Function, MainFileID);
354     createExpansionSubViews(View, MainFileID, Function);
355   }
356   if (RegionManager.getSourceRegions().empty())
357     return true;
358   View.load(RegionManager);
359   // Show instantiations
360   if (!ViewOpts.ShowFunctionInstantiations)
361     return false;
362   for (const auto &InstantiationSet : InstantiationSetCollector) {
363     if (InstantiationSet.second.size() < 2)
364       continue;
365     auto InterestingRange = findExpandedFileInterestingLineRange(
366         InstantiationSet.second.front()->CountedRegions.front().FileID,
367         *InstantiationSet.second.front());
368     for (auto Function : InstantiationSet.second) {
369       auto SubView = llvm::make_unique<SourceCoverageView>(
370           View, InterestingRange.first, InterestingRange.second,
371           Function->Name);
372       createInstantiationSubView(SourceFile, *Function, *SubView);
373       View.addChild(std::move(SubView));
374     }
375   }
376   return false;
377 }
378
379 bool CodeCoverageTool::load() {
380   auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename);
381   if (auto EC = CounterMappingBuff.getError()) {
382     error(EC.message(), ObjectFilename);
383     return true;
384   }
385   ObjectFileCoverageMappingReader MappingReader(CounterMappingBuff.get());
386   if (auto EC = MappingReader.readHeader()) {
387     error(EC.message(), ObjectFilename);
388     return true;
389   }
390
391   std::vector<uint64_t> Counts;
392   for (const auto &I : MappingReader) {
393     FunctionCoverageMapping Function(I.FunctionName, I.Filenames);
394
395     // Create the mapping regions with evaluated execution counts
396     Counts.clear();
397     PGOReader->getFunctionCounts(Function.Name, I.FunctionHash, Counts);
398
399     // Get the biggest referenced counters
400     bool RegionError = false;
401     CounterMappingContext Ctx(I.Expressions, Counts);
402     for (const auto &R : I.MappingRegions) {
403       // Compute the values of mapped regions
404       if (ViewOpts.Debug) {
405         outs() << "File " << R.FileID << "| " << R.LineStart << ":"
406                << R.ColumnStart << " -> " << R.LineEnd << ":" << R.ColumnEnd
407                << " = ";
408         Ctx.dump(R.Count);
409         if (R.Kind == CounterMappingRegion::ExpansionRegion) {
410           outs() << " (Expanded file id = " << R.ExpandedFileID << ") ";
411         }
412         outs() << "\n";
413       }
414       ErrorOr<int64_t> ExecutionCount = Ctx.evaluate(R.Count);
415       if (ExecutionCount) {
416         Function.CountedRegions.push_back(CountedRegion(R, *ExecutionCount));
417       } else if (!RegionError) {
418         colored_ostream(errs(), raw_ostream::RED)
419             << "error: Regions and counters don't match in a function '"
420             << Function.Name << "' (re-run the instrumented binary).";
421         errs() << "\n";
422         RegionError = true;
423       }
424     }
425
426     if (RegionError || !Filters.matches(Function))
427       continue;
428
429     FunctionMappingRecords.push_back(Function);
430   }
431   return false;
432 }
433
434 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
435   // Print a stack trace if we signal out.
436   sys::PrintStackTraceOnErrorSignal();
437   PrettyStackTraceProgram X(argc, argv);
438   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
439
440   cl::list<std::string> InputSourceFiles(
441       cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
442
443   cl::opt<std::string> PGOFilename(
444       "instr-profile", cl::Required,
445       cl::desc(
446           "File with the profile data obtained after an instrumented run"));
447
448   cl::opt<bool> DebugDump("dump", cl::Optional,
449                           cl::desc("Show internal debug dump"));
450
451   cl::opt<bool> FilenameEquivalence(
452       "filename-equivalence", cl::Optional,
453       cl::desc("Compare the filenames instead of full filepaths"));
454
455   cl::OptionCategory FilteringCategory("Function filtering options");
456
457   cl::list<std::string> NameFilters(
458       "name", cl::Optional,
459       cl::desc("Show code coverage only for functions with the given name"),
460       cl::ZeroOrMore, cl::cat(FilteringCategory));
461
462   cl::list<std::string> NameRegexFilters(
463       "name-regex", cl::Optional,
464       cl::desc("Show code coverage only for functions that match the given "
465                "regular expression"),
466       cl::ZeroOrMore, cl::cat(FilteringCategory));
467
468   cl::opt<double> RegionCoverageLtFilter(
469       "region-coverage-lt", cl::Optional,
470       cl::desc("Show code coverage only for functions with region coverage "
471                "less than the given threshold"),
472       cl::cat(FilteringCategory));
473
474   cl::opt<double> RegionCoverageGtFilter(
475       "region-coverage-gt", cl::Optional,
476       cl::desc("Show code coverage only for functions with region coverage "
477                "greater than the given threshold"),
478       cl::cat(FilteringCategory));
479
480   cl::opt<double> LineCoverageLtFilter(
481       "line-coverage-lt", cl::Optional,
482       cl::desc("Show code coverage only for functions with line coverage less "
483                "than the given threshold"),
484       cl::cat(FilteringCategory));
485
486   cl::opt<double> LineCoverageGtFilter(
487       "line-coverage-gt", cl::Optional,
488       cl::desc("Show code coverage only for functions with line coverage "
489                "greater than the given threshold"),
490       cl::cat(FilteringCategory));
491
492   auto commandLineParser = [&, this](int argc, const char **argv) -> int {
493     cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
494     ViewOpts.Debug = DebugDump;
495     CompareFilenamesOnly = FilenameEquivalence;
496
497     if (auto EC = IndexedInstrProfReader::create(PGOFilename, PGOReader)) {
498       error(EC.message(), PGOFilename);
499       return 1;
500     }
501
502     // Create the function filters
503     if (!NameFilters.empty() || !NameRegexFilters.empty()) {
504       auto NameFilterer = new CoverageFilters;
505       for (const auto &Name : NameFilters)
506         NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
507       for (const auto &Regex : NameRegexFilters)
508         NameFilterer->push_back(
509             llvm::make_unique<NameRegexCoverageFilter>(Regex));
510       Filters.push_back(std::unique_ptr<CoverageFilter>(NameFilterer));
511     }
512     if (RegionCoverageLtFilter.getNumOccurrences() ||
513         RegionCoverageGtFilter.getNumOccurrences() ||
514         LineCoverageLtFilter.getNumOccurrences() ||
515         LineCoverageGtFilter.getNumOccurrences()) {
516       auto StatFilterer = new CoverageFilters;
517       if (RegionCoverageLtFilter.getNumOccurrences())
518         StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
519             RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
520       if (RegionCoverageGtFilter.getNumOccurrences())
521         StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
522             RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
523       if (LineCoverageLtFilter.getNumOccurrences())
524         StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
525             LineCoverageFilter::LessThan, LineCoverageLtFilter));
526       if (LineCoverageGtFilter.getNumOccurrences())
527         StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
528             RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
529       Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
530     }
531
532     SourceFiles = InputSourceFiles;
533     return 0;
534   };
535
536   // Parse the object filename
537   if (argc > 1) {
538     StringRef Arg(argv[1]);
539     if (Arg.equals_lower("-help") || Arg.equals_lower("-version")) {
540       cl::ParseCommandLineOptions(2, argv, "LLVM code coverage tool\n");
541       return 0;
542     }
543     ObjectFilename = Arg;
544
545     argv[1] = argv[0];
546     --argc;
547     ++argv;
548   } else {
549     errs() << sys::path::filename(argv[0]) << ": No executable file given!\n";
550     return 1;
551   }
552
553   switch (Cmd) {
554   case Show:
555     return show(argc, argv, commandLineParser);
556   case Report:
557     return report(argc, argv, commandLineParser);
558   }
559   return 0;
560 }
561
562 int CodeCoverageTool::show(int argc, const char **argv,
563                            CommandLineParserType commandLineParser) {
564
565   cl::OptionCategory ViewCategory("Viewing options");
566
567   cl::opt<bool> ShowLineExecutionCounts(
568       "show-line-counts", cl::Optional,
569       cl::desc("Show the execution counts for each line"), cl::init(true),
570       cl::cat(ViewCategory));
571
572   cl::opt<bool> ShowRegions(
573       "show-regions", cl::Optional,
574       cl::desc("Show the execution counts for each region"),
575       cl::cat(ViewCategory));
576
577   cl::opt<bool> ShowBestLineRegionsCounts(
578       "show-line-counts-or-regions", cl::Optional,
579       cl::desc("Show the execution counts for each line, or the execution "
580                "counts for each region on lines that have multiple regions"),
581       cl::cat(ViewCategory));
582
583   cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
584                                cl::desc("Show expanded source regions"),
585                                cl::cat(ViewCategory));
586
587   cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
588                                    cl::desc("Show function instantiations"),
589                                    cl::cat(ViewCategory));
590
591   cl::opt<bool> NoColors("no-colors", cl::Optional,
592                          cl::desc("Don't show text colors"), cl::init(false),
593                          cl::cat(ViewCategory));
594
595   auto Err = commandLineParser(argc, argv);
596   if (Err)
597     return Err;
598
599   ViewOpts.Colors = !NoColors;
600   ViewOpts.ShowLineNumbers = true;
601   ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
602                            !ShowRegions || ShowBestLineRegionsCounts;
603   ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
604   ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts;
605   ViewOpts.ShowExpandedRegions = ShowExpansions;
606   ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
607
608   if (load())
609     return 1;
610
611   if (!Filters.empty()) {
612     // Show functions
613     for (const auto &Function : FunctionMappingRecords) {
614       unsigned MainFileID;
615       if (findMainViewFileID(Function, MainFileID))
616         continue;
617       StringRef SourceFile = Function.Filenames[MainFileID];
618       auto SourceBuffer = getSourceFile(SourceFile);
619       if (!SourceBuffer)
620         return 1;
621       auto Range = findExpandedFileInterestingLineRange(MainFileID, Function);
622       SourceCoverageView mainView(SourceBuffer.get(), ViewOpts, Range.first,
623                                   Range.second);
624       createSourceFileView(SourceFile, mainView, Function, true);
625       ViewOpts.colored_ostream(outs(), raw_ostream::CYAN)
626           << Function.Name << " from " << SourceFile << ":";
627       outs() << "\n";
628       mainView.render(outs());
629       if (FunctionMappingRecords.size() > 1)
630         outs() << "\n";
631     }
632     return 0;
633   }
634
635   // Show files
636   bool ShowFilenames = SourceFiles.size() != 1;
637
638   if (SourceFiles.empty()) {
639     // Get the source files from the function coverage mapping
640     std::set<StringRef> UniqueFilenames;
641     for (const auto &Function : FunctionMappingRecords) {
642       for (const auto &Filename : Function.Filenames)
643         UniqueFilenames.insert(Filename);
644     }
645     for (const auto &Filename : UniqueFilenames)
646       SourceFiles.push_back(Filename);
647   }
648
649   for (const auto &SourceFile : SourceFiles) {
650     auto SourceBuffer = getSourceFile(SourceFile);
651     if (!SourceBuffer)
652       return 1;
653     SourceCoverageView mainView(SourceBuffer.get(), ViewOpts);
654     if (createSourceFileView(SourceFile, mainView, FunctionMappingRecords)) {
655       ViewOpts.colored_ostream(outs(), raw_ostream::RED)
656           << "warning: The file '" << SourceFile << "' isn't covered.";
657       outs() << "\n";
658       continue;
659     }
660
661     if (ShowFilenames) {
662       ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":";
663       outs() << "\n";
664     }
665     mainView.render(outs());
666     if (SourceFiles.size() > 1)
667       outs() << "\n";
668   }
669
670   return 0;
671 }
672
673 int CodeCoverageTool::report(int argc, const char **argv,
674                              CommandLineParserType commandLineParser) {
675   cl::opt<bool> NoColors("no-colors", cl::Optional,
676                          cl::desc("Don't show text colors"), cl::init(false));
677
678   auto Err = commandLineParser(argc, argv);
679   if (Err)
680     return Err;
681
682   ViewOpts.Colors = !NoColors;
683
684   if (load())
685     return 1;
686
687   CoverageSummary Summarizer;
688   Summarizer.createSummaries(FunctionMappingRecords);
689   CoverageReport Report(ViewOpts, Summarizer);
690   if (SourceFiles.empty() && Filters.empty()) {
691     Report.renderFileReports(llvm::outs());
692     return 0;
693   }
694
695   Report.renderFunctionReports(llvm::outs());
696   return 0;
697 }
698
699 int show_main(int argc, const char **argv) {
700   CodeCoverageTool Tool;
701   return Tool.run(CodeCoverageTool::Show, argc, argv);
702 }
703
704 int report_main(int argc, const char **argv) {
705   CodeCoverageTool Tool;
706   return Tool.run(CodeCoverageTool::Report, argc, argv);
707 }