LLVMCoverage: Unify getCoverageForFile and getCoverageForFunction. NFC (#120842)

Since #119952, `getCoverageForFile` and `getCoverageForFunction` have
similar structure each other. Ther merged method `addFunctionRegions`
has two lambda subfunctions.

* `getCoverageForFile`
  - `MainFileID` may be `nullopt`.
- `shouldProcess` picks up relevant records along `FileIDs` that is
scanned based on `MainFileID`. They may have expanded source files.
  - `shouldExpand` takes the presense of `MainFileID` into account.
* `getCoverageForFunction`
  - This assumes the presense of `MainFileID`.
  - `shouldProcess` picks up records that belong only to `MainFileID`.
  - `shouldExpand` assumes the presense of `MainFileID`.

This change introduces a wrapper class `MergeableCoverageData` for
further merging instances. At the moment, this returns `CoverageData`
including `buildSegments()`.

This change itself is NFC.
This commit is contained in:
NAKAMURA Takumi 2026-01-10 10:29:52 +09:00 committed by GitHub
parent 0727fcb11d
commit fea69aa19f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 45 additions and 38 deletions

View File

@ -943,6 +943,7 @@ public:
class CoverageData {
friend class CoverageMapping;
protected:
std::string Filename;
std::vector<CoverageSegment> Segments;
std::vector<ExpansionRecord> Expansions;
@ -957,6 +958,8 @@ public:
CoverageData(bool Single, StringRef Filename)
: Filename(Filename), SingleByteCoverage(Single) {}
CoverageData(CoverageData &&RHS) = default;
/// Get the name of the file this data covers.
StringRef getFilename() const { return Filename; }

View File

@ -1397,6 +1397,37 @@ public:
}
};
struct MergeableCoverageData : public CoverageData {
std::vector<CountedRegion> CodeRegions;
MergeableCoverageData(bool Single, StringRef Filename)
: CoverageData(Single, Filename) {}
void addFunctionRegions(
const FunctionRecord &Function,
std::function<bool(const CounterMappingRegion &CR)> shouldProcess,
std::function<bool(const CountedRegion &CR)> shouldExpand) {
for (const auto &CR : Function.CountedRegions)
if (shouldProcess(CR)) {
CodeRegions.push_back(CR);
if (shouldExpand(CR))
Expansions.emplace_back(CR, Function);
}
// Capture branch regions specific to the function (excluding expansions).
for (const auto &CR : Function.CountedBranchRegions)
if (shouldProcess(CR))
BranchRegions.push_back(CR);
// Capture MCDC records specific to the function.
for (const auto &MR : Function.MCDCRecords)
if (shouldProcess(MR.getDecisionRegion()))
MCDCRecords.push_back(MR);
}
CoverageData buildSegments() {
Segments = SegmentBuilder::buildSegments(CodeRegions);
return CoverageData(std::move(*this));
}
};
} // end anonymous namespace
std::vector<StringRef> CoverageMapping::getUniqueSourceFiles() const {
@ -1448,8 +1479,7 @@ static bool isExpansion(const CountedRegion &R, unsigned FileID) {
CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
assert(SingleByteCoverage);
CoverageData FileCoverage(*SingleByteCoverage, Filename);
std::vector<CountedRegion> Regions;
MergeableCoverageData FileCoverage(*SingleByteCoverage, Filename);
// Look up the function records in the given file. Due to hash collisions on
// the filename, we may get back some records that are not in the file.
@ -1459,26 +1489,14 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
const FunctionRecord &Function = Functions[RecordIndex];
auto MainFileID = findMainViewFileID(Filename, Function);
auto FileIDs = gatherFileIDs(Filename, Function);
for (const auto &CR : Function.CountedRegions)
if (FileIDs.test(CR.FileID)) {
Regions.push_back(CR);
if (MainFileID && isExpansion(CR, *MainFileID))
FileCoverage.Expansions.emplace_back(CR, Function);
}
// Capture branch regions specific to the function (excluding expansions).
for (const auto &CR : Function.CountedBranchRegions)
if (FileIDs.test(CR.FileID))
FileCoverage.BranchRegions.push_back(CR);
// Capture MCDC records specific to the function.
for (const auto &MR : Function.MCDCRecords)
if (FileIDs.test(MR.getDecisionRegion().FileID))
FileCoverage.MCDCRecords.push_back(MR);
FileCoverage.addFunctionRegions(
Function, [&](auto &CR) { return FileIDs.test(CR.FileID); },
[&](auto &CR) { return (MainFileID && isExpansion(CR, *MainFileID)); });
}
LLVM_DEBUG(dbgs() << "Emitting segments for file: " << Filename << "\n");
FileCoverage.Segments = SegmentBuilder::buildSegments(Regions);
return FileCoverage;
return FileCoverage.buildSegments();
}
std::vector<InstantiationGroup>
@ -1513,30 +1531,16 @@ CoverageMapping::getCoverageForFunction(const FunctionRecord &Function) const {
return CoverageData();
assert(SingleByteCoverage);
CoverageData FunctionCoverage(*SingleByteCoverage,
Function.Filenames[*MainFileID]);
std::vector<CountedRegion> Regions;
for (const auto &CR : Function.CountedRegions)
if (CR.FileID == *MainFileID) {
Regions.push_back(CR);
if (isExpansion(CR, *MainFileID))
FunctionCoverage.Expansions.emplace_back(CR, Function);
}
// Capture branch regions specific to the function (excluding expansions).
for (const auto &CR : Function.CountedBranchRegions)
if (CR.FileID == *MainFileID)
FunctionCoverage.BranchRegions.push_back(CR);
// Capture MCDC records specific to the function.
for (const auto &MR : Function.MCDCRecords)
if (MR.getDecisionRegion().FileID == *MainFileID)
FunctionCoverage.MCDCRecords.push_back(MR);
MergeableCoverageData FunctionCoverage(*SingleByteCoverage,
Function.Filenames[*MainFileID]);
FunctionCoverage.addFunctionRegions(
Function, [&](auto &CR) { return (CR.FileID == *MainFileID); },
[&](auto &CR) { return isExpansion(CR, *MainFileID); });
LLVM_DEBUG(dbgs() << "Emitting segments for function: " << Function.Name
<< "\n");
FunctionCoverage.Segments = SegmentBuilder::buildSegments(Regions);
return FunctionCoverage;
return FunctionCoverage.buildSegments();
}
CoverageData CoverageMapping::getCoverageForExpansion(