//===- CoverageSummaryInfo.cpp - Coverage summary for function/file -------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // These structures are used to represent code coverage metrics // for functions/files. // //===----------------------------------------------------------------------===// #include "CoverageSummaryInfo.h" using namespace llvm; using namespace coverage; LineCoverageStats::LineCoverageStats( ArrayRef LineSegments, const coverage::CoverageSegment *WrappedSegment, unsigned Line) : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line), LineSegments(LineSegments), WrappedSegment(WrappedSegment) { // Find the minimum number of regions which start in this line. unsigned MinRegionCount = 0; auto isStartOfRegion = [](const coverage::CoverageSegment *S) { return !S->IsGapRegion && S->HasCount && S->IsRegionEntry; }; for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I) if (isStartOfRegion(LineSegments[I])) ++MinRegionCount; bool StartOfSkippedRegion = !LineSegments.empty() && !LineSegments.front()->HasCount && LineSegments.front()->IsRegionEntry; HasMultipleRegions = MinRegionCount > 1; Mapped = !StartOfSkippedRegion && ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0)); if (!Mapped) return; // Pick the max count among regions which start and end on this line, to // avoid erroneously using the wrapped count, and to avoid picking region // counts which come from deferred regions. if (LineSegments.size() > 1) { for (unsigned I = 0; I < LineSegments.size() - 1; ++I) { if (!LineSegments[I]->IsGapRegion) ExecutionCount = std::max(ExecutionCount, LineSegments[I]->Count); } return; } // If a non-gap region starts here, use its count. Otherwise use the wrapped // count. if (MinRegionCount == 1) ExecutionCount = LineSegments[0]->Count; else ExecutionCount = WrappedSegment->Count; } LineCoverageIterator &LineCoverageIterator::operator++() { if (Next == CD.end()) { Stats = LineCoverageStats(); Ended = true; return *this; } if (Segments.size()) WrappedSegment = Segments.back(); Segments.clear(); while (Next != CD.end() && Next->Line == Line) Segments.push_back(&*Next++); Stats = LineCoverageStats(Segments, WrappedSegment, Line); ++Line; return *this; } FunctionCoverageSummary FunctionCoverageSummary::get(const CoverageMapping &CM, const coverage::FunctionRecord &Function) { // Compute the region coverage. size_t NumCodeRegions = 0, CoveredRegions = 0; for (auto &CR : Function.CountedRegions) { if (CR.Kind != CounterMappingRegion::CodeRegion) continue; ++NumCodeRegions; if (CR.ExecutionCount != 0) ++CoveredRegions; } // Compute the line coverage size_t NumLines = 0, CoveredLines = 0; CoverageData CD = CM.getCoverageForFunction(Function); for (const auto &LCS : getLineCoverageStats(CD)) { if (!LCS.isMapped()) continue; ++NumLines; if (LCS.getExecutionCount()) ++CoveredLines; } return FunctionCoverageSummary( Function.Name, Function.ExecutionCount, RegionCoverageInfo(CoveredRegions, NumCodeRegions), LineCoverageInfo(CoveredLines, NumLines)); } FunctionCoverageSummary FunctionCoverageSummary::get(const InstantiationGroup &Group, ArrayRef Summaries) { std::string Name; if (Group.hasName()) { Name = Group.getName(); } else { llvm::raw_string_ostream OS(Name); OS << "Definition at line " << Group.getLine() << ", column " << Group.getColumn(); } FunctionCoverageSummary Summary(Name); Summary.ExecutionCount = Group.getTotalExecutionCount(); Summary.RegionCoverage = Summaries[0].RegionCoverage; Summary.LineCoverage = Summaries[0].LineCoverage; for (const auto &FCS : Summaries.drop_front()) { Summary.RegionCoverage.merge(FCS.RegionCoverage); Summary.LineCoverage.merge(FCS.LineCoverage); } return Summary; }