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+ // Indicates whether this item should 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+
4966void renderFunctionSummary (raw_ostream &OS,
5067 const FileCoverageSummary &Summary) {
5168 OS << " FNF:" << Summary.FunctionCoverage .getNumFunctions () << ' \n '
@@ -75,71 +92,121 @@ void renderLineExecutionCounts(raw_ostream &OS,
7592 }
7693}
7794
78- std::vector<llvm::coverage::CountedRegion >
95+ std::vector<NestedCountedRegion >
7996collectNestedBranches (const coverage::CoverageMapping &Coverage,
8097 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;
83100 for (const auto &Expansion : Expansions) {
84101 auto ExpansionCoverage = Coverage.getCoverageForExpansion (Expansion);
85102
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 ());
89105
90106 // Recursively collect branches from nested expansions.
91107 auto NestedExpansions = ExpansionCoverage.getExpansions ();
92- auto NestedExBranches = collectNestedBranches (Coverage, NestedExpansions,
93- ViewDepth + 1 , SrcLine );
108+ auto NestedExBranches =
109+ collectNestedBranches (Coverage, NestedExpansions, NestedPath );
94110 append_range (Branches, NestedExBranches);
95111
96112 // Add branches from this level of expansion.
97113 auto ExBranches = ExpansionCoverage.getBranches ();
98- for (auto B : ExBranches)
114+ for (auto & B : ExBranches)
99115 if (B.FileID == Expansion.FileID ) {
100- B.LineStart = SrcLine;
101- Branches.push_back (B);
116+ Branches.push_back (NestedCountedRegion (B, NestedPath));
102117 }
118+
119+ NestedPath.pop_back ();
103120 }
104121
105122 return Branches;
106123}
107124
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+ }
112170}
113171
114172void renderBranchExecutionCounts (raw_ostream &OS,
115173 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);
119180
120181 // 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);
123185
124186 // Append Expansion Branches to Source Branches.
125- append_range (Branches, ExBranches );
187+ appendNestedCountedRegions (ExBranches, Branches );
126188
127189 // Sort branches based on line number to ensure branches corresponding to the
128190 // same source line are counted together.
129- llvm::sort (Branches, sortLine);
191+ llvm::sort (Branches, sortNested);
192+
193+ if (UnifyInstances) {
194+ combineInstanceCounts (Branches);
195+ }
130196
131197 auto NextBranch = Branches.begin ();
132198 auto EndBranch = Branches.end ();
133199
134200 // Branches with the same source line are enumerated individually
135201 // (BranchIndex) as well as based on True/False pairs (PairIndex).
136202 while (NextBranch != EndBranch) {
137- unsigned CurrentLine = NextBranch->LineStart ;
203+ unsigned CurrentLine = NextBranch->getEffectiveLine () ;
138204 unsigned PairIndex = 0 ;
139205 unsigned BranchIndex = 0 ;
140206
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 ) {
143210 unsigned BC1 = NextBranch->ExecutionCount ;
144211 unsigned BC2 = NextBranch->FalseExecutionCount ;
145212 bool BranchNotExecuted = (BC1 == 0 && BC2 == 0 );
@@ -173,7 +240,7 @@ void renderBranchSummary(raw_ostream &OS, const FileCoverageSummary &Summary) {
173240void renderFile (raw_ostream &OS, const coverage::CoverageMapping &Coverage,
174241 const std::string &Filename,
175242 const FileCoverageSummary &FileReport, bool ExportSummaryOnly,
176- bool SkipFunctions, bool SkipBranches) {
243+ bool SkipFunctions, bool SkipBranches, bool UnifyInstances ) {
177244 OS << " SF:" << Filename << ' \n ' ;
178245
179246 if (!ExportSummaryOnly && !SkipFunctions) {
@@ -186,7 +253,7 @@ void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
186253 auto FileCoverage = Coverage.getCoverageForFile (Filename);
187254 renderLineExecutionCounts (OS, FileCoverage);
188255 if (!SkipBranches)
189- renderBranchExecutionCounts (OS, Coverage, FileCoverage);
256+ renderBranchExecutionCounts (OS, Coverage, FileCoverage, UnifyInstances );
190257 }
191258 if (!SkipBranches)
192259 renderBranchSummary (OS, FileReport);
@@ -198,11 +265,11 @@ void renderFile(raw_ostream &OS, const coverage::CoverageMapping &Coverage,
198265void renderFiles (raw_ostream &OS, const coverage::CoverageMapping &Coverage,
199266 ArrayRef<std::string> SourceFiles,
200267 ArrayRef<FileCoverageSummary> FileReports,
201- bool ExportSummaryOnly, bool SkipFunctions,
202- bool SkipBranches ) {
268+ bool ExportSummaryOnly, bool SkipFunctions, bool SkipBranches,
269+ bool UnifyInstances ) {
203270 for (unsigned I = 0 , E = SourceFiles.size (); I < E; ++I)
204271 renderFile (OS, Coverage, SourceFiles[I], FileReports[I], ExportSummaryOnly,
205- SkipFunctions, SkipBranches);
272+ SkipFunctions, SkipBranches, UnifyInstances );
206273}
207274
208275} // end anonymous namespace
@@ -221,5 +288,6 @@ void CoverageExporterLcov::renderRoot(ArrayRef<std::string> SourceFiles) {
221288 auto FileReports = CoverageReport::prepareFileReports (Coverage, Totals,
222289 SourceFiles, Options);
223290 renderFiles (OS, Coverage, SourceFiles, FileReports, Options.ExportSummaryOnly ,
224- Options.SkipFunctions , Options.SkipBranches );
291+ Options.SkipFunctions , Options.SkipBranches ,
292+ Options.UnifyFunctionInstantiations );
225293}
0 commit comments