Mercurial > hg > CbC > CbC_llvm
diff tools/llvm-cov/CodeCoverage.cpp @ 83:60c9769439b8 LLVM3.7
LLVM 3.7
author | Tatsuki IHA <e125716@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 18 Feb 2015 14:55:36 +0900 |
parents | 54457678186b |
children | afa8332a0e37 |
line wrap: on
line diff
--- a/tools/llvm-cov/CodeCoverage.cpp Mon Sep 08 22:07:30 2014 +0900 +++ b/tools/llvm-cov/CodeCoverage.cpp Wed Feb 18 14:55:36 2015 +0900 @@ -13,77 +13,29 @@ // //===----------------------------------------------------------------------===// -#include "FunctionCoverageMapping.h" #include "RenderingSupport.h" -#include "CoverageViewOptions.h" #include "CoverageFilters.h" -#include "SourceCoverageDataManager.h" -#include "SourceCoverageView.h" -#include "CoverageSummary.h" #include "CoverageReport.h" -#include "llvm/ADT/StringRef.h" +#include "CoverageViewOptions.h" +#include "SourceCoverageView.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ProfileData/CoverageMapping.h" #include "llvm/ProfileData/InstrProfReader.h" -#include "llvm/ProfileData/CoverageMapping.h" -#include "llvm/ProfileData/CoverageMappingReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MemoryObject.h" -#include "llvm/Support/Format.h" #include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/PrettyStackTrace.h" +#include <functional> #include <system_error> -#include <functional> using namespace llvm; using namespace coverage; namespace { -/// \brief Distribute the functions into instantiation sets. -/// An instantiation set is a collection of functions -/// that have the same source code, e.g. -/// template functions specializations. -class FunctionInstantiationSetCollector { - ArrayRef<FunctionCoverageMapping> FunctionMappings; - typedef uint64_t KeyType; - typedef std::vector<const FunctionCoverageMapping *> SetType; - std::unordered_map<uint64_t, SetType> InstantiatedFunctions; - - static KeyType getKey(const MappingRegion &R) { - return uint64_t(R.LineStart) | uint64_t(R.ColumnStart) << 32; - } - -public: - void insert(const FunctionCoverageMapping &Function, unsigned FileID) { - KeyType Key = 0; - for (const auto &R : Function.MappingRegions) { - if (R.FileID == FileID) { - Key = getKey(R); - break; - } - } - auto I = InstantiatedFunctions.find(Key); - if (I == InstantiatedFunctions.end()) { - SetType Set; - Set.push_back(&Function); - InstantiatedFunctions.insert(std::make_pair(Key, Set)); - } else - I->second.push_back(&Function); - } - - std::unordered_map<KeyType, SetType>::iterator begin() { - return InstantiatedFunctions.begin(); - } - - std::unordered_map<KeyType, SetType>::iterator end() { - return InstantiatedFunctions.end(); - } -}; - /// \brief The implementation of the coverage tool. class CodeCoverageTool { public: @@ -100,47 +52,21 @@ /// \brief Return a memory buffer for the given source file. ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile); - /// \brief Return true if two filepaths refer to the same file. - bool equivalentFiles(StringRef A, StringRef B); - - /// \brief Collect a set of function's file ids which correspond to the - /// given source file. Return false if the set is empty. - bool gatherInterestingFileIDs(StringRef SourceFile, - const FunctionCoverageMapping &Function, - SmallSet<unsigned, 8> &InterestingFileIDs); - - /// \brief Find the file id which is not an expanded file id. - bool findMainViewFileID(StringRef SourceFile, - const FunctionCoverageMapping &Function, - unsigned &MainViewFileID); + /// \brief Create source views for the expansions of the view. + void attachExpansionSubViews(SourceCoverageView &View, + ArrayRef<ExpansionRecord> Expansions, + CoverageMapping &Coverage); - bool findMainViewFileID(const FunctionCoverageMapping &Function, - unsigned &MainViewFileID); - - /// \brief Create a source view which shows coverage for an expansion - /// of a file. - void createExpansionSubView(const MappingRegion &ExpandedRegion, - const FunctionCoverageMapping &Function, - SourceCoverageView &Parent); - - void createExpansionSubViews(SourceCoverageView &View, unsigned ViewFileID, - const FunctionCoverageMapping &Function); - - /// \brief Create a source view which shows coverage for an instantiation - /// of a funciton. - void createInstantiationSubView(StringRef SourceFile, - const FunctionCoverageMapping &Function, - SourceCoverageView &View); + /// \brief Create the source view of a particular function. + std::unique_ptr<SourceCoverageView> + createFunctionView(const FunctionRecord &Function, CoverageMapping &Coverage); /// \brief Create the main source view of a particular source file. - /// Return true if this particular source file is not covered. - bool - createSourceFileView(StringRef SourceFile, SourceCoverageView &View, - ArrayRef<FunctionCoverageMapping> FunctionMappingRecords, - bool UseOnlyRegionsInMainFile = false); + std::unique_ptr<SourceCoverageView> + createSourceFileView(StringRef SourceFile, CoverageMapping &Coverage); /// \brief Load the coverage mapping data. Return true if an error occured. - bool load(); + std::unique_ptr<CoverageMapping> load(); int run(Command Cmd, int argc, const char **argv); @@ -152,15 +78,15 @@ int report(int argc, const char **argv, CommandLineParserType commandLineParser); - StringRef ObjectFilename; + std::string ObjectFilename; CoverageViewOptions ViewOpts; - std::unique_ptr<IndexedInstrProfReader> PGOReader; + std::string PGOFilename; CoverageFiltersMatchAll Filters; std::vector<std::string> SourceFiles; std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>> LoadedSourceFiles; - std::vector<FunctionCoverageMapping> FunctionMappingRecords; bool CompareFilenamesOnly; + StringMap<std::string> RemappedFilenames; }; } @@ -173,262 +99,129 @@ ErrorOr<const MemoryBuffer &> CodeCoverageTool::getSourceFile(StringRef SourceFile) { - SmallString<256> Path(SourceFile); - sys::fs::make_absolute(Path); - for (const auto &Files : LoadedSourceFiles) { - if (sys::fs::equivalent(Path.str(), Files.first)) { + // If we've remapped filenames, look up the real location for this file. + if (!RemappedFilenames.empty()) { + auto Loc = RemappedFilenames.find(SourceFile); + if (Loc != RemappedFilenames.end()) + SourceFile = Loc->second; + } + for (const auto &Files : LoadedSourceFiles) + if (sys::fs::equivalent(SourceFile, Files.first)) return *Files.second; - } - } auto Buffer = MemoryBuffer::getFile(SourceFile); if (auto EC = Buffer.getError()) { error(EC.message(), SourceFile); return EC; } - LoadedSourceFiles.push_back(std::make_pair( - std::string(Path.begin(), Path.end()), std::move(Buffer.get()))); + LoadedSourceFiles.push_back( + std::make_pair(SourceFile, std::move(Buffer.get()))); return *LoadedSourceFiles.back().second; } -/// \brief Return a line start - line end range which contains -/// all the mapping regions of a given function with a particular file id. -std::pair<unsigned, unsigned> -findExpandedFileInterestingLineRange(unsigned FileID, - const FunctionCoverageMapping &Function) { - unsigned LineStart = std::numeric_limits<unsigned>::max(); - unsigned LineEnd = 0; - for (const auto &Region : Function.MappingRegions) { - if (Region.FileID != FileID) - continue; - LineStart = std::min(Region.LineStart, LineStart); - LineEnd = std::max(Region.LineEnd, LineEnd); - } - return std::make_pair(LineStart, LineEnd); -} - -bool CodeCoverageTool::equivalentFiles(StringRef A, StringRef B) { - if (CompareFilenamesOnly) - return sys::path::filename(A).equals_lower(sys::path::filename(B)); - return sys::fs::equivalent(A, B); -} - -bool CodeCoverageTool::gatherInterestingFileIDs( - StringRef SourceFile, const FunctionCoverageMapping &Function, - SmallSet<unsigned, 8> &InterestingFileIDs) { - bool Interesting = false; - for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) { - if (equivalentFiles(SourceFile, Function.Filenames[I])) { - InterestingFileIDs.insert(I); - Interesting = true; - } - } - return Interesting; -} - -bool -CodeCoverageTool::findMainViewFileID(StringRef SourceFile, - const FunctionCoverageMapping &Function, - unsigned &MainViewFileID) { - llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false); - llvm::SmallVector<bool, 8> FilenameEquivalence(Function.Filenames.size(), - false); - for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) { - if (equivalentFiles(SourceFile, Function.Filenames[I])) - FilenameEquivalence[I] = true; - } - for (const auto &Region : Function.MappingRegions) { - if (Region.Kind == MappingRegion::ExpansionRegion && - FilenameEquivalence[Region.FileID]) - IsExpandedFile[Region.ExpandedFileID] = true; - } - for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) { - if (!FilenameEquivalence[I] || IsExpandedFile[I]) - continue; - MainViewFileID = I; - return false; - } - return true; -} - -bool -CodeCoverageTool::findMainViewFileID(const FunctionCoverageMapping &Function, - unsigned &MainViewFileID) { - llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false); - for (const auto &Region : Function.MappingRegions) { - if (Region.Kind == MappingRegion::ExpansionRegion) - IsExpandedFile[Region.ExpandedFileID] = true; - } - for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) { - if (IsExpandedFile[I]) - continue; - MainViewFileID = I; - return false; - } - return true; -} - -void CodeCoverageTool::createExpansionSubView( - const MappingRegion &ExpandedRegion, - const FunctionCoverageMapping &Function, SourceCoverageView &Parent) { - auto ExpandedLines = findExpandedFileInterestingLineRange( - ExpandedRegion.ExpandedFileID, Function); - if (ViewOpts.Debug) - llvm::outs() << "Expansion of " << ExpandedRegion.ExpandedFileID << ":" - << ExpandedLines.first << " -> " << ExpandedLines.second - << " @ " << ExpandedRegion.FileID << ", " - << ExpandedRegion.LineStart << ":" - << ExpandedRegion.ColumnStart << "\n"; - auto SourceBuffer = - getSourceFile(Function.Filenames[ExpandedRegion.ExpandedFileID]); - if (!SourceBuffer) - return; - auto SubView = llvm::make_unique<SourceCoverageView>( - SourceBuffer.get(), Parent.getOptions(), ExpandedLines.first, - ExpandedLines.second, ExpandedRegion); - SourceCoverageDataManager RegionManager; - for (const auto &Region : Function.MappingRegions) { - if (Region.FileID == ExpandedRegion.ExpandedFileID) - RegionManager.insert(Region); - } - SubView->load(RegionManager); - createExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID, Function); - Parent.addChild(std::move(SubView)); -} - -void CodeCoverageTool::createExpansionSubViews( - SourceCoverageView &View, unsigned ViewFileID, - const FunctionCoverageMapping &Function) { +void +CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View, + ArrayRef<ExpansionRecord> Expansions, + CoverageMapping &Coverage) { if (!ViewOpts.ShowExpandedRegions) return; - for (const auto &Region : Function.MappingRegions) { - if (Region.Kind != CounterMappingRegion::ExpansionRegion) + for (const auto &Expansion : Expansions) { + auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion); + if (ExpansionCoverage.empty()) + continue; + auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename()); + if (!SourceBuffer) continue; - if (Region.FileID != ViewFileID) - continue; - createExpansionSubView(Region, Function, View); + + auto SubViewExpansions = ExpansionCoverage.getExpansions(); + auto SubView = llvm::make_unique<SourceCoverageView>( + SourceBuffer.get(), ViewOpts, std::move(ExpansionCoverage)); + attachExpansionSubViews(*SubView, SubViewExpansions, Coverage); + View.addExpansion(Expansion.Region, std::move(SubView)); } } -void CodeCoverageTool::createInstantiationSubView( - StringRef SourceFile, const FunctionCoverageMapping &Function, - SourceCoverageView &View) { - SourceCoverageDataManager RegionManager; - SmallSet<unsigned, 8> InterestingFileIDs; - if (!gatherInterestingFileIDs(SourceFile, Function, InterestingFileIDs)) - return; - // Get the interesting regions - for (const auto &Region : Function.MappingRegions) { - if (InterestingFileIDs.count(Region.FileID)) - RegionManager.insert(Region); - } - View.load(RegionManager); - unsigned MainFileID; - if (findMainViewFileID(SourceFile, Function, MainFileID)) - return; - createExpansionSubViews(View, MainFileID, Function); +std::unique_ptr<SourceCoverageView> +CodeCoverageTool::createFunctionView(const FunctionRecord &Function, + CoverageMapping &Coverage) { + auto FunctionCoverage = Coverage.getCoverageForFunction(Function); + if (FunctionCoverage.empty()) + return nullptr; + auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename()); + if (!SourceBuffer) + return nullptr; + + auto Expansions = FunctionCoverage.getExpansions(); + auto View = llvm::make_unique<SourceCoverageView>( + SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage)); + attachExpansionSubViews(*View, Expansions, Coverage); + + return View; } -bool CodeCoverageTool::createSourceFileView( - StringRef SourceFile, SourceCoverageView &View, - ArrayRef<FunctionCoverageMapping> FunctionMappingRecords, - bool UseOnlyRegionsInMainFile) { - SourceCoverageDataManager RegionManager; - FunctionInstantiationSetCollector InstantiationSetCollector; +std::unique_ptr<SourceCoverageView> +CodeCoverageTool::createSourceFileView(StringRef SourceFile, + CoverageMapping &Coverage) { + auto SourceBuffer = getSourceFile(SourceFile); + if (!SourceBuffer) + return nullptr; + auto FileCoverage = Coverage.getCoverageForFile(SourceFile); + if (FileCoverage.empty()) + return nullptr; + + auto Expansions = FileCoverage.getExpansions(); + auto View = llvm::make_unique<SourceCoverageView>( + SourceBuffer.get(), ViewOpts, std::move(FileCoverage)); + attachExpansionSubViews(*View, Expansions, Coverage); - for (const auto &Function : FunctionMappingRecords) { - unsigned MainFileID; - if (findMainViewFileID(SourceFile, Function, MainFileID)) - continue; - SmallSet<unsigned, 8> InterestingFileIDs; - if (UseOnlyRegionsInMainFile) { - InterestingFileIDs.insert(MainFileID); - } else if (!gatherInterestingFileIDs(SourceFile, Function, - InterestingFileIDs)) - continue; - // Get the interesting regions - for (const auto &Region : Function.MappingRegions) { - if (InterestingFileIDs.count(Region.FileID)) - RegionManager.insert(Region); - } - InstantiationSetCollector.insert(Function, MainFileID); - createExpansionSubViews(View, MainFileID, Function); - } - if (RegionManager.getSourceRegions().empty()) - return true; - View.load(RegionManager); - // Show instantiations - if (!ViewOpts.ShowFunctionInstantiations) - return false; - for (const auto &InstantiationSet : InstantiationSetCollector) { - if (InstantiationSet.second.size() < 2) - continue; - auto InterestingRange = findExpandedFileInterestingLineRange( - InstantiationSet.second.front()->MappingRegions.front().FileID, - *InstantiationSet.second.front()); - for (auto Function : InstantiationSet.second) { - auto SubView = llvm::make_unique<SourceCoverageView>( - View, InterestingRange.first, InterestingRange.second, - Function->PrettyName); - createInstantiationSubView(SourceFile, *Function, *SubView); - View.addChild(std::move(SubView)); + for (auto Function : Coverage.getInstantiations(SourceFile)) { + auto SubViewCoverage = Coverage.getCoverageForFunction(*Function); + auto SubViewExpansions = SubViewCoverage.getExpansions(); + auto SubView = llvm::make_unique<SourceCoverageView>( + SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage)); + attachExpansionSubViews(*SubView, SubViewExpansions, Coverage); + + if (SubView) { + unsigned FileID = Function->CountedRegions.front().FileID; + unsigned Line = 0; + for (const auto &CR : Function->CountedRegions) + if (CR.FileID == FileID) + Line = std::max(CR.LineEnd, Line); + View->addInstantiation(Function->Name, Line, std::move(SubView)); } } - return false; + return View; } -bool CodeCoverageTool::load() { - auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename); - if (auto EC = CounterMappingBuff.getError()) { - error(EC.message(), ObjectFilename); - return true; +std::unique_ptr<CoverageMapping> CodeCoverageTool::load() { + auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename); + if (std::error_code EC = CoverageOrErr.getError()) { + colored_ostream(errs(), raw_ostream::RED) + << "error: Failed to load coverage: " << EC.message(); + errs() << "\n"; + return nullptr; } - ObjectFileCoverageMappingReader MappingReader(CounterMappingBuff.get()); - if (auto EC = MappingReader.readHeader()) { - error(EC.message(), ObjectFilename); - return true; + auto Coverage = std::move(CoverageOrErr.get()); + unsigned Mismatched = Coverage->getMismatchedCount(); + if (Mismatched) { + colored_ostream(errs(), raw_ostream::RED) + << "warning: " << Mismatched << " functions have mismatched data. "; + errs() << "\n"; } - std::vector<uint64_t> Counts; - for (const auto &I : MappingReader) { - FunctionCoverageMapping Function(I.FunctionName, I.Filenames); - - // Create the mapping regions with evaluated execution counts - Counts.clear(); - PGOReader->getFunctionCounts(Function.Name, I.FunctionHash, Counts); - - // Get the biggest referenced counters - bool RegionError = false; - CounterMappingContext Ctx(I.Expressions, Counts); - for (const auto &R : I.MappingRegions) { - // Compute the values of mapped regions - if (ViewOpts.Debug) { - outs() << "File " << R.FileID << "| " << R.LineStart << ":" - << R.ColumnStart << " -> " << R.LineEnd << ":" << R.ColumnEnd - << " = "; - Ctx.dump(R.Count); - if (R.Kind == CounterMappingRegion::ExpansionRegion) { - outs() << " (Expanded file id = " << R.ExpandedFileID << ") "; + if (CompareFilenamesOnly) { + auto CoveredFiles = Coverage.get()->getUniqueSourceFiles(); + for (auto &SF : SourceFiles) { + StringRef SFBase = sys::path::filename(SF); + for (const auto &CF : CoveredFiles) + if (SFBase == sys::path::filename(CF)) { + RemappedFilenames[CF] = SF; + SF = CF; + break; } - outs() << "\n"; - } - std::error_code Error; - Function.MappingRegions.push_back( - MappingRegion(R, Ctx.evaluate(R.Count, Error))); - if (Error && !RegionError) { - colored_ostream(errs(), raw_ostream::RED) - << "error: Regions and counters don't match in a function '" - << Function.PrettyName << "' (re-run the instrumented binary)."; - errs() << "\n"; - RegionError = true; - } } - - if (RegionError || !Filters.matches(Function)) - continue; + } - FunctionMappingRecords.push_back(Function); - } - return false; + return Coverage; } int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { @@ -437,11 +230,15 @@ PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + cl::opt<std::string, true> ObjectFilename( + cl::Positional, cl::Required, cl::location(this->ObjectFilename), + cl::desc("Covered executable or object file.")); + cl::list<std::string> InputSourceFiles( cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore); - cl::opt<std::string> PGOFilename( - "instr-profile", cl::Required, + cl::opt<std::string, true> PGOFilename( + "instr-profile", cl::Required, cl::location(this->PGOFilename), cl::desc( "File with the profile data obtained after an instrumented run")); @@ -450,7 +247,8 @@ cl::opt<bool> FilenameEquivalence( "filename-equivalence", cl::Optional, - cl::desc("Compare the filenames instead of full filepaths")); + cl::desc("Treat source files as equivalent to paths in the coverage data " + "when the file names match, even if the full paths do not")); cl::OptionCategory FilteringCategory("Function filtering options"); @@ -494,11 +292,6 @@ ViewOpts.Debug = DebugDump; CompareFilenamesOnly = FilenameEquivalence; - if (auto EC = IndexedInstrProfReader::create(PGOFilename, PGOReader)) { - error(EC.message(), PGOFilename); - return 1; - } - // Create the function filters if (!NameFilters.empty() || !NameRegexFilters.empty()) { auto NameFilterer = new CoverageFilters; @@ -529,27 +322,18 @@ Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer)); } - SourceFiles = InputSourceFiles; + for (const auto &File : InputSourceFiles) { + SmallString<128> Path(File); + if (!CompareFilenamesOnly) + if (std::error_code EC = sys::fs::make_absolute(Path)) { + errs() << "error: " << File << ": " << EC.message(); + return 1; + } + SourceFiles.push_back(Path.str()); + } return 0; }; - // Parse the object filename - if (argc > 1) { - StringRef Arg(argv[1]); - if (Arg.equals_lower("-help") || Arg.equals_lower("-version")) { - cl::ParseCommandLineOptions(2, argv, "LLVM code coverage tool\n"); - return 0; - } - ObjectFilename = Arg; - - argv[1] = argv[0]; - --argc; - ++argv; - } else { - errs() << sys::path::filename(argv[0]) << ": No executable file given!\n"; - return 1; - } - switch (Cmd) { case Show: return show(argc, argv, commandLineParser); @@ -605,29 +389,28 @@ ViewOpts.ShowExpandedRegions = ShowExpansions; ViewOpts.ShowFunctionInstantiations = ShowInstantiations; - if (load()) + auto Coverage = load(); + if (!Coverage) return 1; if (!Filters.empty()) { // Show functions - for (const auto &Function : FunctionMappingRecords) { - unsigned MainFileID; - if (findMainViewFileID(Function, MainFileID)) + for (const auto &Function : Coverage->getCoveredFunctions()) { + if (!Filters.matches(Function)) continue; - StringRef SourceFile = Function.Filenames[MainFileID]; - auto SourceBuffer = getSourceFile(SourceFile); - if (!SourceBuffer) - return 1; - auto Range = findExpandedFileInterestingLineRange(MainFileID, Function); - SourceCoverageView mainView(SourceBuffer.get(), ViewOpts, Range.first, - Range.second); - createSourceFileView(SourceFile, mainView, Function, true); - ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) - << Function.PrettyName << " from " << SourceFile << ":"; + + auto mainView = createFunctionView(Function, *Coverage); + if (!mainView) { + ViewOpts.colored_ostream(outs(), raw_ostream::RED) + << "warning: Could not read coverage for '" << Function.Name; + outs() << "\n"; + continue; + } + ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << Function.Name + << ":"; outs() << "\n"; - mainView.render(outs()); - if (FunctionMappingRecords.size() > 1) - outs() << "\n"; + mainView->render(outs(), /*WholeFile=*/false); + outs() << "\n"; } return 0; } @@ -635,23 +418,14 @@ // Show files bool ShowFilenames = SourceFiles.size() != 1; - if (SourceFiles.empty()) { + if (SourceFiles.empty()) // Get the source files from the function coverage mapping - std::set<StringRef> UniqueFilenames; - for (const auto &Function : FunctionMappingRecords) { - for (const auto &Filename : Function.Filenames) - UniqueFilenames.insert(Filename); - } - for (const auto &Filename : UniqueFilenames) + for (StringRef Filename : Coverage->getUniqueSourceFiles()) SourceFiles.push_back(Filename); - } for (const auto &SourceFile : SourceFiles) { - auto SourceBuffer = getSourceFile(SourceFile); - if (!SourceBuffer) - return 1; - SourceCoverageView mainView(SourceBuffer.get(), ViewOpts); - if (createSourceFileView(SourceFile, mainView, FunctionMappingRecords)) { + auto mainView = createSourceFileView(SourceFile, *Coverage); + if (!mainView) { ViewOpts.colored_ostream(outs(), raw_ostream::RED) << "warning: The file '" << SourceFile << "' isn't covered."; outs() << "\n"; @@ -662,7 +436,7 @@ ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":"; outs() << "\n"; } - mainView.render(outs()); + mainView->render(outs(), /*Wholefile=*/true); if (SourceFiles.size() > 1) outs() << "\n"; } @@ -681,27 +455,24 @@ ViewOpts.Colors = !NoColors; - if (load()) + auto Coverage = load(); + if (!Coverage) return 1; - CoverageSummary Summarizer; - Summarizer.createSummaries(FunctionMappingRecords); - CoverageReport Report(ViewOpts, Summarizer); - if (SourceFiles.empty() && Filters.empty()) { + CoverageReport Report(ViewOpts, std::move(Coverage)); + if (SourceFiles.empty()) Report.renderFileReports(llvm::outs()); - return 0; - } - - Report.renderFunctionReports(llvm::outs()); + else + Report.renderFunctionReports(SourceFiles, llvm::outs()); return 0; } -int show_main(int argc, const char **argv) { +int showMain(int argc, const char *argv[]) { CodeCoverageTool Tool; return Tool.run(CodeCoverageTool::Show, argc, argv); } -int report_main(int argc, const char **argv) { +int reportMain(int argc, const char *argv[]) { CodeCoverageTool Tool; return Tool.run(CodeCoverageTool::Report, argc, argv); }