llvm-cov: Fix dropped lines when filters were applied
[oota-llvm.git] / tools / llvm-cov / SourceCoverageDataManager.cpp
1 //===- SourceCoverageDataManager.cpp - Manager for source file coverage
2 // data-===//
3 //
4 //                     The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10 //
11 // This class separates and merges mapping regions for a specific source file.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "SourceCoverageDataManager.h"
16
17 using namespace llvm;
18 using namespace coverage;
19
20 void SourceCoverageDataManager::insert(const CountedRegion &CR) {
21   Regions.push_back(CR);
22   Segments.clear();
23 }
24
25 namespace {
26 class SegmentBuilder {
27   std::vector<CoverageSegment> Segments;
28   SmallVector<const CountedRegion *, 8> ActiveRegions;
29
30   /// Start a segment with no count specified.
31   void startSegment(unsigned Line, unsigned Col, bool IsRegionEntry) {
32     Segments.emplace_back(Line, Col, IsRegionEntry);
33   }
34
35   /// Start a segment with the given Region's count.
36   void startSegment(unsigned Line, unsigned Col, bool IsRegionEntry,
37                     const CountedRegion &Region) {
38     if (Segments.empty())
39       Segments.emplace_back(Line, Col, IsRegionEntry);
40     CoverageSegment S = Segments.back();
41     // Avoid creating empty regions.
42     if (S.Line != Line || S.Col != Col) {
43       Segments.emplace_back(Line, Col, IsRegionEntry);
44       S = Segments.back();
45     }
46     // Set this region's count.
47     if (Region.Kind != coverage::CounterMappingRegion::SkippedRegion)
48       Segments.back().setCount(Region.ExecutionCount);
49   }
50
51   /// Start a segment for the given region.
52   void startSegment(const CountedRegion &Region) {
53     startSegment(Region.LineStart, Region.ColumnStart, true, Region);
54   }
55
56   /// Pop the top region off of the active stack, starting a new segment with
57   /// the containing Region's count.
58   void popRegion() {
59     const CountedRegion *Active = ActiveRegions.back();
60     unsigned Line = Active->LineEnd, Col = Active->ColumnEnd;
61     ActiveRegions.pop_back();
62     if (ActiveRegions.empty())
63       startSegment(Line, Col, /*IsRegionEntry=*/false);
64     else
65       startSegment(Line, Col, /*IsRegionEntry=*/false, *ActiveRegions.back());
66   }
67
68 public:
69   /// Build a list of CoverageSegments from a sorted list of Regions.
70   std::vector<CoverageSegment>
71   buildSegments(ArrayRef<CountedRegion> Regions) {
72     for (const auto &Region : Regions) {
73       // Pop any regions that end before this one starts.
74       while (!ActiveRegions.empty() &&
75              ActiveRegions.back()->endLoc() <= Region.startLoc())
76         popRegion();
77       // Add this region to the stack.
78       ActiveRegions.push_back(&Region);
79       startSegment(Region);
80     }
81     // Pop any regions that are left in the stack.
82     while (!ActiveRegions.empty())
83       popRegion();
84     return Segments;
85   }
86 };
87 }
88
89 ArrayRef<CoverageSegment> SourceCoverageDataManager::getCoverageSegments() {
90   if (Segments.empty()) {
91     // Sort the regions given that they're all in the same file at this point.
92     std::sort(Regions.begin(), Regions.end(),
93               [](const CountedRegion &LHS, const CountedRegion &RHS) {
94       if (LHS.startLoc() == RHS.startLoc())
95         // When LHS completely contains RHS, we sort LHS first.
96         return RHS.endLoc() < LHS.endLoc();
97       return LHS.startLoc() < RHS.startLoc();
98     });
99
100     Segments = SegmentBuilder().buildSegments(Regions);
101   }
102
103   return Segments;
104 }