43
43
#include " CoverageReport.h"
44
44
45
45
using namespace llvm ;
46
+ using namespace coverage ;
46
47
47
48
namespace {
48
49
50
+ struct NestedCountedRegion : public coverage ::CountedRegion {
51
+ // Contains the path to default and expanded branches
52
+ // Size is 1 for default branches and greater 1 for expanded branches.
53
+ std::vector<LineColPair> NestedPath;
54
+
55
+ NestedCountedRegion (llvm::coverage::CountedRegion Region,
56
+ std::vector<LineColPair> NestedPath)
57
+ : llvm::coverage::CountedRegion(std::move(Region)),
58
+ NestedPath (std::move(NestedPath)) {}
59
+
60
+ // Returns the root line of the branch
61
+ unsigned getEffectiveLine () const { return NestedPath.front ().first ; }
62
+ };
63
+
49
64
void renderFunctionSummary (raw_ostream &OS,
50
65
const FileCoverageSummary &Summary) {
51
66
OS << " FNF:" << Summary.FunctionCoverage .getNumFunctions () << ' \n '
@@ -75,70 +90,120 @@ void renderLineExecutionCounts(raw_ostream &OS,
75
90
}
76
91
}
77
92
78
- std::vector<llvm::coverage::CountedRegion >
93
+ std::vector<NestedCountedRegion >
79
94
collectNestedBranches (const coverage::CoverageMapping &Coverage,
80
95
ArrayRef<llvm::coverage::ExpansionRecord> Expansions,
81
- int ViewDepth = 0 , int SrcLine = 0 ) {
82
- std::vector<llvm::coverage::CountedRegion > Branches;
96
+ std::vector<LineColPair> &NestedPath ) {
97
+ std::vector<NestedCountedRegion > Branches;
83
98
for (const auto &Expansion : Expansions) {
84
99
auto ExpansionCoverage = Coverage.getCoverageForExpansion (Expansion);
85
100
86
- // If we're at the top level, set the corresponding source line.
87
- if (ViewDepth == 0 )
88
- SrcLine = Expansion.Region .LineStart ;
101
+ // Track the path to the nested expansions
102
+ NestedPath.push_back (Expansion.Region .startLoc ());
89
103
90
104
// Recursively collect branches from nested expansions.
91
105
auto NestedExpansions = ExpansionCoverage.getExpansions ();
92
- auto NestedExBranches = collectNestedBranches (Coverage, NestedExpansions,
93
- ViewDepth + 1 , SrcLine );
106
+ auto NestedExBranches =
107
+ collectNestedBranches (Coverage, NestedExpansions, NestedPath );
94
108
append_range (Branches, NestedExBranches);
95
109
96
110
// Add branches from this level of expansion.
97
111
auto ExBranches = ExpansionCoverage.getBranches ();
98
- for (auto B : ExBranches)
112
+ for (auto & B : ExBranches)
99
113
if (B.FileID == Expansion.FileID ) {
100
- B.LineStart = SrcLine;
101
- Branches.push_back (B);
114
+ Branches.push_back (NestedCountedRegion (B, NestedPath));
102
115
}
116
+
117
+ NestedPath.pop_back ();
103
118
}
104
119
105
120
return Branches;
106
121
}
107
122
108
- bool sortLine (llvm::coverage::CountedRegion I,
109
- llvm::coverage::CountedRegion J) {
110
- return (I.LineStart < J.LineStart ) ||
111
- ((I.LineStart == J.LineStart ) && (I.ColumnStart < J.ColumnStart ));
123
+ void appendNestedCountedRegions (const std::vector<CountedRegion> &Src,
124
+ std::vector<NestedCountedRegion> &Dst) {
125
+ auto Unfolded = make_filter_range (Src, [](auto &Region) {
126
+ return !Region.TrueFolded || !Region.FalseFolded ;
127
+ });
128
+ Dst.reserve (Dst.size () + Src.size ());
129
+ std::transform (Unfolded.begin (), Unfolded.end (), std::back_inserter (Dst),
130
+ [=](auto &Region) {
131
+ return NestedCountedRegion (Region, {Region.startLoc ()});
132
+ });
133
+ }
134
+
135
+ void appendNestedCountedRegions (const std::vector<NestedCountedRegion> &Src,
136
+ std::vector<NestedCountedRegion> &Dst) {
137
+ auto Unfolded = make_filter_range (Src, [](auto &NestedRegion) {
138
+ return !NestedRegion.TrueFolded || !NestedRegion.FalseFolded ;
139
+ });
140
+ Dst.reserve (Dst.size () + Src.size ());
141
+ std::copy (Unfolded.begin (), Unfolded.end (), std::back_inserter (Dst));
142
+ }
143
+
144
+ bool sortNested (const NestedCountedRegion &I, const NestedCountedRegion &J) {
145
+ // This sorts each element by line and column
146
+ // Implies that all elements are first sorted by getEffectiveLine()
147
+ return I.NestedPath < J.NestedPath ;
148
+ }
149
+
150
+ void combineInstanceCounts (std::vector<NestedCountedRegion> &Branches) {
151
+ auto NextBranch = Branches.begin ();
152
+ auto EndBranch = Branches.end ();
153
+
154
+ while (NextBranch != EndBranch) {
155
+ auto SumBranch = NextBranch++;
156
+
157
+ // Ensure that only branches with the same NestedPath are summed up
158
+ while (NextBranch != EndBranch &&
159
+ SumBranch->NestedPath == NextBranch->NestedPath ) {
160
+ SumBranch->ExecutionCount += NextBranch->ExecutionCount ;
161
+ SumBranch->FalseExecutionCount += NextBranch->FalseExecutionCount ;
162
+ NextBranch->TrueFolded = true ;
163
+ NextBranch->FalseFolded = true ;
164
+
165
+ NextBranch++;
166
+ }
167
+ }
112
168
}
113
169
114
170
void renderBranchExecutionCounts (raw_ostream &OS,
115
171
const coverage::CoverageMapping &Coverage,
116
- const coverage::CoverageData &FileCoverage) {
117
- std::vector<llvm::coverage::CountedRegion> Branches =
118
- FileCoverage.getBranches ();
172
+ const coverage::CoverageData &FileCoverage,
173
+ bool UnifyInstances) {
174
+
175
+ std::vector<NestedCountedRegion> Branches;
176
+
177
+ appendNestedCountedRegions (FileCoverage.getBranches (), Branches);
119
178
120
179
// Recursively collect branches for all file expansions.
121
- std::vector<llvm::coverage::CountedRegion> ExBranches =
122
- collectNestedBranches (Coverage, FileCoverage.getExpansions ());
180
+ std::vector<LineColPair> NestedPath;
181
+ std::vector<NestedCountedRegion> ExBranches =
182
+ collectNestedBranches (Coverage, FileCoverage.getExpansions (), NestedPath);
123
183
124
184
// Append Expansion Branches to Source Branches.
125
- append_range (Branches, ExBranches );
185
+ appendNestedCountedRegions (ExBranches, Branches );
126
186
127
187
// Sort branches based on line number to ensure branches corresponding to the
128
188
// same source line are counted together.
129
- llvm::sort (Branches, sortLine);
189
+ llvm::sort (Branches, sortNested);
190
+
191
+ if (UnifyInstances) {
192
+ combineInstanceCounts (Branches);
193
+ }
130
194
131
195
auto NextBranch = Branches.begin ();
132
196
auto EndBranch = Branches.end ();
133
197
134
198
// Branches with the same source line are enumerated individually
135
199
// (BranchIndex) as well as based on True/False pairs (PairIndex).
136
200
while (NextBranch != EndBranch) {
137
- unsigned CurrentLine = NextBranch->LineStart ;
201
+ unsigned CurrentLine = NextBranch->getEffectiveLine () ;
138
202
unsigned PairIndex = 0 ;
139
203
unsigned BranchIndex = 0 ;
140
204
141
- while (NextBranch != EndBranch && CurrentLine == NextBranch->LineStart ) {
205
+ while (NextBranch != EndBranch &&
206
+ CurrentLine == NextBranch->getEffectiveLine ()) {
142
207
if (!NextBranch->TrueFolded || !NextBranch->FalseFolded ) {
143
208
unsigned BC1 = NextBranch->ExecutionCount ;
144
209
unsigned BC2 = NextBranch->FalseExecutionCount ;
@@ -173,7 +238,7 @@ void renderBranchSummary(raw_ostream &OS, const FileCoverageSummary &Summary) {
173
238
void renderFile (raw_ostream &OS, const coverage::CoverageMapping &Coverage,
174
239
const std::string &Filename,
175
240
const FileCoverageSummary &FileReport, bool ExportSummaryOnly,
176
- bool SkipFunctions, bool SkipBranches) {
241
+ bool SkipFunctions, bool SkipBranches, bool UnifyInstances ) {
177
242
OS << " SF:" << Filename << ' \n ' ;
178
243
179
244
if (!ExportSummaryOnly && !SkipFunctions) {
@@ -186,7 +251,7 @@ void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
186
251
auto FileCoverage = Coverage.getCoverageForFile (Filename);
187
252
renderLineExecutionCounts (OS, FileCoverage);
188
253
if (!SkipBranches)
189
- renderBranchExecutionCounts (OS, Coverage, FileCoverage);
254
+ renderBranchExecutionCounts (OS, Coverage, FileCoverage, UnifyInstances );
190
255
}
191
256
if (!SkipBranches)
192
257
renderBranchSummary (OS, FileReport);
@@ -198,11 +263,11 @@ void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
198
263
void renderFiles (raw_ostream &OS, const coverage::CoverageMapping &Coverage,
199
264
ArrayRef<std::string> SourceFiles,
200
265
ArrayRef<FileCoverageSummary> FileReports,
201
- bool ExportSummaryOnly, bool SkipFunctions,
202
- bool SkipBranches ) {
266
+ bool ExportSummaryOnly, bool SkipFunctions, bool SkipBranches,
267
+ bool UnifyInstances ) {
203
268
for (unsigned I = 0 , E = SourceFiles.size (); I < E; ++I)
204
269
renderFile (OS, Coverage, SourceFiles[I], FileReports[I], ExportSummaryOnly,
205
- SkipFunctions, SkipBranches);
270
+ SkipFunctions, SkipBranches, UnifyInstances );
206
271
}
207
272
208
273
} // end anonymous namespace
@@ -221,5 +286,6 @@ void CoverageExporterLcov::renderRoot(ArrayRef<std::string> SourceFiles) {
221
286
auto FileReports = CoverageReport::prepareFileReports (Coverage, Totals,
222
287
SourceFiles, Options);
223
288
renderFiles (OS, Coverage, SourceFiles, FileReports, Options.ExportSummaryOnly ,
224
- Options.SkipFunctions , Options.SkipBranches );
289
+ Options.SkipFunctions , Options.SkipBranches ,
290
+ Options.UnifyFunctionInstantiations );
225
291
}
0 commit comments