4343#include " CoverageReport.h"
4444
4545using namespace llvm ;
46+ using namespace coverage ;
4647
4748namespace {
4849
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+
4964void renderFunctionSummary (raw_ostream &OS,
5065 const FileCoverageSummary &Summary) {
5166 OS << " FNF:" << Summary.FunctionCoverage .getNumFunctions () << ' \n '
@@ -75,70 +90,120 @@ void renderLineExecutionCounts(raw_ostream &OS,
7590 }
7691}
7792
78- std::vector<llvm::coverage::CountedRegion >
93+ std::vector<NestedCountedRegion >
7994collectNestedBranches (const coverage::CoverageMapping &Coverage,
8095 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;
8398 for (const auto &Expansion : Expansions) {
8499 auto ExpansionCoverage = Coverage.getCoverageForExpansion (Expansion);
85100
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 ());
89103
90104 // Recursively collect branches from nested expansions.
91105 auto NestedExpansions = ExpansionCoverage.getExpansions ();
92- auto NestedExBranches = collectNestedBranches (Coverage, NestedExpansions,
93- ViewDepth + 1 , SrcLine );
106+ auto NestedExBranches =
107+ collectNestedBranches (Coverage, NestedExpansions, NestedPath );
94108 append_range (Branches, NestedExBranches);
95109
96110 // Add branches from this level of expansion.
97111 auto ExBranches = ExpansionCoverage.getBranches ();
98- for (auto B : ExBranches)
112+ for (auto & B : ExBranches)
99113 if (B.FileID == Expansion.FileID ) {
100- B.LineStart = SrcLine;
101- Branches.push_back (B);
114+ Branches.push_back (NestedCountedRegion (B, NestedPath));
102115 }
116+
117+ NestedPath.pop_back ();
103118 }
104119
105120 return Branches;
106121}
107122
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+ }
112168}
113169
114170void renderBranchExecutionCounts (raw_ostream &OS,
115171 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);
119178
120179 // 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);
123183
124184 // Append Expansion Branches to Source Branches.
125- append_range (Branches, ExBranches );
185+ appendNestedCountedRegions (ExBranches, Branches );
126186
127187 // Sort branches based on line number to ensure branches corresponding to the
128188 // same source line are counted together.
129- llvm::sort (Branches, sortLine);
189+ llvm::sort (Branches, sortNested);
190+
191+ if (UnifyInstances) {
192+ combineInstanceCounts (Branches);
193+ }
130194
131195 auto NextBranch = Branches.begin ();
132196 auto EndBranch = Branches.end ();
133197
134198 // Branches with the same source line are enumerated individually
135199 // (BranchIndex) as well as based on True/False pairs (PairIndex).
136200 while (NextBranch != EndBranch) {
137- unsigned CurrentLine = NextBranch->LineStart ;
201+ unsigned CurrentLine = NextBranch->getEffectiveLine () ;
138202 unsigned PairIndex = 0 ;
139203 unsigned BranchIndex = 0 ;
140204
141- while (NextBranch != EndBranch && CurrentLine == NextBranch->LineStart ) {
205+ while (NextBranch != EndBranch &&
206+ CurrentLine == NextBranch->getEffectiveLine ()) {
142207 if (!NextBranch->TrueFolded || !NextBranch->FalseFolded ) {
143208 unsigned BC1 = NextBranch->ExecutionCount ;
144209 unsigned BC2 = NextBranch->FalseExecutionCount ;
@@ -173,7 +238,7 @@ void renderBranchSummary(raw_ostream &OS, const FileCoverageSummary &Summary) {
173238void renderFile (raw_ostream &OS, const coverage::CoverageMapping &Coverage,
174239 const std::string &Filename,
175240 const FileCoverageSummary &FileReport, bool ExportSummaryOnly,
176- bool SkipFunctions, bool SkipBranches) {
241+ bool SkipFunctions, bool SkipBranches, bool UnifyInstances ) {
177242 OS << " SF:" << Filename << ' \n ' ;
178243
179244 if (!ExportSummaryOnly && !SkipFunctions) {
@@ -186,7 +251,7 @@ void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
186251 auto FileCoverage = Coverage.getCoverageForFile (Filename);
187252 renderLineExecutionCounts (OS, FileCoverage);
188253 if (!SkipBranches)
189- renderBranchExecutionCounts (OS, Coverage, FileCoverage);
254+ renderBranchExecutionCounts (OS, Coverage, FileCoverage, UnifyInstances );
190255 }
191256 if (!SkipBranches)
192257 renderBranchSummary (OS, FileReport);
@@ -198,11 +263,11 @@ void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
198263void renderFiles (raw_ostream &OS, const coverage::CoverageMapping &Coverage,
199264 ArrayRef<std::string> SourceFiles,
200265 ArrayRef<FileCoverageSummary> FileReports,
201- bool ExportSummaryOnly, bool SkipFunctions,
202- bool SkipBranches ) {
266+ bool ExportSummaryOnly, bool SkipFunctions, bool SkipBranches,
267+ bool UnifyInstances ) {
203268 for (unsigned I = 0 , E = SourceFiles.size (); I < E; ++I)
204269 renderFile (OS, Coverage, SourceFiles[I], FileReports[I], ExportSummaryOnly,
205- SkipFunctions, SkipBranches);
270+ SkipFunctions, SkipBranches, UnifyInstances );
206271}
207272
208273} // end anonymous namespace
@@ -221,5 +286,6 @@ void CoverageExporterLcov::renderRoot(ArrayRef<std::string> SourceFiles) {
221286 auto FileReports = CoverageReport::prepareFileReports (Coverage, Totals,
222287 SourceFiles, Options);
223288 renderFiles (OS, Coverage, SourceFiles, FileReports, Options.ExportSummaryOnly ,
224- Options.SkipFunctions , Options.SkipBranches );
289+ Options.SkipFunctions , Options.SkipBranches ,
290+ Options.UnifyFunctionInstantiations );
225291}
0 commit comments