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