1 //===- CoverageSummaryInfo.cpp - Coverage summary for function/file -------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // These structures are used to represent code coverage metrics
11 // for functions/files.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "CoverageSummaryInfo.h"
16 
17 using namespace llvm;
18 using namespace coverage;
19 
20 LineCoverageStats::LineCoverageStats(
21     ArrayRef<const coverage::CoverageSegment *> LineSegments,
22     const coverage::CoverageSegment *WrappedSegment, unsigned Line)
23     : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line),
24       LineSegments(LineSegments), WrappedSegment(WrappedSegment) {
25   // Find the minimum number of regions which start in this line.
26   unsigned MinRegionCount = 0;
27   auto isStartOfRegion = [](const coverage::CoverageSegment *S) {
28     return !S->IsGapRegion && S->HasCount && S->IsRegionEntry;
29   };
30   for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I)
31     if (isStartOfRegion(LineSegments[I]))
32       ++MinRegionCount;
33 
34   bool StartOfSkippedRegion = !LineSegments.empty() &&
35                               !LineSegments.front()->HasCount &&
36                               LineSegments.front()->IsRegionEntry;
37 
38   HasMultipleRegions = MinRegionCount > 1;
39   Mapped =
40       !StartOfSkippedRegion &&
41       ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0));
42 
43   if (!Mapped)
44     return;
45 
46   // Pick the max count among regions which start and end on this line, to
47   // avoid erroneously using the wrapped count, and to avoid picking region
48   // counts which come from deferred regions.
49   if (LineSegments.size() > 1) {
50     for (unsigned I = 0; I < LineSegments.size() - 1; ++I) {
51       if (!LineSegments[I]->IsGapRegion)
52         ExecutionCount = std::max(ExecutionCount, LineSegments[I]->Count);
53     }
54     return;
55   }
56 
57   // If a non-gap region starts here, use its count. Otherwise use the wrapped
58   // count.
59   if (MinRegionCount == 1)
60     ExecutionCount = LineSegments[0]->Count;
61   else
62     ExecutionCount = WrappedSegment->Count;
63 }
64 
65 LineCoverageIterator &LineCoverageIterator::operator++() {
66   if (Next == CD.end()) {
67     Stats = LineCoverageStats();
68     Ended = true;
69     return *this;
70   }
71   if (Segments.size())
72     WrappedSegment = Segments.back();
73   Segments.clear();
74   while (Next != CD.end() && Next->Line == Line)
75     Segments.push_back(&*Next++);
76   Stats = LineCoverageStats(Segments, WrappedSegment, Line);
77   ++Line;
78   return *this;
79 }
80 
81 FunctionCoverageSummary
82 FunctionCoverageSummary::get(const CoverageMapping &CM,
83                              const coverage::FunctionRecord &Function) {
84   // Compute the region coverage.
85   size_t NumCodeRegions = 0, CoveredRegions = 0;
86   for (auto &CR : Function.CountedRegions) {
87     if (CR.Kind != CounterMappingRegion::CodeRegion)
88       continue;
89     ++NumCodeRegions;
90     if (CR.ExecutionCount != 0)
91       ++CoveredRegions;
92   }
93 
94   // Compute the line coverage
95   size_t NumLines = 0, CoveredLines = 0;
96   CoverageData CD = CM.getCoverageForFunction(Function);
97   for (const auto &LCS : getLineCoverageStats(CD)) {
98     if (!LCS.isMapped())
99       continue;
100     ++NumLines;
101     if (LCS.getExecutionCount())
102       ++CoveredLines;
103   }
104 
105   return FunctionCoverageSummary(
106       Function.Name, Function.ExecutionCount,
107       RegionCoverageInfo(CoveredRegions, NumCodeRegions),
108       LineCoverageInfo(CoveredLines, NumLines));
109 }
110 
111 FunctionCoverageSummary
112 FunctionCoverageSummary::get(const InstantiationGroup &Group,
113                              ArrayRef<FunctionCoverageSummary> Summaries) {
114   std::string Name;
115   if (Group.hasName()) {
116     Name = Group.getName();
117   } else {
118     llvm::raw_string_ostream OS(Name);
119     OS << "Definition at line " << Group.getLine() << ", column "
120        << Group.getColumn();
121   }
122 
123   FunctionCoverageSummary Summary(Name);
124   Summary.ExecutionCount = Group.getTotalExecutionCount();
125   Summary.RegionCoverage = Summaries[0].RegionCoverage;
126   Summary.LineCoverage = Summaries[0].LineCoverage;
127   for (const auto &FCS : Summaries.drop_front()) {
128     Summary.RegionCoverage.merge(FCS.RegionCoverage);
129     Summary.LineCoverage.merge(FCS.LineCoverage);
130   }
131   return Summary;
132 }
133