llvm.org GIT mirror llvm / a8dfa81
[Coverage] Add an API to retrive all instantiations of a function (NFC) The CoverageMapping::getInstantiations() API retrieved all function records corresponding to functions with more than one instantiation (e.g template functions with multiple specializations). However, there was no simple way to determine *which* function a given record was an instantiation of. This was an oversight, since it's useful to aggregate coverage information over all instantiations of a function. llvm-cov works around this by building a mapping of source locations to instantiation sets, but this duplicates logic that libCoverage already has (see FunctionInstantiationSetCollector). This change adds a new API, CoverageMapping::getInstantiationGroups(), which returns a list of InstantiationGroups. A group contains records for each instantiation of some particular function, and also provides utilities to get the total execution count within the group, the source location of the common definition, etc. This lets removes some hacky logic in llvm-cov by reusing FunctionInstantiationSetCollector and makes the CoverageMapping API friendlier for other clients. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@309904 91177308-0d34-0410-b5e6-96231b3b80d8 Vedant Kumar 2 years ago
7 changed file(s) with 144 addition(s) and 67 deletion(s). Raw diff Collapse all Expand all
395395 }
396396 };
397397
398 /// An instantiation group contains a \c FunctionRecord list, such that each
399 /// record corresponds to a distinct instantiation of the same function.
400 ///
401 /// Note that it's possible for a function to have more than one instantiation
402 /// (consider C++ template specializations or static inline functions).
403 class InstantiationGroup {
404 friend class CoverageMapping;
405
406 unsigned Line;
407 unsigned Col;
408 std::vector Instantiations;
409
410 InstantiationGroup(unsigned Line, unsigned Col,
411 std::vector Instantiations)
412 : Line(Line), Col(Col), Instantiations(std::move(Instantiations)) {}
413
414 public:
415 InstantiationGroup(const InstantiationGroup &) = delete;
416 InstantiationGroup(InstantiationGroup &&) = default;
417
418 /// Get the number of instantiations in this group.
419 size_t size() const { return Instantiations.size(); }
420
421 /// Get the line where the common function was defined.
422 unsigned getLine() const { return Line; }
423
424 /// Get the column where the common function was defined.
425 unsigned getColumn() const { return Col; }
426
427 /// Check if the instantiations in this group have a common mangled name.
428 bool hasName() const {
429 for (unsigned I = 1, E = Instantiations.size(); I < E; ++I)
430 if (Instantiations[I]->Name != Instantiations[0]->Name)
431 return false;
432 return true;
433 }
434
435 /// Get the common mangled name for instantiations in this group.
436 StringRef getName() const {
437 assert(hasName() && "Instantiations don't have a shared name");
438 return Instantiations[0]->Name;
439 }
440
441 /// Get the total execution count of all instantiations in this group.
442 uint64_t getTotalExecutionCount() const {
443 uint64_t Count = 0;
444 for (const FunctionRecord *F : Instantiations)
445 Count += F->ExecutionCount;
446 return Count;
447 }
448
449 /// Get the instantiations in this group.
450 ArrayRef getInstantiations() const {
451 return Instantiations;
452 }
453 };
454
398455 /// \brief Coverage information to be processed or displayed.
399456 ///
400457 /// This represents the coverage of an entire file, expansion, or function. It
489546 FunctionRecordIterator());
490547 }
491548
492 /// \brief Get the list of function instantiations in the file.
549 /// Get the list of function instantiation groups in a particular file.
493550 ///
494 /// Functions that are instantiated more than once, such as C++ template
495 /// specializations, have distinct coverage records for each instantiation.
496 std::vector
497 getInstantiations(StringRef Filename) const;
551 /// Every instantiation group in a program is attributed to exactly one file:
552 /// the file in which the definition for the common function begins.
553 std::vector
554 getInstantiationGroups(StringRef Filename) const;
498555
499556 /// \brief Get the coverage for a particular function.
500557 CoverageData getCoverageForFunction(const FunctionRecord &Function) const;
509509 return FileCoverage;
510510 }
511511
512 std::vector
513 CoverageMapping::getInstantiations(StringRef Filename) const {
512 std::vector
513 CoverageMapping::getInstantiationGroups(StringRef Filename) const {
514514 FunctionInstantiationSetCollector InstantiationSetCollector;
515515 for (const auto &Function : Functions) {
516516 auto MainFileID = findMainViewFileID(Filename, Function);
519519 InstantiationSetCollector.insert(Function, *MainFileID);
520520 }
521521
522 std::vector<const FunctionRecord *> Result;
522 std::vector<InstantiationGroup> Result;
523523 for (const auto &InstantiationSet : InstantiationSetCollector) {
524 if (InstantiationSet.second.size() < 2)
525 continue;
526 Result.insert(Result.end(), InstantiationSet.second.begin(),
527 InstantiationSet.second.end());
524 InstantiationGroup IG{InstantiationSet.first.first,
525 InstantiationSet.first.second,
526 std::move(InstantiationSet.second)};
527 Result.emplace_back(std::move(IG));
528528 }
529529 return Result;
530530 }
290290 if (!ViewOpts.ShowFunctionInstantiations)
291291 return View;
292292
293 for (const auto *Function : Coverage.getInstantiations(SourceFile)) {
294 std::unique_ptr SubView{nullptr};
295
296 StringRef Funcname = DC.demangle(Function->Name);
297
298 if (Function->ExecutionCount > 0) {
299 auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
300 auto SubViewExpansions = SubViewCoverage.getExpansions();
301 SubView = SourceCoverageView::create(
302 Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
303 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
304 }
305
306 unsigned FileID = Function->CountedRegions.front().FileID;
307 unsigned Line = 0;
308 for (const auto &CR : Function->CountedRegions)
309 if (CR.FileID == FileID)
310 Line = std::max(CR.LineEnd, Line);
311 View->addInstantiation(Funcname, Line, std::move(SubView));
293 for (const auto &Group : Coverage.getInstantiationGroups(SourceFile)) {
294 // Skip functions which have a single instantiation.
295 if (Group.size() < 2)
296 continue;
297
298 for (const FunctionRecord *Function : Group.getInstantiations()) {
299 std::unique_ptr SubView{nullptr};
300
301 StringRef Funcname = DC.demangle(Function->Name);
302
303 if (Function->ExecutionCount > 0) {
304 auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
305 auto SubViewExpansions = SubViewCoverage.getExpansions();
306 SubView = SourceCoverageView::create(
307 Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
308 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
309 }
310
311 unsigned FileID = Function->CountedRegions.front().FileID;
312 unsigned Line = 0;
313 for (const auto &CR : Function->CountedRegions)
314 if (CR.FileID == FileID)
315 Line = std::max(CR.LineEnd, Line);
316 View->addInstantiation(Funcname, Line, std::move(SubView));
317 }
312318 }
313319 return View;
314320 }
316316 for (StringRef Filename : Files) {
317317 FileCoverageSummary Summary(Filename.drop_front(LCP));
318318
319 // Map source locations to aggregate function coverage summaries.
320 DenseMap, FunctionCoverageSummary> Summaries;
321
322 for (const auto &F : Coverage.getCoveredFunctions(Filename)) {
323 FunctionCoverageSummary Function = FunctionCoverageSummary::get(F);
324 auto StartLoc = F.CountedRegions[0].startLoc();
325
326 auto UniquedSummary = Summaries.insert({StartLoc, Function});
327 if (!UniquedSummary.second)
328 UniquedSummary.first->second.update(Function);
329
330 Summary.addInstantiation(Function);
331 Totals.addInstantiation(Function);
332 }
333
334 for (const auto &UniquedSummary : Summaries) {
335 const FunctionCoverageSummary &FCS = UniquedSummary.second;
336 Summary.addFunction(FCS);
337 Totals.addFunction(FCS);
319 for (const auto &Group : Coverage.getInstantiationGroups(Filename)) {
320 std::vector InstantiationSummaries;
321 for (const coverage::FunctionRecord *F : Group.getInstantiations()) {
322 auto InstantiationSummary = FunctionCoverageSummary::get(*F);
323 Summary.addInstantiation(InstantiationSummary);
324 Totals.addInstantiation(InstantiationSummary);
325 InstantiationSummaries.push_back(InstantiationSummary);
326 }
327
328 auto GroupSummary =
329 FunctionCoverageSummary::get(Group, InstantiationSummaries);
330 Summary.addFunction(GroupSummary);
331 Totals.addFunction(GroupSummary);
338332 }
339333
340334 FileReports.push_back(Summary);
6969 LineCoverageInfo(CoveredLines, NumLines));
7070 }
7171
72 void FunctionCoverageSummary::update(const FunctionCoverageSummary &Summary) {
73 ExecutionCount += Summary.ExecutionCount;
74 RegionCoverage.Covered =
75 std::max(RegionCoverage.Covered, Summary.RegionCoverage.Covered);
76 RegionCoverage.NotCovered =
77 std::min(RegionCoverage.NotCovered, Summary.RegionCoverage.NotCovered);
78 LineCoverage.Covered =
79 std::max(LineCoverage.Covered, Summary.LineCoverage.Covered);
80 LineCoverage.NotCovered =
81 std::min(LineCoverage.NotCovered, Summary.LineCoverage.NotCovered);
72 FunctionCoverageSummary
73 FunctionCoverageSummary::get(const InstantiationGroup &Group,
74 ArrayRef Summaries) {
75 std::string Name;
76 if (Group.hasName()) {
77 Name = Group.getName();
78 } else {
79 llvm::raw_string_ostream OS(Name);
80 OS << "Definition at line " << Group.getLine() << ", column "
81 << Group.getColumn();
82 }
83
84 FunctionCoverageSummary Summary(std::move(Name));
85 Summary.ExecutionCount = Group.getTotalExecutionCount();
86 Summary.RegionCoverage = Summaries[0].RegionCoverage;
87 Summary.LineCoverage = Summaries[0].LineCoverage;
88 for (const auto &FCS : Summaries.drop_front()) {
89 Summary.RegionCoverage.Covered =
90 std::max(FCS.RegionCoverage.Covered, Summary.RegionCoverage.Covered);
91 Summary.RegionCoverage.NotCovered = std::min(
92 FCS.RegionCoverage.NotCovered, Summary.RegionCoverage.NotCovered);
93 Summary.LineCoverage.Covered =
94 std::max(FCS.LineCoverage.Covered, Summary.LineCoverage.Covered);
95 Summary.LineCoverage.NotCovered =
96 std::min(FCS.LineCoverage.NotCovered, Summary.LineCoverage.NotCovered);
97 }
98 return Summary;
8299 }
114114
115115 /// \brief A summary of function's code coverage.
116116 struct FunctionCoverageSummary {
117 StringRef Name;
117 std::string Name;
118118 uint64_t ExecutionCount;
119119 RegionCoverageInfo RegionCoverage;
120120 LineCoverageInfo LineCoverage;
133133 static FunctionCoverageSummary
134134 get(const coverage::FunctionRecord &Function);
135135
136 /// \brief Update the summary with information from another instantiation
137 /// of this function.
138 void update(const FunctionCoverageSummary &Summary);
136 /// Compute the code coverage summary for an instantiation group \p Group,
137 /// given a list of summaries for each instantiation in \p Summaries.
138 static FunctionCoverageSummary
139 get(const coverage::InstantiationGroup &Group,
140 ArrayRef Summaries);
139141 };
140142
141143 /// \brief A summary of file's code coverage.
547547
548548 EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());
549549
550 std::vector Instantiations =
551 LoadedCoverage->getInstantiations("expanded");
552 ASSERT_TRUE(Instantiations.empty());
550 std::vector InstantiationGroups =
551 LoadedCoverage->getInstantiationGroups("expanded");
552 for (const auto &Group : InstantiationGroups)
553 ASSERT_EQ(Group.size(), 1U);
553554 }
554555
555556 TEST_P(CoverageMappingTest, load_coverage_for_expanded_file) {