//===- 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 Segments; SmallVector 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 buildSegments(ArrayRef 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 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; }