aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp350
1 files changed, 311 insertions, 39 deletions
diff --git a/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp b/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp
index 78b268f423cb..5c25c204cc0b 100644
--- a/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/contrib/llvm-project/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -31,20 +31,73 @@
// is textually included.
#define COVMAP_V3
+static llvm::cl::opt<bool> EmptyLineCommentCoverage(
+ "emptyline-comment-coverage",
+ llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only "
+ "disable it on test)"),
+ llvm::cl::init(true), llvm::cl::Hidden);
+
using namespace clang;
using namespace CodeGen;
using namespace llvm::coverage;
+CoverageSourceInfo *
+CoverageMappingModuleGen::setUpCoverageCallbacks(Preprocessor &PP) {
+ CoverageSourceInfo *CoverageInfo =
+ new CoverageSourceInfo(PP.getSourceManager());
+ PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(CoverageInfo));
+ if (EmptyLineCommentCoverage) {
+ PP.addCommentHandler(CoverageInfo);
+ PP.setEmptylineHandler(CoverageInfo);
+ PP.setPreprocessToken(true);
+ PP.setTokenWatcher([CoverageInfo](clang::Token Tok) {
+ // Update previous token location.
+ CoverageInfo->PrevTokLoc = Tok.getLocation();
+ if (Tok.getKind() != clang::tok::eod)
+ CoverageInfo->updateNextTokLoc(Tok.getLocation());
+ });
+ }
+ return CoverageInfo;
+}
+
+void CoverageSourceInfo::AddSkippedRange(SourceRange Range) {
+ if (EmptyLineCommentCoverage && !SkippedRanges.empty() &&
+ PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
+ SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
+ Range.getBegin()))
+ SkippedRanges.back().Range.setEnd(Range.getEnd());
+ else
+ SkippedRanges.push_back({Range, PrevTokLoc});
+}
+
void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) {
- SkippedRanges.push_back(Range);
+ AddSkippedRange(Range);
+}
+
+void CoverageSourceInfo::HandleEmptyline(SourceRange Range) {
+ AddSkippedRange(Range);
+}
+
+bool CoverageSourceInfo::HandleComment(Preprocessor &PP, SourceRange Range) {
+ AddSkippedRange(Range);
+ return false;
+}
+
+void CoverageSourceInfo::updateNextTokLoc(SourceLocation Loc) {
+ if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
+ SkippedRanges.back().NextTokLoc = Loc;
}
namespace {
/// A region of source code that can be mapped to a counter.
class SourceMappingRegion {
+ /// Primary Counter that is also used for Branch Regions for "True" branches.
Counter Count;
+ /// Secondary Counter used for Branch Regions for "False" branches.
+ Optional<Counter> FalseCount;
+
/// The region's starting location.
Optional<SourceLocation> LocStart;
@@ -65,8 +118,20 @@ public:
: Count(Count), LocStart(LocStart), LocEnd(LocEnd),
DeferRegion(DeferRegion), GapRegion(GapRegion) {}
+ SourceMappingRegion(Counter Count, Optional<Counter> FalseCount,
+ Optional<SourceLocation> LocStart,
+ Optional<SourceLocation> LocEnd, bool DeferRegion = false,
+ bool GapRegion = false)
+ : Count(Count), FalseCount(FalseCount), LocStart(LocStart),
+ LocEnd(LocEnd), DeferRegion(DeferRegion), GapRegion(GapRegion) {}
+
const Counter &getCounter() const { return Count; }
+ const Counter &getFalseCounter() const {
+ assert(FalseCount && "Region has no alternate counter");
+ return *FalseCount;
+ }
+
void setCounter(Counter C) { Count = C; }
bool hasStartLoc() const { return LocStart.hasValue(); }
@@ -97,6 +162,8 @@ public:
bool isGap() const { return GapRegion; }
void setGap(bool Gap) { GapRegion = Gap; }
+
+ bool isBranch() const { return FalseCount.hasValue(); }
};
/// Spelling locations for the start and end of a source region.
@@ -274,8 +341,31 @@ public:
return None;
}
+ /// This shrinks the skipped range if it spans a line that contains a
+ /// non-comment token. If shrinking the skipped range would make it empty,
+ /// this returns None.
+ Optional<SpellingRegion> adjustSkippedRange(SourceManager &SM,
+ SourceLocation LocStart,
+ SourceLocation LocEnd,
+ SourceLocation PrevTokLoc,
+ SourceLocation NextTokLoc) {
+ SpellingRegion SR{SM, LocStart, LocEnd};
+ SR.ColumnStart = 1;
+ if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
+ SR.LineStart == SM.getSpellingLineNumber(PrevTokLoc))
+ SR.LineStart++;
+ if (NextTokLoc.isValid() && SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
+ SR.LineEnd == SM.getSpellingLineNumber(NextTokLoc)) {
+ SR.LineEnd--;
+ SR.ColumnEnd++;
+ }
+ if (SR.isInSourceOrder())
+ return SR;
+ return None;
+ }
+
/// Gather all the regions that were skipped by the preprocessor
- /// using the constructs like #if.
+ /// using the constructs like #if or comments.
void gatherSkippedRegions() {
/// An array of the minimum lineStarts and the maximum lineEnds
/// for mapping regions from the appropriate source files.
@@ -291,18 +381,23 @@ public:
}
auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges();
- for (const auto &I : SkippedRanges) {
- auto LocStart = I.getBegin();
- auto LocEnd = I.getEnd();
+ for (auto &I : SkippedRanges) {
+ SourceRange Range = I.Range;
+ auto LocStart = Range.getBegin();
+ auto LocEnd = Range.getEnd();
assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
"region spans multiple files");
auto CovFileID = getCoverageFileID(LocStart);
if (!CovFileID)
continue;
- SpellingRegion SR{SM, LocStart, LocEnd};
+ Optional<SpellingRegion> SR =
+ adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc, I.NextTokLoc);
+ if (!SR.hasValue())
+ continue;
auto Region = CounterMappingRegion::makeSkipped(
- *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd);
+ *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
+ SR->ColumnEnd);
// Make sure that we only collect the regions that are inside
// the source code of this function.
if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
@@ -348,6 +443,10 @@ public:
MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
SR.LineEnd, SR.ColumnEnd));
+ } else if (Region.isBranch()) {
+ MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
+ Region.getCounter(), Region.getFalseCounter(), *CovFileID,
+ SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
} else {
MappingRegions.push_back(CounterMappingRegion::makeRegion(
Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
@@ -486,12 +585,16 @@ struct CounterCoverageMappingBuilder
/// Returns the index on the stack where the region was pushed. This can be
/// used with popRegions to exit a "scope", ending the region that was pushed.
size_t pushRegion(Counter Count, Optional<SourceLocation> StartLoc = None,
- Optional<SourceLocation> EndLoc = None) {
- if (StartLoc) {
+ Optional<SourceLocation> EndLoc = None,
+ Optional<Counter> FalseCount = None) {
+
+ if (StartLoc && !FalseCount.hasValue()) {
MostRecentLocation = *StartLoc;
completeDeferred(Count, MostRecentLocation);
}
- RegionStack.emplace_back(Count, StartLoc, EndLoc);
+
+ RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc,
+ FalseCount.hasValue());
return RegionStack.size() - 1;
}
@@ -581,49 +684,64 @@ struct CounterCoverageMappingBuilder
SourceLocation EndLoc = Region.hasEndLoc()
? Region.getEndLoc()
: RegionStack[ParentIndex].getEndLoc();
+ bool isBranch = Region.isBranch();
size_t StartDepth = locationDepth(StartLoc);
size_t EndDepth = locationDepth(EndLoc);
while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) {
bool UnnestStart = StartDepth >= EndDepth;
bool UnnestEnd = EndDepth >= StartDepth;
if (UnnestEnd) {
- // The region ends in a nested file or macro expansion. Create a
- // separate region for each expansion.
+ // The region ends in a nested file or macro expansion. If the
+ // region is not a branch region, create a separate region for each
+ // expansion, and for all regions, update the EndLoc. Branch
+ // regions should not be split in order to keep a straightforward
+ // correspondance between the region and its associated branch
+ // condition, even if the condition spans multiple depths.
SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
assert(SM.isWrittenInSameFile(NestedLoc, EndLoc));
- if (!isRegionAlreadyAdded(NestedLoc, EndLoc))
- SourceRegions.emplace_back(Region.getCounter(), NestedLoc, EndLoc);
+ if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
+ SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
+ EndLoc);
EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
if (EndLoc.isInvalid())
- llvm::report_fatal_error("File exit not handled before popRegions");
+ llvm::report_fatal_error(
+ "File exit not handled before popRegions");
EndDepth--;
}
if (UnnestStart) {
- // The region begins in a nested file or macro expansion. Create a
- // separate region for each expansion.
+ // The region ends in a nested file or macro expansion. If the
+ // region is not a branch region, create a separate region for each
+ // expansion, and for all regions, update the StartLoc. Branch
+ // regions should not be split in order to keep a straightforward
+ // correspondance between the region and its associated branch
+ // condition, even if the condition spans multiple depths.
SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
assert(SM.isWrittenInSameFile(StartLoc, NestedLoc));
- if (!isRegionAlreadyAdded(StartLoc, NestedLoc))
- SourceRegions.emplace_back(Region.getCounter(), StartLoc, NestedLoc);
+ if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
+ SourceRegions.emplace_back(Region.getCounter(), StartLoc,
+ NestedLoc);
StartLoc = getIncludeOrExpansionLoc(StartLoc);
if (StartLoc.isInvalid())
- llvm::report_fatal_error("File exit not handled before popRegions");
+ llvm::report_fatal_error(
+ "File exit not handled before popRegions");
StartDepth--;
}
}
Region.setStartLoc(StartLoc);
Region.setEndLoc(EndLoc);
- MostRecentLocation = EndLoc;
- // If this region happens to span an entire expansion, we need to make
- // sure we don't overlap the parent region with it.
- if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
- EndLoc == getEndOfFileOrMacro(EndLoc))
- MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
+ if (!isBranch) {
+ MostRecentLocation = EndLoc;
+ // If this region happens to span an entire expansion, we need to
+ // make sure we don't overlap the parent region with it.
+ if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
+ EndLoc == getEndOfFileOrMacro(EndLoc))
+ MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
+ }
assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
assert(SpellingRegion(SM, Region).isInSourceOrder());
@@ -682,14 +800,61 @@ struct CounterCoverageMappingBuilder
return ExitCount;
}
+ /// Determine whether the given condition can be constant folded.
+ bool ConditionFoldsToBool(const Expr *Cond) {
+ Expr::EvalResult Result;
+ return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext()));
+ }
+
+ /// Create a Branch Region around an instrumentable condition for coverage
+ /// and add it to the function's SourceRegions. A branch region tracks a
+ /// "True" counter and a "False" counter for boolean expressions that
+ /// result in the generation of a branch.
+ void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt) {
+ // Check for NULL conditions.
+ if (!C)
+ return;
+
+ // Ensure we are an instrumentable condition (i.e. no "&&" or "||"). Push
+ // region onto RegionStack but immediately pop it (which adds it to the
+ // function's SourceRegions) because it doesn't apply to any other source
+ // code other than the Condition.
+ if (CodeGenFunction::isInstrumentedCondition(C)) {
+ // If a condition can fold to true or false, the corresponding branch
+ // will be removed. Create a region with both counters hard-coded to
+ // zero. This allows us to visualize them in a special way.
+ // Alternatively, we can prevent any optimization done via
+ // constant-folding by ensuring that ConstantFoldsToSimpleInteger() in
+ // CodeGenFunction.c always returns false, but that is very heavy-handed.
+ if (ConditionFoldsToBool(C))
+ popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C),
+ Counter::getZero()));
+ else
+ // Otherwise, create a region with the True counter and False counter.
+ popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt));
+ }
+ }
+
+ /// Create a Branch Region around a SwitchCase for code coverage
+ /// and add it to the function's SourceRegions.
+ void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt,
+ Counter FalseCnt) {
+ // Push region onto RegionStack but immediately pop it (which adds it to
+ // the function's SourceRegions) because it doesn't apply to any other
+ // source other than the SwitchCase.
+ popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt));
+ }
+
/// Check whether a region with bounds \c StartLoc and \c EndLoc
/// is already added to \c SourceRegions.
- bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc) {
+ bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
+ bool isBranch = false) {
return SourceRegions.rend() !=
std::find_if(SourceRegions.rbegin(), SourceRegions.rend(),
[&](const SourceMappingRegion &Region) {
return Region.getBeginLoc() == StartLoc &&
- Region.getEndLoc() == EndLoc;
+ Region.getEndLoc() == EndLoc &&
+ Region.isBranch() == isBranch;
});
}
@@ -706,7 +871,7 @@ struct CounterCoverageMappingBuilder
if (getRegion().hasEndLoc() &&
MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
- MostRecentLocation))
+ MostRecentLocation, getRegion().isBranch()))
MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
}
@@ -750,9 +915,14 @@ struct CounterCoverageMappingBuilder
// The most nested region for each start location is the one with the
// correct count. We avoid creating redundant regions by stopping once
// we've seen this region.
- if (StartLocs.insert(Loc).second)
- SourceRegions.emplace_back(I.getCounter(), Loc,
- getEndOfFileOrMacro(Loc));
+ if (StartLocs.insert(Loc).second) {
+ if (I.isBranch())
+ SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), Loc,
+ getEndOfFileOrMacro(Loc), I.isBranch());
+ else
+ SourceRegions.emplace_back(I.getCounter(), Loc,
+ getEndOfFileOrMacro(Loc));
+ }
Loc = getIncludeOrExpansionLoc(Loc);
}
I.setStartLoc(getPreciseTokenLocEnd(Loc));
@@ -993,6 +1163,10 @@ struct CounterCoverageMappingBuilder
addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
if (OutCount != ParentCount)
pushRegion(OutCount);
+
+ // Create Branch Region around condition.
+ createBranchRegion(S->getCond(), BodyCount,
+ subtractCounters(CondCount, BodyCount));
}
void VisitDoStmt(const DoStmt *S) {
@@ -1014,6 +1188,10 @@ struct CounterCoverageMappingBuilder
addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
if (OutCount != ParentCount)
pushRegion(OutCount);
+
+ // Create Branch Region around condition.
+ createBranchRegion(S->getCond(), BodyCount,
+ subtractCounters(CondCount, BodyCount));
}
void VisitForStmt(const ForStmt *S) {
@@ -1061,6 +1239,10 @@ struct CounterCoverageMappingBuilder
subtractCounters(CondCount, BodyCount));
if (OutCount != ParentCount)
pushRegion(OutCount);
+
+ // Create Branch Region around condition.
+ createBranchRegion(S->getCond(), BodyCount,
+ subtractCounters(CondCount, BodyCount));
}
void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
@@ -1090,6 +1272,10 @@ struct CounterCoverageMappingBuilder
addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
if (OutCount != ParentCount)
pushRegion(OutCount);
+
+ // Create Branch Region around condition.
+ createBranchRegion(S->getCond(), BodyCount,
+ subtractCounters(LoopCount, BodyCount));
}
void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
@@ -1154,6 +1340,7 @@ struct CounterCoverageMappingBuilder
BreakContinueStack.back().ContinueCount = addCounters(
BreakContinueStack.back().ContinueCount, BC.ContinueCount);
+ Counter ParentCount = getRegion().getCounter();
Counter ExitCount = getRegionCounter(S);
SourceLocation ExitLoc = getEnd(S);
pushRegion(ExitCount);
@@ -1162,6 +1349,28 @@ struct CounterCoverageMappingBuilder
// in a different file.
MostRecentLocation = getStart(S);
handleFileExit(ExitLoc);
+
+ // Create a Branch Region around each Case. Subtract the case's
+ // counter from the Parent counter to track the "False" branch count.
+ Counter CaseCountSum;
+ bool HasDefaultCase = false;
+ const SwitchCase *Case = S->getSwitchCaseList();
+ for (; Case; Case = Case->getNextSwitchCase()) {
+ HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case);
+ CaseCountSum = addCounters(CaseCountSum, getRegionCounter(Case));
+ createSwitchCaseRegion(
+ Case, getRegionCounter(Case),
+ subtractCounters(ParentCount, getRegionCounter(Case)));
+ }
+
+ // If no explicit default case exists, create a branch region to represent
+ // the hidden branch, which will be added later by the CodeGen. This region
+ // will be associated with the switch statement's condition.
+ if (!HasDefaultCase) {
+ Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum);
+ Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue);
+ createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse);
+ }
}
void VisitSwitchCase(const SwitchCase *S) {
@@ -1222,6 +1431,10 @@ struct CounterCoverageMappingBuilder
if (OutCount != ParentCount)
pushRegion(OutCount);
+
+ // Create Branch Region around condition.
+ createBranchRegion(S->getCond(), ThenCount,
+ subtractCounters(ParentCount, ThenCount));
}
void VisitCXXTryStmt(const CXXTryStmt *S) {
@@ -1265,6 +1478,10 @@ struct CounterCoverageMappingBuilder
extendRegion(E->getFalseExpr());
propagateCounts(subtractCounters(ParentCount, TrueCount),
E->getFalseExpr());
+
+ // Create Branch Region around condition.
+ createBranchRegion(E->getCond(), TrueCount,
+ subtractCounters(ParentCount, TrueCount));
}
void VisitBinLAnd(const BinaryOperator *E) {
@@ -1272,8 +1489,26 @@ struct CounterCoverageMappingBuilder
propagateCounts(getRegion().getCounter(), E->getLHS());
handleFileExit(getEnd(E->getLHS()));
+ // Counter tracks the right hand side of a logical and operator.
extendRegion(E->getRHS());
propagateCounts(getRegionCounter(E), E->getRHS());
+
+ // Extract the RHS's Execution Counter.
+ Counter RHSExecCnt = getRegionCounter(E);
+
+ // Extract the RHS's "True" Instance Counter.
+ Counter RHSTrueCnt = getRegionCounter(E->getRHS());
+
+ // Extract the Parent Region Counter.
+ Counter ParentCnt = getRegion().getCounter();
+
+ // Create Branch Region around LHS condition.
+ createBranchRegion(E->getLHS(), RHSExecCnt,
+ subtractCounters(ParentCnt, RHSExecCnt));
+
+ // Create Branch Region around RHS condition.
+ createBranchRegion(E->getRHS(), RHSTrueCnt,
+ subtractCounters(RHSExecCnt, RHSTrueCnt));
}
void VisitBinLOr(const BinaryOperator *E) {
@@ -1281,8 +1516,26 @@ struct CounterCoverageMappingBuilder
propagateCounts(getRegion().getCounter(), E->getLHS());
handleFileExit(getEnd(E->getLHS()));
+ // Counter tracks the right hand side of a logical or operator.
extendRegion(E->getRHS());
propagateCounts(getRegionCounter(E), E->getRHS());
+
+ // Extract the RHS's Execution Counter.
+ Counter RHSExecCnt = getRegionCounter(E);
+
+ // Extract the RHS's "False" Instance Counter.
+ Counter RHSFalseCnt = getRegionCounter(E->getRHS());
+
+ // Extract the Parent Region Counter.
+ Counter ParentCnt = getRegion().getCounter();
+
+ // Create Branch Region around LHS condition.
+ createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
+ RHSExecCnt);
+
+ // Create Branch Region around RHS condition.
+ createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
+ RHSFalseCnt);
}
void VisitLambdaExpr(const LambdaExpr *LE) {
@@ -1291,13 +1544,6 @@ struct CounterCoverageMappingBuilder
}
};
-std::string normalizeFilename(StringRef Filename) {
- llvm::SmallString<256> Path(Filename);
- llvm::sys::fs::make_absolute(Path);
- llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
- return std::string(Path);
-}
-
} // end anonymous namespace
static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
@@ -1319,17 +1565,43 @@ static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
case CounterMappingRegion::GapRegion:
OS << "Gap,";
break;
+ case CounterMappingRegion::BranchRegion:
+ OS << "Branch,";
+ break;
}
OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
<< " -> " << R.LineEnd << ":" << R.ColumnEnd << " = ";
Ctx.dump(R.Count, OS);
+
+ if (R.Kind == CounterMappingRegion::BranchRegion) {
+ OS << ", ";
+ Ctx.dump(R.FalseCount, OS);
+ }
+
if (R.Kind == CounterMappingRegion::ExpansionRegion)
OS << " (Expanded file = " << R.ExpandedFileID << ")";
OS << "\n";
}
}
+CoverageMappingModuleGen::CoverageMappingModuleGen(
+ CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
+ : CGM(CGM), SourceInfo(SourceInfo) {
+ ProfilePrefixMap = CGM.getCodeGenOpts().ProfilePrefixMap;
+}
+
+std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
+ llvm::SmallString<256> Path(Filename);
+ llvm::sys::fs::make_absolute(Path);
+ llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+ for (const auto &Entry : ProfilePrefixMap) {
+ if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
+ break;
+ }
+ return Path.str().str();
+}
+
static std::string getInstrProfSection(const CodeGenModule &CGM,
llvm::InstrProfSectKind SK) {
return llvm::getInstrProfSectionName(