#include <system_error>
namespace llvm {
+class IndexedInstrProfReader;
namespace coverage {
+class ObjectFileCoverageMappingReader;
+
+class CoverageMapping;
struct CounterExpressions;
enum CoverageMappingVersion { CoverageMappingVersion1 };
};
/// \brief Code coverage information for a single function.
-struct FunctionCoverageMapping {
+struct FunctionRecord {
/// \brief Raw function name.
std::string Name;
/// \brief Associated files.
/// \brief Regions in the function along with their counts.
std::vector<CountedRegion> CountedRegions;
- FunctionCoverageMapping(StringRef Name, ArrayRef<StringRef> Filenames)
+ FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames)
: Name(Name), Filenames(Filenames.begin(), Filenames.end()) {}
};
+/// \brief Coverage information for a macro expansion or #included file.
+///
+/// When covered code has pieces that can be expanded for more detail, such as a
+/// preprocessor macro use and its definition, these are represented as
+/// expansions whose coverage can be looked up independently.
+struct ExpansionRecord {
+ /// \brief The abstract file this expansion covers.
+ unsigned FileID;
+ /// \brief The region that expands to this record.
+ const CountedRegion &Region;
+ /// \brief Coverage for the expansion.
+ const FunctionRecord &Function;
+
+ ExpansionRecord(const CountedRegion &Region,
+ const FunctionRecord &Function)
+ : FileID(Region.ExpandedFileID), Region(Region), Function(Function) {}
+};
+
+/// \brief The execution count information starting at a point in a file.
+///
+/// A sequence of CoverageSegments gives execution counts for a file in format
+/// that's simple to iterate through for processing.
+struct CoverageSegment {
+ /// \brief The line where this segment begins.
+ unsigned Line;
+ /// \brief The column where this segment begins.
+ unsigned Col;
+ /// \brief The execution count, or zero if no count was recorded.
+ uint64_t Count;
+ /// \brief When false, the segment was uninstrumented or skipped.
+ bool HasCount;
+ /// \brief Whether this enters a new region or returns to a previous count.
+ bool IsRegionEntry;
+
+ CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry)
+ : Line(Line), Col(Col), Count(0), HasCount(false),
+ IsRegionEntry(IsRegionEntry) {}
+ void setCount(uint64_t NewCount) {
+ Count = NewCount;
+ HasCount = true;
+ }
+};
+
+/// \brief Coverage information to be processed or displayed.
+///
+/// This represents the coverage of an entire file, expansion, or function. It
+/// provides a sequence of CoverageSegments to iterate through, as well as the
+/// list of expansions that can be further processed.
+class CoverageData {
+ std::string Filename;
+ std::vector<CoverageSegment> Segments;
+ std::vector<ExpansionRecord> Expansions;
+ friend class CoverageMapping;
+
+public:
+ CoverageData() {}
+
+ CoverageData(StringRef Filename) : Filename(Filename) {}
+
+ CoverageData(CoverageData &&RHS)
+ : Filename(std::move(RHS.Filename)), Segments(std::move(RHS.Segments)),
+ Expansions(std::move(RHS.Expansions)) {}
+
+ /// \brief Get the name of the file this data covers.
+ StringRef getFilename() { return Filename; }
+
+ std::vector<CoverageSegment>::iterator begin() { return Segments.begin(); }
+ std::vector<CoverageSegment>::iterator end() { return Segments.end(); }
+ bool empty() { return Segments.empty(); }
+
+ /// \brief Expansions that can be further processed.
+ std::vector<ExpansionRecord> getExpansions() { return Expansions; }
+};
+
+/// \brief The mapping of profile information to coverage data.
+///
+/// This is the main interface to get coverage information, using a profile to
+/// fill out execution counts.
+class CoverageMapping {
+ std::vector<FunctionRecord> Functions;
+ unsigned MismatchedFunctionCount;
+
+ CoverageMapping() : MismatchedFunctionCount(0) {}
+
+public:
+ /// Load the coverage mapping using the given readers.
+ static ErrorOr<std::unique_ptr<CoverageMapping>>
+ load(ObjectFileCoverageMappingReader &CoverageReader,
+ IndexedInstrProfReader &ProfileReader);
+
+ /// \brief The number of functions that couldn't have their profiles mapped.
+ ///
+ /// This is a count of functions whose profile is out of date or otherwise
+ /// can't be associated with any coverage information.
+ unsigned getMismatchedCount() { return MismatchedFunctionCount; }
+
+ /// \brief Returns the list of files that are covered.
+ std::vector<StringRef> getUniqueSourceFiles();
+
+ /// \brief Get the coverage for a particular file.
+ ///
+ /// The given filename must be the name as recorded in the coverage
+ /// information. That is, only names returned from getUniqueSourceFiles will
+ /// yield a result.
+ CoverageData getCoverageForFile(StringRef Filename);
+
+ /// \brief Gets all of the functions covered by this profile.
+ ArrayRef<FunctionRecord> getCoveredFunctions() {
+ return ArrayRef<FunctionRecord>(Functions.data(), Functions.size());
+ }
+
+ /// \brief Get the list of function instantiations in the file.
+ ///
+ /// Fucntions that are instantiated more than once, such as C++ template
+ /// specializations, have distinct coverage records for each instantiation.
+ std::vector<const FunctionRecord *> getInstantiations(StringRef Filename);
+
+ /// \brief Get the coverage for a particular function.
+ CoverageData getCoverageForFunction(const FunctionRecord &Function);
+
+ /// \brief Get the coverage for an expansion within a coverage set.
+ CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion);
+};
+
} // end namespace coverage
} // end namespace llvm
//===----------------------------------------------------------------------===//
#include "llvm/ProfileData/CoverageMapping.h"
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ProfileData/CoverageMappingReader.h"
+#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
}
llvm_unreachable("Unhandled CounterKind");
}
+
+ErrorOr<std::unique_ptr<CoverageMapping>>
+CoverageMapping::load(ObjectFileCoverageMappingReader &CoverageReader,
+ IndexedInstrProfReader &ProfileReader) {
+ auto Coverage = std::unique_ptr<CoverageMapping>(new CoverageMapping());
+
+ std::vector<uint64_t> Counts;
+ for (const auto &Record : CoverageReader) {
+ Counts.clear();
+ if (std::error_code EC = ProfileReader.getFunctionCounts(
+ Record.FunctionName, Record.FunctionHash, Counts)) {
+ if (EC != instrprof_error::hash_mismatch &&
+ EC != instrprof_error::unknown_function)
+ return EC;
+ Coverage->MismatchedFunctionCount++;
+ continue;
+ }
+
+ FunctionRecord Function(Record.FunctionName, Record.Filenames);
+ CounterMappingContext Ctx(Record.Expressions, Counts);
+ for (const auto &Region : Record.MappingRegions) {
+ ErrorOr<int64_t> ExecutionCount = Ctx.evaluate(Region.Count);
+ if (!ExecutionCount)
+ break;
+ Function.CountedRegions.push_back(CountedRegion(Region, *ExecutionCount));
+ }
+ if (Function.CountedRegions.size() != Record.MappingRegions.size()) {
+ Coverage->MismatchedFunctionCount++;
+ continue;
+ }
+
+ Coverage->Functions.push_back(Function);
+ }
+
+ return std::move(Coverage);
+}
+
+namespace {
+/// \brief Distributes functions into instantiation sets.
+///
+/// An instantiation set is a collection of functions that have the same source
+/// code, ie, template functions specializations.
+class FunctionInstantiationSetCollector {
+ typedef DenseMap<std::pair<unsigned, unsigned>,
+ std::vector<const FunctionRecord *>> MapT;
+ MapT InstantiatedFunctions;
+
+public:
+ void insert(const FunctionRecord &Function, unsigned FileID) {
+ auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
+ while (I != E && I->FileID != FileID)
+ ++I;
+ assert(I != E && "function does not cover the given file");
+ auto &Functions = InstantiatedFunctions[I->startLoc()];
+ Functions.push_back(&Function);
+ }
+
+ MapT::iterator begin() { return InstantiatedFunctions.begin(); }
+
+ MapT::iterator end() { return InstantiatedFunctions.end(); }
+};
+
+class SegmentBuilder {
+ std::vector<CoverageSegment> Segments;
+ SmallVector<const CountedRegion *, 8> ActiveRegions;
+
+ /// Start a segment with no count specified.
+ void startSegment(unsigned Line, unsigned Col) {
+ Segments.emplace_back(Line, Col, /*IsRegionEntry=*/false);
+ }
+
+ /// Start a segment with the given Region's count.
+ void startSegment(unsigned Line, unsigned Col, bool IsRegionEntry,
+ const CountedRegion &Region) {
+ if (Segments.empty())
+ Segments.emplace_back(Line, Col, IsRegionEntry);
+ CoverageSegment S = Segments.back();
+ // Avoid creating empty regions.
+ if (S.Line != Line || S.Col != Col) {
+ Segments.emplace_back(Line, Col, IsRegionEntry);
+ S = Segments.back();
+ }
+ // Set this region's count.
+ if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion)
+ Segments.back().setCount(Region.ExecutionCount);
+ }
+
+ /// Start a segment for the given region.
+ void startSegment(const CountedRegion &Region) {
+ startSegment(Region.LineStart, Region.ColumnStart, true, Region);
+ }
+
+ /// Pop the top region off of the active stack, starting a new segment with
+ /// the containing Region's count.
+ void popRegion() {
+ const CountedRegion *Active = ActiveRegions.back();
+ unsigned Line = Active->LineEnd, Col = Active->ColumnEnd;
+ ActiveRegions.pop_back();
+ if (ActiveRegions.empty())
+ startSegment(Line, Col);
+ else
+ startSegment(Line, Col, false, *ActiveRegions.back());
+ }
+
+public:
+ /// Build a list of CoverageSegments from a sorted list of Regions.
+ std::vector<CoverageSegment> buildSegments(ArrayRef<CountedRegion> Regions) {
+ for (const auto &Region : Regions) {
+ // Pop any regions that end before this one starts.
+ while (!ActiveRegions.empty() &&
+ ActiveRegions.back()->endLoc() <= Region.startLoc())
+ popRegion();
+ // Add this region to the stack.
+ ActiveRegions.push_back(&Region);
+ startSegment(Region);
+ }
+ // Pop any regions that are left in the stack.
+ while (!ActiveRegions.empty())
+ popRegion();
+ return Segments;
+ }
+};
+}
+
+std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() {
+ std::vector<StringRef> Filenames;
+ for (const auto &Function : getCoveredFunctions())
+ for (const auto &Filename : Function.Filenames)
+ Filenames.push_back(Filename);
+ std::sort(Filenames.begin(), Filenames.end());
+ auto Last = std::unique(Filenames.begin(), Filenames.end());
+ Filenames.erase(Last, Filenames.end());
+ return Filenames;
+}
+
+static Optional<unsigned> findMainViewFileID(StringRef SourceFile,
+ const FunctionRecord &Function) {
+ 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 (SourceFile == Function.Filenames[I])
+ FilenameEquivalence[I] = true;
+ for (const auto &CR : Function.CountedRegions)
+ if (CR.Kind == CounterMappingRegion::ExpansionRegion &&
+ FilenameEquivalence[CR.FileID])
+ IsExpandedFile[CR.ExpandedFileID] = true;
+ for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
+ if (FilenameEquivalence[I] && !IsExpandedFile[I])
+ return I;
+ return None;
+}
+
+static Optional<unsigned> findMainViewFileID(const FunctionRecord &Function) {
+ llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false);
+ for (const auto &CR : Function.CountedRegions)
+ if (CR.Kind == CounterMappingRegion::ExpansionRegion)
+ IsExpandedFile[CR.ExpandedFileID] = true;
+ for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
+ if (!IsExpandedFile[I])
+ return I;
+ return None;
+}
+
+static SmallSet<unsigned, 8> gatherFileIDs(StringRef SourceFile,
+ const FunctionRecord &Function) {
+ SmallSet<unsigned, 8> IDs;
+ for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I)
+ if (SourceFile == Function.Filenames[I])
+ IDs.insert(I);
+ return IDs;
+}
+
+/// Sort a nested sequence of regions from a single file.
+template <class It> static void sortNestedRegions(It First, It Last) {
+ std::sort(First, Last,
+ [](const CountedRegion &LHS, const CountedRegion &RHS) {
+ if (LHS.startLoc() == RHS.startLoc())
+ // When LHS completely contains RHS, we sort LHS first.
+ return RHS.endLoc() < LHS.endLoc();
+ return LHS.startLoc() < RHS.startLoc();
+ });
+}
+
+static bool isExpansion(const CountedRegion &R, unsigned FileID) {
+ return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
+}
+
+CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) {
+ CoverageData FileCoverage(Filename);
+ std::vector<coverage::CountedRegion> Regions;
+
+ for (const auto &Function : Functions) {
+ auto MainFileID = findMainViewFileID(Filename, Function);
+ if (!MainFileID)
+ continue;
+ auto FileIDs = gatherFileIDs(Filename, Function);
+ for (const auto &CR : Function.CountedRegions)
+ if (FileIDs.count(CR.FileID)) {
+ Regions.push_back(CR);
+ if (isExpansion(CR, *MainFileID))
+ FileCoverage.Expansions.emplace_back(CR, Function);
+ }
+ }
+
+ sortNestedRegions(Regions.begin(), Regions.end());
+ FileCoverage.Segments = SegmentBuilder().buildSegments(Regions);
+
+ return FileCoverage;
+}
+
+std::vector<const FunctionRecord *>
+CoverageMapping::getInstantiations(StringRef Filename) {
+ FunctionInstantiationSetCollector InstantiationSetCollector;
+ for (const auto &Function : Functions) {
+ auto MainFileID = findMainViewFileID(Filename, Function);
+ if (!MainFileID)
+ continue;
+ InstantiationSetCollector.insert(Function, *MainFileID);
+ }
+
+ std::vector<const FunctionRecord *> Result;
+ for (const auto &InstantiationSet : InstantiationSetCollector) {
+ if (InstantiationSet.second.size() < 2)
+ continue;
+ for (auto Function : InstantiationSet.second)
+ Result.push_back(Function);
+ }
+ return Result;
+}
+
+CoverageData
+CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) {
+ auto MainFileID = findMainViewFileID(Function);
+ if (!MainFileID)
+ return CoverageData();
+
+ CoverageData FunctionCoverage(Function.Filenames[*MainFileID]);
+ std::vector<coverage::CountedRegion> Regions;
+ for (const auto &CR : Function.CountedRegions)
+ if (CR.FileID == *MainFileID) {
+ Regions.push_back(CR);
+ if (isExpansion(CR, *MainFileID))
+ FunctionCoverage.Expansions.emplace_back(CR, Function);
+ }
+
+ sortNestedRegions(Regions.begin(), Regions.end());
+ FunctionCoverage.Segments = SegmentBuilder().buildSegments(Regions);
+
+ return FunctionCoverage;
+}
+
+CoverageData
+CoverageMapping::getCoverageForExpansion(const ExpansionRecord &Expansion) {
+ CoverageData ExpansionCoverage(
+ Expansion.Function.Filenames[Expansion.FileID]);
+ std::vector<coverage::CountedRegion> Regions;
+ for (const auto &CR : Expansion.Function.CountedRegions)
+ if (CR.FileID == Expansion.FileID) {
+ Regions.push_back(CR);
+ if (isExpansion(CR, Expansion.FileID))
+ ExpansionCoverage.Expansions.emplace_back(CR, Expansion.Function);
+ }
+
+ sortNestedRegions(Regions.begin(), Regions.end());
+ ExpansionCoverage.Segments = SegmentBuilder().buildSegments(Regions);
+
+ return ExpansionCoverage;
+}
CoverageReport.cpp
CoverageSummary.cpp
CoverageSummaryInfo.cpp
- SourceCoverageDataManager.cpp
SourceCoverageView.cpp
TestingSupport.cpp
)
#include "RenderingSupport.h"
#include "CoverageViewOptions.h"
#include "CoverageFilters.h"
-#include "SourceCoverageDataManager.h"
#include "SourceCoverageView.h"
#include "CoverageSummary.h"
#include "CoverageReport.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/ProfileData/CoverageMapping.h"
#include "llvm/ProfileData/CoverageMappingReader.h"
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, ie, template functions specializations.
-class FunctionInstantiationSetCollector {
- typedef DenseMap<std::pair<unsigned, unsigned>,
- std::vector<const FunctionCoverageMapping *>> MapT;
- MapT InstantiatedFunctions;
-
-public:
- void insert(const FunctionCoverageMapping &Function, unsigned FileID) {
- auto I = Function.CountedRegions.begin(), E = Function.CountedRegions.end();
- while (I != E && I->FileID != FileID)
- ++I;
- assert(I != E && "function does not cover the given file");
- auto &Functions = InstantiatedFunctions[I->startLoc()];
- Functions.push_back(&Function);
- }
-
- MapT::iterator begin() {
- return InstantiatedFunctions.begin();
- }
-
- MapT::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 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 Create source views for the expansions of the view.
+ void attachExpansionSubViews(SourceCoverageView &View,
+ ArrayRef<ExpansionRecord> Expansions,
+ CoverageMapping &Coverage);
- /// \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 a source view which shows coverage for an expansion
- /// of a file.
- std::unique_ptr<SourceCoverageView>
- createExpansionSubView(const CountedRegion &ExpandedRegion,
- const FunctionCoverageMapping &Function);
-
- void attachExpansionSubViews(SourceCoverageView &View, unsigned ViewFileID,
- const FunctionCoverageMapping &Function);
-
- /// \brief Create a source view which shows coverage for an instantiation
- /// of a funciton.
+ /// \brief Create the source view of a particular function.
std::unique_ptr<SourceCoverageView>
- createInstantiationSubView(StringRef SourceFile,
- const FunctionCoverageMapping &Function);
+ createFunctionView(const FunctionRecord &Function, CoverageMapping &Coverage);
/// \brief Create the main source view of a particular source file.
std::unique_ptr<SourceCoverageView>
- createSourceFileView(StringRef SourceFile,
- ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
- bool UseOnlyRegionsInMainFile = false);
+ 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);
StringRef 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;
};
}
-static std::vector<StringRef>
-getUniqueFilenames(ArrayRef<FunctionCoverageMapping> FunctionMappingRecords) {
- std::vector<StringRef> Filenames;
- for (const auto &Function : FunctionMappingRecords)
- for (const auto &Filename : Function.Filenames)
- Filenames.push_back(Filename);
- std::sort(Filenames.begin(), Filenames.end());
- auto Last = std::unique(Filenames.begin(), Filenames.end());
- Filenames.erase(Last, Filenames.end());
- return Filenames;
-}
-
void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
errs() << "error: ";
if (!Whence.empty())
return *LoadedSourceFiles.back().second;
}
-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 (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 (SourceFile == Function.Filenames[I])
- FilenameEquivalence[I] = true;
- }
- for (const auto &CR : Function.CountedRegions) {
- if (CR.Kind == CounterMappingRegion::ExpansionRegion &&
- FilenameEquivalence[CR.FileID])
- IsExpandedFile[CR.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 &CR : Function.CountedRegions) {
- if (CR.Kind == CounterMappingRegion::ExpansionRegion)
- IsExpandedFile[CR.ExpandedFileID] = true;
- }
- for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
- if (IsExpandedFile[I])
- continue;
- MainViewFileID = I;
- return false;
- }
- return true;
-}
-
-std::unique_ptr<SourceCoverageView> CodeCoverageTool::createExpansionSubView(
- const CountedRegion &ExpandedRegion,
- const FunctionCoverageMapping &Function) {
- auto SourceBuffer =
- getSourceFile(Function.Filenames[ExpandedRegion.ExpandedFileID]);
- if (!SourceBuffer)
- return nullptr;
- auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
- for (const auto &CR : Function.CountedRegions) {
- if (CR.FileID == ExpandedRegion.ExpandedFileID)
- RegionManager->insert(CR);
- }
- auto SubView = llvm::make_unique<SourceCoverageView>(SourceBuffer.get(),
- ViewOpts);
- SubView->load(std::move(RegionManager));
- attachExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID, Function);
- return SubView;
-}
-
-void CodeCoverageTool::attachExpansionSubViews(
- SourceCoverageView &View, unsigned ViewFileID,
- const FunctionCoverageMapping &Function) {
+void
+CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View,
+ ArrayRef<ExpansionRecord> Expansions,
+ CoverageMapping &Coverage) {
if (!ViewOpts.ShowExpandedRegions)
return;
- for (const auto &CR : Function.CountedRegions) {
- if (CR.Kind != CounterMappingRegion::ExpansionRegion)
+ for (const auto &Expansion : Expansions) {
+ auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
+ if (ExpansionCoverage.empty())
continue;
- if (CR.FileID != ViewFileID)
+ auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
+ if (!SourceBuffer)
continue;
- auto SubView = createExpansionSubView(CR, Function);
- if (SubView)
- View.addExpansion(CR, std::move(SubView));
+
+ 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));
}
}
std::unique_ptr<SourceCoverageView>
-CodeCoverageTool::createInstantiationSubView(
- StringRef SourceFile, const FunctionCoverageMapping &Function) {
- auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
- SmallSet<unsigned, 8> InterestingFileIDs;
- if (!gatherInterestingFileIDs(SourceFile, Function, InterestingFileIDs))
+CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
+ CoverageMapping &Coverage) {
+ auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
+ if (FunctionCoverage.empty())
return nullptr;
- // Get the interesting regions
- for (const auto &CR : Function.CountedRegions) {
- if (InterestingFileIDs.count(CR.FileID))
- RegionManager->insert(CR);
- }
-
- auto SourceBuffer = getSourceFile(SourceFile);
+ auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
if (!SourceBuffer)
return nullptr;
- auto SubView = llvm::make_unique<SourceCoverageView>(SourceBuffer.get(),
- ViewOpts);
- SubView->load(std::move(RegionManager));
- unsigned MainFileID;
- if (!findMainViewFileID(SourceFile, Function, MainFileID))
- attachExpansionSubViews(*SubView, MainFileID, Function);
- return SubView;
-}
-std::unique_ptr<SourceCoverageView> CodeCoverageTool::createSourceFileView(
- StringRef SourceFile,
- ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
- bool UseOnlyRegionsInMainFile) {
- auto RegionManager = llvm::make_unique<SourceCoverageDataManager>();
- FunctionInstantiationSetCollector InstantiationSetCollector;
+ auto Expansions = FunctionCoverage.getExpansions();
+ auto View = llvm::make_unique<SourceCoverageView>(
+ SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage));
+ attachExpansionSubViews(*View, Expansions, Coverage);
+
+ return View;
+}
+std::unique_ptr<SourceCoverageView>
+CodeCoverageTool::createSourceFileView(StringRef SourceFile,
+ CoverageMapping &Coverage) {
auto SourceBuffer = getSourceFile(SourceFile);
if (!SourceBuffer)
return nullptr;
- auto View =
- llvm::make_unique<SourceCoverageView>(SourceBuffer.get(), ViewOpts);
-
- 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 &CR : Function.CountedRegions) {
- if (InterestingFileIDs.count(CR.FileID))
- RegionManager->insert(CR);
- }
- InstantiationSetCollector.insert(Function, MainFileID);
- attachExpansionSubViews(*View, MainFileID, Function);
- }
- if (RegionManager->getCoverageSegments().empty())
+ auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
+ if (FileCoverage.empty())
return nullptr;
- View->load(std::move(RegionManager));
- // Show instantiations
- if (!ViewOpts.ShowFunctionInstantiations)
- return View;
- for (const auto &InstantiationSet : InstantiationSetCollector) {
- if (InstantiationSet.second.size() < 2)
- continue;
- for (auto Function : InstantiationSet.second) {
+
+ 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);
- auto SubView = createInstantiationSubView(SourceFile, *Function);
- if (SubView)
- View->addInstantiation(Function->Name, Line, std::move(SubView));
+ View->addInstantiation(Function->Name, Line, std::move(SubView));
}
}
return View;
}
-bool CodeCoverageTool::load() {
+std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename);
if (auto EC = CounterMappingBuff.getError()) {
error(EC.message(), ObjectFilename);
- return true;
+ return nullptr;
}
ObjectFileCoverageMappingReader MappingReader(CounterMappingBuff.get());
if (auto EC = MappingReader.readHeader()) {
error(EC.message(), ObjectFilename);
- return true;
+ return nullptr;
}
- 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) {
- ErrorOr<int64_t> ExecutionCount = Ctx.evaluate(R.Count);
- if (ExecutionCount) {
- Function.CountedRegions.push_back(CountedRegion(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;
+ std::unique_ptr<IndexedInstrProfReader> PGOReader;
+ if (auto EC = IndexedInstrProfReader::create(PGOFilename, PGOReader)) {
+ error(EC.message(), PGOFilename);
+ return nullptr;
+ }
- FunctionMappingRecords.push_back(Function);
+ auto CoverageOrErr = CoverageMapping::load(MappingReader, *PGOReader);
+ if (std::error_code EC = CoverageOrErr.getError()) {
+ colored_ostream(errs(), raw_ostream::RED)
+ << "error: Failed to load coverage: " << EC.message();
+ errs() << "\n";
+ return nullptr;
+ }
+ 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";
}
if (CompareFilenamesOnly) {
- auto CoveredFiles = getUniqueFilenames(FunctionMappingRecords);
+ auto CoveredFiles = Coverage.get()->getUniqueSourceFiles();
for (auto &SF : SourceFiles) {
StringRef SFBase = sys::path::filename(SF);
for (const auto &CF : CoveredFiles)
}
}
- return false;
+ return Coverage;
}
int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
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"));
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;
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 mainView = createSourceFileView(SourceFile, Function, true);
+
+ auto mainView = createFunctionView(Function, *Coverage);
if (!mainView) {
ViewOpts.colored_ostream(outs(), raw_ostream::RED)
- << "warning: Could not read coverage for '" << Function.Name
- << " from " << SourceFile;
+ << "warning: Could not read coverage for '" << Function.Name;
outs() << "\n";
continue;
}
- ViewOpts.colored_ostream(outs(), raw_ostream::CYAN)
- << Function.Name << " from " << SourceFile << ":";
+ ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << Function.Name
+ << ":";
outs() << "\n";
mainView->render(outs(), /*WholeFile=*/false);
- if (FunctionMappingRecords.size() > 1)
- outs() << "\n";
+ outs() << "\n";
}
return 0;
}
if (SourceFiles.empty())
// Get the source files from the function coverage mapping
- for (StringRef Filename : getUniqueFilenames(FunctionMappingRecords))
+ for (StringRef Filename : Coverage->getUniqueSourceFiles())
SourceFiles.push_back(Filename);
for (const auto &SourceFile : SourceFiles) {
- auto mainView = createSourceFileView(SourceFile, FunctionMappingRecords);
+ auto mainView = createSourceFileView(SourceFile, *Coverage);
if (!mainView) {
ViewOpts.colored_ostream(outs(), raw_ostream::RED)
<< "warning: The file '" << SourceFile << "' isn't covered.";
ViewOpts.Colors = !NoColors;
- if (load())
+ auto Coverage = load();
+ if (!Coverage)
return 1;
CoverageSummary Summarizer;
- Summarizer.createSummaries(FunctionMappingRecords);
+ Summarizer.createSummaries(Coverage->getCoveredFunctions());
CoverageReport Report(ViewOpts, Summarizer);
if (SourceFiles.empty() && Filters.empty()) {
Report.renderFileReports(llvm::outs());
using namespace llvm;
-bool NameCoverageFilter::matches(const FunctionCoverageMapping &Function) {
+bool NameCoverageFilter::matches(const coverage::FunctionRecord &Function) {
StringRef FuncName = Function.Name;
return FuncName.find(Name) != StringRef::npos;
}
-bool NameRegexCoverageFilter::matches(const FunctionCoverageMapping &Function) {
+bool
+NameRegexCoverageFilter::matches(const coverage::FunctionRecord &Function) {
return llvm::Regex(Regex).match(Function.Name);
}
-bool RegionCoverageFilter::matches(const FunctionCoverageMapping &Function) {
+bool RegionCoverageFilter::matches(const coverage::FunctionRecord &Function) {
return PassesThreshold(FunctionCoverageSummary::get(Function)
.RegionCoverage.getPercentCovered());
}
-bool LineCoverageFilter::matches(const FunctionCoverageMapping &Function) {
+bool LineCoverageFilter::matches(const coverage::FunctionRecord &Function) {
return PassesThreshold(
FunctionCoverageSummary::get(Function).LineCoverage.getPercentCovered());
}
Filters.push_back(std::move(Filter));
}
-bool CoverageFilters::matches(const FunctionCoverageMapping &Function) {
+bool CoverageFilters::matches(const coverage::FunctionRecord &Function) {
for (const auto &Filter : Filters) {
if (Filter->matches(Function))
return true;
return false;
}
-bool CoverageFiltersMatchAll::matches(const FunctionCoverageMapping &Function) {
+bool
+CoverageFiltersMatchAll::matches(const coverage::FunctionRecord &Function) {
for (const auto &Filter : Filters) {
if (!Filter->matches(Function))
return false;
namespace llvm {
-using coverage::FunctionCoverageMapping;
-
/// \brief Matches specific functions that pass the requirement of this filter.
class CoverageFilter {
public:
virtual ~CoverageFilter() {}
/// \brief Return true if the function passes the requirements of this filter.
- virtual bool matches(const FunctionCoverageMapping &Function) { return true; }
+ virtual bool matches(const coverage::FunctionRecord &Function) {
+ return true;
+ }
};
/// \brief Matches functions that contain a specific string in their name.
public:
NameCoverageFilter(StringRef Name) : Name(Name) {}
- bool matches(const FunctionCoverageMapping &Function) override;
+ bool matches(const coverage::FunctionRecord &Function) override;
};
/// \brief Matches functions whose name matches a certain regular expression.
public:
NameRegexCoverageFilter(StringRef Regex) : Regex(Regex) {}
- bool matches(const FunctionCoverageMapping &Function) override;
+ bool matches(const coverage::FunctionRecord &Function) override;
};
/// \brief Matches numbers that pass a certain threshold.
RegionCoverageFilter(Operation Op, double Threshold)
: StatisticThresholdFilter(Op, Threshold) {}
- bool matches(const FunctionCoverageMapping &Function) override;
+ bool matches(const coverage::FunctionRecord &Function) override;
};
/// \brief Matches functions whose line coverage percentage
LineCoverageFilter(Operation Op, double Threshold)
: StatisticThresholdFilter(Op, Threshold) {}
- bool matches(const FunctionCoverageMapping &Function) override;
+ bool matches(const coverage::FunctionRecord &Function) override;
};
/// \brief A collection of filters.
bool empty() const { return Filters.empty(); }
- bool matches(const FunctionCoverageMapping &Function) override;
+ bool matches(const coverage::FunctionRecord &Function) override;
};
/// \brief A collection of filters.
/// in an instance of this class.
class CoverageFiltersMatchAll : public CoverageFilters {
public:
- bool matches(const FunctionCoverageMapping &Function) override;
+ bool matches(const coverage::FunctionRecord &Function) override;
};
} // namespace llvm
return Filenames.size() - 1;
}
-void CoverageSummary::createSummaries(
- ArrayRef<coverage::FunctionCoverageMapping> Functions) {
+void
+CoverageSummary::createSummaries(ArrayRef<coverage::FunctionRecord> Functions) {
std::vector<std::pair<unsigned, size_t>> FunctionFileIDs;
FunctionFileIDs.resize(Functions.size());
unsigned getFileID(StringRef Filename);
public:
- void createSummaries(ArrayRef<coverage::FunctionCoverageMapping> Functions);
+ void createSummaries(ArrayRef<coverage::FunctionRecord> Functions);
ArrayRef<FileCoverageSummary> getFileSummaries() { return FileSummaries; }
using namespace coverage;
FunctionCoverageSummary
-FunctionCoverageSummary::get(const FunctionCoverageMapping &Function) {
+FunctionCoverageSummary::get(const coverage::FunctionRecord &Function) {
// Compute the region coverage
size_t NumCodeRegions = 0, CoveredRegions = 0;
for (auto &CR : Function.CountedRegions) {
/// \brief Compute the code coverage summary for the given function coverage
/// mapping record.
static FunctionCoverageSummary
- get(const coverage::FunctionCoverageMapping &Function);
+ get(const coverage::FunctionRecord &Function);
};
/// \brief A summary of file's code coverage.
+++ /dev/null
-//===- SourceCoverageDataManager.cpp - Manager for source file coverage
-// data-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class separates and merges mapping regions for a specific source file.
-//
-//===----------------------------------------------------------------------===//
-
-#include "SourceCoverageDataManager.h"
-
-using namespace llvm;
-using namespace coverage;
-
-void SourceCoverageDataManager::insert(const CountedRegion &CR) {
- Regions.push_back(CR);
- Segments.clear();
-}
-
-namespace {
-class SegmentBuilder {
- std::vector<CoverageSegment> Segments;
- SmallVector<const CountedRegion *, 8> ActiveRegions;
-
- /// Start a segment with no count specified.
- void startSegment(unsigned Line, unsigned Col, bool IsRegionEntry) {
- Segments.emplace_back(Line, Col, IsRegionEntry);
- }
-
- /// Start a segment with the given Region's count.
- void startSegment(unsigned Line, unsigned Col, bool IsRegionEntry,
- const CountedRegion &Region) {
- if (Segments.empty())
- Segments.emplace_back(Line, Col, IsRegionEntry);
- CoverageSegment S = Segments.back();
- // Avoid creating empty regions.
- if (S.Line != Line || S.Col != Col) {
- Segments.emplace_back(Line, Col, IsRegionEntry);
- S = Segments.back();
- }
- // Set this region's count.
- if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion)
- Segments.back().setCount(Region.ExecutionCount);
- }
-
- /// Start a segment for the given region.
- void startSegment(const CountedRegion &Region) {
- startSegment(Region.LineStart, Region.ColumnStart, true, Region);
- }
-
- /// Pop the top region off of the active stack, starting a new segment with
- /// the containing Region's count.
- void popRegion() {
- const CountedRegion *Active = ActiveRegions.back();
- unsigned Line = Active->LineEnd, Col = Active->ColumnEnd;
- ActiveRegions.pop_back();
- if (ActiveRegions.empty())
- startSegment(Line, Col, /*IsRegionEntry=*/false);
- else
- startSegment(Line, Col, /*IsRegionEntry=*/false, *ActiveRegions.back());
- }
-
-public:
- /// Build a list of CoverageSegments from a sorted list of Regions.
- std::vector<CoverageSegment>
- buildSegments(ArrayRef<CountedRegion> Regions) {
- for (const auto &Region : Regions) {
- // Pop any regions that end before this one starts.
- while (!ActiveRegions.empty() &&
- ActiveRegions.back()->endLoc() <= Region.startLoc())
- popRegion();
- // Add this region to the stack.
- ActiveRegions.push_back(&Region);
- startSegment(Region);
- }
- // Pop any regions that are left in the stack.
- while (!ActiveRegions.empty())
- popRegion();
- return Segments;
- }
-};
-}
-
-ArrayRef<CoverageSegment> SourceCoverageDataManager::getCoverageSegments() {
- if (Segments.empty()) {
- // Sort the regions given that they're all in the same file at this point.
- std::sort(Regions.begin(), Regions.end(),
- [](const CountedRegion &LHS, const CountedRegion &RHS) {
- if (LHS.startLoc() == RHS.startLoc())
- // When LHS completely contains RHS, we sort LHS first.
- return RHS.endLoc() < LHS.endLoc();
- return LHS.startLoc() < RHS.startLoc();
- });
-
- Segments = SegmentBuilder().buildSegments(Regions);
- }
-
- return Segments;
-}
+++ /dev/null
-//===- SourceCoverageDataManager.h - Manager for source file coverage data-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class separates and merges mapping regions for a specific source file.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_COV_SOURCECOVERAGEDATAMANAGER_H
-#define LLVM_COV_SOURCECOVERAGEDATAMANAGER_H
-
-#include "llvm/ProfileData/CoverageMapping.h"
-#include <vector>
-
-namespace llvm {
-
-struct CoverageSegment {
- unsigned Line;
- unsigned Col;
- bool IsRegionEntry;
- uint64_t Count;
- bool HasCount;
-
- CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry)
- : Line(Line), Col(Col), IsRegionEntry(IsRegionEntry),
- Count(0), HasCount(false) {}
- void setCount(uint64_t NewCount) {
- Count = NewCount;
- HasCount = true;
- }
-};
-
-/// \brief Partions mapping regions by their kind and sums
-/// the execution counts of the regions that start at the same location.
-class SourceCoverageDataManager {
- std::vector<coverage::CountedRegion> Regions;
- std::vector<CoverageSegment> Segments;
-
-public:
- void insert(const coverage::CountedRegion &CR);
-
- /// \brief Return a sequence of non-overlapping coverage segments.
- ArrayRef<CoverageSegment> getCoverageSegments();
-};
-
-} // namespace llvm
-
-#endif // LLVM_COV_SOURCECOVERAGEDATAMANAGER_H
using namespace llvm;
-void SourceCoverageView::renderLine(raw_ostream &OS, StringRef Line,
- int64_t LineNumber,
- const CoverageSegment *WrappedSegment,
- ArrayRef<const CoverageSegment *> Segments,
- unsigned ExpansionCol) {
+void SourceCoverageView::renderLine(
+ raw_ostream &OS, StringRef Line, int64_t LineNumber,
+ const coverage::CoverageSegment *WrappedSegment,
+ ArrayRef<const coverage::CoverageSegment *> Segments,
+ unsigned ExpansionCol) {
Optional<raw_ostream::Colors> Highlight;
SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges;
}
void SourceCoverageView::renderRegionMarkers(
- raw_ostream &OS, ArrayRef<const CoverageSegment *> Segments) {
+ raw_ostream &OS, ArrayRef<const coverage::CoverageSegment *> Segments) {
SmallString<32> Buffer;
raw_svector_ostream BufferOS(Buffer);
auto EndISV = InstantiationSubViews.end();
// Get the coverage information for the file.
- auto CoverageSegments = RegionManager->getCoverageSegments();
- assert(CoverageSegments.size() && "View with no coverage?");
- auto NextSegment = CoverageSegments.begin();
- auto EndSegment = CoverageSegments.end();
+ auto NextSegment = CoverageInfo.begin();
+ auto EndSegment = CoverageInfo.end();
unsigned FirstLine = NextSegment != EndSegment ? NextSegment->Line : 0;
- const CoverageSegment *WrappedSegment = nullptr;
- SmallVector<const CoverageSegment *, 8> LineSegments;
+ const coverage::CoverageSegment *WrappedSegment = nullptr;
+ SmallVector<const coverage::CoverageSegment *, 8> LineSegments;
for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof(); ++LI) {
// If we aren't rendering the whole file, we need to filter out the prologue
// and epilogue.
#define LLVM_COV_SOURCECOVERAGEVIEW_H
#include "CoverageViewOptions.h"
-#include "SourceCoverageDataManager.h"
#include "llvm/ProfileData/CoverageMapping.h"
#include "llvm/Support/MemoryBuffer.h"
#include <vector>
const MemoryBuffer &File;
const CoverageViewOptions &Options;
- std::unique_ptr<SourceCoverageDataManager> RegionManager;
+ coverage::CoverageData CoverageInfo;
std::vector<ExpansionView> ExpansionSubViews;
std::vector<InstantiationView> InstantiationSubViews;
/// \brief Render a source line with highlighting.
void renderLine(raw_ostream &OS, StringRef Line, int64_t LineNumber,
- const CoverageSegment *WrappedSegment,
- ArrayRef<const CoverageSegment *> Segments,
+ const coverage::CoverageSegment *WrappedSegment,
+ ArrayRef<const coverage::CoverageSegment *> Segments,
unsigned ExpansionCol);
void renderIndent(raw_ostream &OS, unsigned Level);
void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo);
/// \brief Render all the region's execution counts on a line.
- void renderRegionMarkers(raw_ostream &OS,
- ArrayRef<const CoverageSegment *> Segments);
+ void
+ renderRegionMarkers(raw_ostream &OS,
+ ArrayRef<const coverage::CoverageSegment *> Segments);
static const unsigned LineCoverageColumnWidth = 7;
static const unsigned LineNumberColumnWidth = 5;
public:
SourceCoverageView(const MemoryBuffer &File,
- const CoverageViewOptions &Options)
- : File(File), Options(Options) {}
+ const CoverageViewOptions &Options,
+ coverage::CoverageData &&CoverageInfo)
+ : File(File), Options(Options), CoverageInfo(std::move(CoverageInfo)) {}
const CoverageViewOptions &getOptions() const { return Options; }
/// \brief Print the code coverage information for a specific
/// portion of a source file to the output stream.
void render(raw_ostream &OS, bool WholeFile, unsigned IndentLevel = 0);
-
- /// \brief Load the coverage information required for rendering
- /// from the mapping regions in the data manager.
- void load(std::unique_ptr<SourceCoverageDataManager> Data) {
- RegionManager = std::move(Data);
- }
};
} // namespace llvm