//
//===----------------------------------------------------------------------===//
-#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/ProfileData/InstrProfReader.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/ProfileData/CoverageMapping.h"
-#include "llvm/ProfileData/CoverageMappingReader.h"
+#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/MemoryObject.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/Signals.h"
#include "llvm/Support/PrettyStackTrace.h"
-#include <system_error>
+#include "llvm/Support/Signals.h"
#include <functional>
+#include <system_error>
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:
/// \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);
-
- bool findMainViewFileID(const FunctionCoverageMapping &Function,
- unsigned &MainViewFileID);
+ /// \brief Create source views for the expansions of the view.
+ void attachExpansionSubViews(SourceCoverageView &View,
+ ArrayRef<ExpansionRecord> Expansions,
+ CoverageMapping &Coverage);
- /// \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);
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;
};
}
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)) {
- return *Files.second;
- }
+ // 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)
+void
+CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View,
+ ArrayRef<ExpansionRecord> Expansions,
+ CoverageMapping &Coverage) {
+ if (!ViewOpts.ShowExpandedRegions)
+ return;
+ for (const auto &Expansion : Expansions) {
+ auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
+ if (ExpansionCoverage.empty())
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])
+ auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
+ if (!SourceBuffer)
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;
+ 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));
}
- 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]);
+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;
- 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));
-}
+ return nullptr;
-void CodeCoverageTool::createExpansionSubViews(
- SourceCoverageView &View, unsigned ViewFileID,
- const FunctionCoverageMapping &Function) {
- if (!ViewOpts.ShowExpandedRegions)
- return;
- for (const auto &Region : Function.MappingRegions) {
- if (Region.Kind != CounterMappingRegion::ExpansionRegion)
- continue;
- if (Region.FileID != ViewFileID)
- continue;
- createExpansionSubView(Region, Function, View);
- }
-}
+ auto Expansions = FunctionCoverage.getExpansions();
+ auto View = llvm::make_unique<SourceCoverageView>(
+ SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage));
+ attachExpansionSubViews(*View, Expansions, Coverage);
-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);
+ return View;
}
-bool CodeCoverageTool::createSourceFileView(
- StringRef SourceFile, SourceCoverageView &View,
- ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
- bool UseOnlyRegionsInMainFile) {
- SourceCoverageDataManager RegionManager;
- FunctionInstantiationSetCollector InstantiationSetCollector;
-
- 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->Name);
- createInstantiationSubView(SourceFile, *Function, *SubView);
- View.addChild(std::move(SubView));
+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 (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";
- }
- ErrorOr<int64_t> ExecutionCount = Ctx.evaluate(R.Count);
- if (ExecutionCount) {
- Function.MappingRegions.push_back(MappingRegion(R, *ExecutionCount));
- } else if (!RegionError) {
- colored_ostream(errs(), raw_ostream::RED)
- << "error: Regions and counters don't match in a function '"
- << Function.Name << "' (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) {
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"));
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");
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;
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);
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.Name << " from " << SourceFile << ":";
- outs() << "\n";
- mainView.render(outs());
- if (FunctionMappingRecords.size() > 1)
+
+ 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(), /*WholeFile=*/false);
+ outs() << "\n";
}
return 0;
}
// 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";
ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":";
outs() << "\n";
}
- mainView.render(outs());
+ mainView->render(outs(), /*Wholefile=*/true);
if (SourceFiles.size() > 1)
outs() << "\n";
}
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);
}