summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-cov/SourceCoverageDataManager.cpp
blob: a60ea6e2586d238a4a818d4bef9a9afdd10efb78 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//===- 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;
}
OpenPOWER on IntegriCloud