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