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
+ // Contains the original index of this element used to keep the original order
55
+ // in case of equal nested path.
56
+ unsigned Position;
57
+ // Indicates whether this item should be ignored at rendering.
58
+ bool Ignore = false ;
59
+
60
+ NestedCountedRegion (llvm::coverage::CountedRegion Region,
61
+ std::vector<LineColPair> NestedPath, unsigned Position)
62
+ : llvm::coverage::CountedRegion(std::move(Region)),
63
+ NestedPath (std::move(NestedPath)), Position(Position) {}
64
+
65
+ // Returns the root line of the branch.
66
+ unsigned getEffectiveLine () const { return NestedPath.front ().first ; }
67
+ };
68
+
49
69
void renderFunctionSummary (raw_ostream &OS,
50
70
const FileCoverageSummary &Summary) {
51
71
OS << " FNF:" << Summary.FunctionCoverage .getNumFunctions () << ' \n '
@@ -75,71 +95,128 @@ void renderLineExecutionCounts(raw_ostream &OS,
75
95
}
76
96
}
77
97
78
- std::vector<llvm::coverage::CountedRegion >
98
+ std::vector<NestedCountedRegion >
79
99
collectNestedBranches (const coverage::CoverageMapping &Coverage,
80
100
ArrayRef<llvm::coverage::ExpansionRecord> Expansions,
81
- int ViewDepth = 0 , int SrcLine = 0 ) {
82
- std::vector<llvm::coverage::CountedRegion> Branches;
101
+ std::vector<LineColPair> &NestedPath,
102
+ unsigned &PositionCounter) {
103
+ std::vector<NestedCountedRegion> Branches;
83
104
for (const auto &Expansion : Expansions) {
84
105
auto ExpansionCoverage = Coverage.getCoverageForExpansion (Expansion);
85
106
86
- // If we're at the top level, set the corresponding source line.
87
- if (ViewDepth == 0 )
88
- SrcLine = Expansion.Region .LineStart ;
107
+ // Track the path to the nested expansions.
108
+ NestedPath.push_back (Expansion.Region .startLoc ());
89
109
90
110
// Recursively collect branches from nested expansions.
91
111
auto NestedExpansions = ExpansionCoverage.getExpansions ();
92
112
auto NestedExBranches = collectNestedBranches (Coverage, NestedExpansions,
93
- ViewDepth + 1 , SrcLine );
113
+ NestedPath, PositionCounter );
94
114
append_range (Branches, NestedExBranches);
95
115
96
116
// Add branches from this level of expansion.
97
117
auto ExBranches = ExpansionCoverage.getBranches ();
98
- for (auto B : ExBranches)
118
+ for (auto & B : ExBranches)
99
119
if (B.FileID == Expansion.FileID ) {
100
- B. LineStart = SrcLine;
101
- Branches. push_back (B );
120
+ Branches. push_back (
121
+ NestedCountedRegion (B, NestedPath, PositionCounter++) );
102
122
}
123
+
124
+ NestedPath.pop_back ();
103
125
}
104
126
105
127
return Branches;
106
128
}
107
129
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 ));
130
+ void appendNestedCountedRegions (const std::vector<CountedRegion> &Src,
131
+ std::vector<NestedCountedRegion> &Dst) {
132
+ auto Unfolded = make_filter_range (Src, [](auto &Region) {
133
+ return !Region.TrueFolded || !Region.FalseFolded ;
134
+ });
135
+ Dst.reserve (Dst.size () + Src.size ());
136
+ unsigned PositionCounter = Dst.size ();
137
+ std::transform (Unfolded.begin (), Unfolded.end (), std::back_inserter (Dst),
138
+ [=, &PositionCounter](auto &Region) {
139
+ return NestedCountedRegion (Region, {Region.startLoc ()},
140
+ PositionCounter++);
141
+ });
142
+ }
143
+
144
+ void appendNestedCountedRegions (const std::vector<NestedCountedRegion> &Src,
145
+ std::vector<NestedCountedRegion> &Dst) {
146
+ auto Unfolded = make_filter_range (Src, [](auto &NestedRegion) {
147
+ return !NestedRegion.TrueFolded || !NestedRegion.FalseFolded ;
148
+ });
149
+ Dst.reserve (Dst.size () + Src.size ());
150
+ std::copy (Unfolded.begin (), Unfolded.end (), std::back_inserter (Dst));
151
+ }
152
+
153
+ bool sortNested (const NestedCountedRegion &I, const NestedCountedRegion &J) {
154
+ // This sorts each element by line and column.
155
+ // Implies that all elements are first sorted by getEffectiveLine().
156
+ // Use original position if NestedPath is equal.
157
+ return std::tie (I.NestedPath , I.Position ) <
158
+ std::tie (J.NestedPath , J.Position );
159
+ }
160
+
161
+ void combineInstanceCounts (std::vector<NestedCountedRegion> &Branches) {
162
+ auto NextBranch = Branches.begin ();
163
+ auto EndBranch = Branches.end ();
164
+
165
+ while (NextBranch != EndBranch) {
166
+ auto SumBranch = NextBranch++;
167
+
168
+ // Ensure that only branches with the same NestedPath are summed up.
169
+ while (NextBranch != EndBranch &&
170
+ SumBranch->NestedPath == NextBranch->NestedPath ) {
171
+ SumBranch->ExecutionCount += NextBranch->ExecutionCount ;
172
+ SumBranch->FalseExecutionCount += NextBranch->FalseExecutionCount ;
173
+ // Mark this branch as ignored.
174
+ NextBranch->Ignore = true ;
175
+
176
+ NextBranch++;
177
+ }
178
+ }
112
179
}
113
180
114
181
void renderBranchExecutionCounts (raw_ostream &OS,
115
182
const coverage::CoverageMapping &Coverage,
116
- const coverage::CoverageData &FileCoverage) {
117
- std::vector<llvm::coverage::CountedRegion> Branches =
118
- FileCoverage.getBranches ();
183
+ const coverage::CoverageData &FileCoverage,
184
+ bool UnifyInstances) {
185
+
186
+ std::vector<NestedCountedRegion> Branches;
187
+
188
+ appendNestedCountedRegions (FileCoverage.getBranches (), Branches);
119
189
120
190
// Recursively collect branches for all file expansions.
121
- std::vector<llvm::coverage::CountedRegion> ExBranches =
122
- collectNestedBranches (Coverage, FileCoverage.getExpansions ());
191
+ std::vector<LineColPair> NestedPath;
192
+ unsigned PositionCounter = 0 ;
193
+ std::vector<NestedCountedRegion> ExBranches = collectNestedBranches (
194
+ Coverage, FileCoverage.getExpansions (), NestedPath, PositionCounter);
123
195
124
196
// Append Expansion Branches to Source Branches.
125
- append_range (Branches, ExBranches );
197
+ appendNestedCountedRegions (ExBranches, Branches );
126
198
127
199
// Sort branches based on line number to ensure branches corresponding to the
128
200
// same source line are counted together.
129
- llvm::sort (Branches, sortLine);
201
+ llvm::sort (Branches, sortNested);
202
+
203
+ if (UnifyInstances) {
204
+ combineInstanceCounts (Branches);
205
+ }
130
206
131
207
auto NextBranch = Branches.begin ();
132
208
auto EndBranch = Branches.end ();
133
209
134
210
// Branches with the same source line are enumerated individually
135
211
// (BranchIndex) as well as based on True/False pairs (PairIndex).
136
212
while (NextBranch != EndBranch) {
137
- unsigned CurrentLine = NextBranch->LineStart ;
213
+ unsigned CurrentLine = NextBranch->getEffectiveLine () ;
138
214
unsigned PairIndex = 0 ;
139
215
unsigned BranchIndex = 0 ;
140
216
141
- while (NextBranch != EndBranch && CurrentLine == NextBranch->LineStart ) {
142
- if (!NextBranch->TrueFolded || !NextBranch->FalseFolded ) {
217
+ while (NextBranch != EndBranch &&
218
+ CurrentLine == NextBranch->getEffectiveLine ()) {
219
+ if (!NextBranch->Ignore ) {
143
220
unsigned BC1 = NextBranch->ExecutionCount ;
144
221
unsigned BC2 = NextBranch->FalseExecutionCount ;
145
222
bool BranchNotExecuted = (BC1 == 0 && BC2 == 0 );
@@ -173,7 +250,7 @@ void renderBranchSummary(raw_ostream &OS, const FileCoverageSummary &Summary) {
173
250
void renderFile (raw_ostream &OS, const coverage::CoverageMapping &Coverage,
174
251
const std::string &Filename,
175
252
const FileCoverageSummary &FileReport, bool ExportSummaryOnly,
176
- bool SkipFunctions, bool SkipBranches) {
253
+ bool SkipFunctions, bool SkipBranches, bool UnifyInstances ) {
177
254
OS << " SF:" << Filename << ' \n ' ;
178
255
179
256
if (!ExportSummaryOnly && !SkipFunctions) {
@@ -186,7 +263,7 @@ void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
186
263
auto FileCoverage = Coverage.getCoverageForFile (Filename);
187
264
renderLineExecutionCounts (OS, FileCoverage);
188
265
if (!SkipBranches)
189
- renderBranchExecutionCounts (OS, Coverage, FileCoverage);
266
+ renderBranchExecutionCounts (OS, Coverage, FileCoverage, UnifyInstances );
190
267
}
191
268
if (!SkipBranches)
192
269
renderBranchSummary (OS, FileReport);
@@ -198,11 +275,11 @@ void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
198
275
void renderFiles (raw_ostream &OS, const coverage::CoverageMapping &Coverage,
199
276
ArrayRef<std::string> SourceFiles,
200
277
ArrayRef<FileCoverageSummary> FileReports,
201
- bool ExportSummaryOnly, bool SkipFunctions,
202
- bool SkipBranches ) {
278
+ bool ExportSummaryOnly, bool SkipFunctions, bool SkipBranches,
279
+ bool UnifyInstances ) {
203
280
for (unsigned I = 0 , E = SourceFiles.size (); I < E; ++I)
204
281
renderFile (OS, Coverage, SourceFiles[I], FileReports[I], ExportSummaryOnly,
205
- SkipFunctions, SkipBranches);
282
+ SkipFunctions, SkipBranches, UnifyInstances );
206
283
}
207
284
208
285
} // end anonymous namespace
@@ -221,5 +298,6 @@ void CoverageExporterLcov::renderRoot(ArrayRef<std::string> SourceFiles) {
221
298
auto FileReports = CoverageReport::prepareFileReports (Coverage, Totals,
222
299
SourceFiles, Options);
223
300
renderFiles (OS, Coverage, SourceFiles, FileReports, Options.ExportSummaryOnly ,
224
- Options.SkipFunctions , Options.SkipBranches );
301
+ Options.SkipFunctions , Options.SkipBranches ,
302
+ Options.UnifyFunctionInstantiations );
225
303
}
0 commit comments