1//===- CoverageSummaryInfo.cpp - Coverage summary for function/file -------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// These structures are used to represent code coverage metrics
10// for functions/files.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CoverageSummaryInfo.h"
15
16using namespace llvm;
17using namespace coverage;
18
19static void sumBranches(size_t &NumBranches, size_t &CoveredBranches,
20                        const ArrayRef<CountedRegion> &Branches) {
21  for (const auto &BR : Branches) {
22    // Skip folded branches.
23    if (BR.Folded)
24      continue;
25
26    // "True" Condition Branches.
27    ++NumBranches;
28    if (BR.ExecutionCount > 0)
29      ++CoveredBranches;
30    // "False" Condition Branches.
31    ++NumBranches;
32    if (BR.FalseExecutionCount > 0)
33      ++CoveredBranches;
34  }
35}
36
37static void sumBranchExpansions(size_t &NumBranches, size_t &CoveredBranches,
38                                const CoverageMapping &CM,
39                                ArrayRef<ExpansionRecord> Expansions) {
40  for (const auto &Expansion : Expansions) {
41    auto CE = CM.getCoverageForExpansion(Expansion);
42    sumBranches(NumBranches, CoveredBranches, CE.getBranches());
43    sumBranchExpansions(NumBranches, CoveredBranches, CM, CE.getExpansions());
44  }
45}
46
47static std::pair<size_t, size_t>
48sumMCDCPairs(const ArrayRef<MCDCRecord> &Records) {
49  size_t NumPairs = 0, CoveredPairs = 0;
50  for (const auto &Record : Records) {
51    const auto NumConditions = Record.getNumConditions();
52    for (unsigned C = 0; C < NumConditions; C++) {
53      if (!Record.isCondFolded(C))
54        ++NumPairs;
55      if (Record.isConditionIndependencePairCovered(C))
56        ++CoveredPairs;
57    }
58  }
59  return {NumPairs, CoveredPairs};
60}
61
62FunctionCoverageSummary
63FunctionCoverageSummary::get(const CoverageMapping &CM,
64                             const coverage::FunctionRecord &Function) {
65  // Compute the region coverage.
66  size_t NumCodeRegions = 0, CoveredRegions = 0;
67  for (auto &CR : Function.CountedRegions) {
68    if (CR.Kind != CounterMappingRegion::CodeRegion)
69      continue;
70    ++NumCodeRegions;
71    if (CR.ExecutionCount != 0)
72      ++CoveredRegions;
73  }
74
75  // Compute the line coverage
76  size_t NumLines = 0, CoveredLines = 0;
77  CoverageData CD = CM.getCoverageForFunction(Function);
78  for (const auto &LCS : getLineCoverageStats(CD)) {
79    if (!LCS.isMapped())
80      continue;
81    ++NumLines;
82    if (LCS.getExecutionCount())
83      ++CoveredLines;
84  }
85
86  // Compute the branch coverage, including branches from expansions.
87  size_t NumBranches = 0, CoveredBranches = 0;
88  sumBranches(NumBranches, CoveredBranches, CD.getBranches());
89  sumBranchExpansions(NumBranches, CoveredBranches, CM, CD.getExpansions());
90
91  size_t NumPairs = 0, CoveredPairs = 0;
92  std::tie(NumPairs, CoveredPairs) = sumMCDCPairs(CD.getMCDCRecords());
93
94  return FunctionCoverageSummary(
95      Function.Name, Function.ExecutionCount,
96      RegionCoverageInfo(CoveredRegions, NumCodeRegions),
97      LineCoverageInfo(CoveredLines, NumLines),
98      BranchCoverageInfo(CoveredBranches, NumBranches),
99      MCDCCoverageInfo(CoveredPairs, NumPairs));
100}
101
102FunctionCoverageSummary
103FunctionCoverageSummary::get(const InstantiationGroup &Group,
104                             ArrayRef<FunctionCoverageSummary> Summaries) {
105  std::string Name;
106  if (Group.hasName()) {
107    Name = std::string(Group.getName());
108  } else {
109    llvm::raw_string_ostream OS(Name);
110    OS << "Definition at line " << Group.getLine() << ", column "
111       << Group.getColumn();
112  }
113
114  FunctionCoverageSummary Summary(Name);
115  Summary.ExecutionCount = Group.getTotalExecutionCount();
116  Summary.RegionCoverage = Summaries[0].RegionCoverage;
117  Summary.LineCoverage = Summaries[0].LineCoverage;
118  Summary.BranchCoverage = Summaries[0].BranchCoverage;
119  Summary.MCDCCoverage = Summaries[0].MCDCCoverage;
120  for (const auto &FCS : Summaries.drop_front()) {
121    Summary.RegionCoverage.merge(FCS.RegionCoverage);
122    Summary.LineCoverage.merge(FCS.LineCoverage);
123    Summary.BranchCoverage.merge(FCS.BranchCoverage);
124    Summary.MCDCCoverage.merge(FCS.MCDCCoverage);
125  }
126  return Summary;
127}
128