20#include "llvm/ADT/DenseSet.h"
21#include "llvm/ADT/SmallSet.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/ProfileData/Coverage/CoverageMapping.h"
24#include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
25#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
26#include "llvm/Support/FileSystem.h"
27#include "llvm/Support/Path.h"
37 llvm::cl::desc(
"Enable single byte coverage"),
38 llvm::cl::Hidden, llvm::cl::init(
false));
42 "emptyline-comment-coverage",
43 llvm::cl::desc(
"Emit emptylines and comment lines as skipped regions (only "
44 "disable it on test)"),
45 llvm::cl::init(
true), llvm::cl::Hidden);
49 "system-headers-coverage",
50 cl::desc(
"Enable collecting coverage from system headers"), cl::init(
false),
70 if (
Tok.getKind() != clang::tok::eod)
80 PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
81 SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
83 SkippedRanges.back().Range.setEnd(Range.getEnd());
85 SkippedRanges.push_back({Range, RangeKind,
PrevTokLoc});
102 if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
103 SkippedRanges.back().NextTokLoc = Loc;
108class SourceMappingRegion {
113 std::optional<Counter> FalseCount;
116 mcdc::Parameters MCDCParams;
119 std::optional<SourceLocation> LocStart;
122 std::optional<SourceLocation> LocEnd;
133 SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart,
134 std::optional<SourceLocation> LocEnd,
135 bool GapRegion =
false)
136 : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
137 SkippedRegion(
false) {}
139 SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount,
140 mcdc::Parameters MCDCParams,
141 std::optional<SourceLocation> LocStart,
142 std::optional<SourceLocation> LocEnd,
143 bool GapRegion =
false)
144 : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams),
145 LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
146 SkippedRegion(
false) {}
148 SourceMappingRegion(mcdc::Parameters MCDCParams,
149 std::optional<SourceLocation> LocStart,
150 std::optional<SourceLocation> LocEnd)
151 : MCDCParams(MCDCParams), LocStart(LocStart), LocEnd(LocEnd),
154 const Counter &getCounter()
const {
return Count; }
156 const Counter &getFalseCounter()
const {
157 assert(FalseCount &&
"Region has no alternate counter");
161 void setCounter(Counter
C) { Count =
C; }
163 bool hasStartLoc()
const {
return LocStart.has_value(); }
165 void setStartLoc(SourceLocation Loc) { LocStart = Loc; }
167 SourceLocation getBeginLoc()
const {
168 assert(LocStart &&
"Region has no start location");
172 bool hasEndLoc()
const {
return LocEnd.has_value(); }
174 void setEndLoc(SourceLocation Loc) {
175 assert(Loc.
isValid() &&
"Setting an invalid end location");
179 SourceLocation getEndLoc()
const {
180 assert(LocEnd &&
"Region has no end location");
184 bool isGap()
const {
return GapRegion; }
186 void setGap(
bool Gap) { GapRegion = Gap; }
188 bool isSkipped()
const {
return SkippedRegion; }
190 void setSkipped(
bool Skipped) { SkippedRegion = Skipped; }
192 bool isBranch()
const {
return FalseCount.has_value(); }
194 bool isMCDCBranch()
const {
195 return std::holds_alternative<mcdc::BranchParameters>(MCDCParams);
198 const auto &getMCDCBranchParams()
const {
199 return mcdc::getParams<const mcdc::BranchParameters>(MCDCParams);
202 bool isMCDCDecision()
const {
203 return std::holds_alternative<mcdc::DecisionParameters>(MCDCParams);
206 const auto &getMCDCDecisionParams()
const {
207 return mcdc::getParams<const mcdc::DecisionParameters>(MCDCParams);
210 const mcdc::Parameters &getMCDCParams()
const {
return MCDCParams; }
212 void resetMCDCParams() { MCDCParams = mcdc::Parameters(); }
216struct SpellingRegion {
221 unsigned ColumnStart;
229 SpellingRegion(SourceManager &SM, SourceLocation LocStart,
230 SourceLocation LocEnd) {
237 SpellingRegion(SourceManager &SM, SourceMappingRegion &R)
238 : SpellingRegion(SM,
R.getBeginLoc(),
R.getEndLoc()) {}
242 bool isInSourceOrder()
const {
243 return (LineStart < LineEnd) ||
244 (LineStart == LineEnd && ColumnStart <= ColumnEnd);
250class CoverageMappingBuilder {
252 CoverageMappingModuleGen &CVM;
254 const LangOptions &LangOpts;
258 llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
263 llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
265 std::vector<SourceMappingRegion> SourceRegions;
272 typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
275 CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
276 const LangOptions &LangOpts)
277 : CVM(CVM), SM(SM), LangOpts(LangOpts) {}
280 SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
289 SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
296 SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
310 std::pair<SourceLocation, std::optional<SourceLocation>>
311 getNonScratchExpansionLoc(SourceLocation Loc) {
312 std::optional<SourceLocation> EndLoc = std::nullopt;
316 Loc = ExpansionRange.getBegin();
317 EndLoc = ExpansionRange.getEnd();
319 return std::make_pair(Loc, EndLoc);
325 SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc,
326 bool AcceptScratch =
true) {
332 return getNonScratchExpansionLoc(Loc).first;
336 bool isInBuiltin(SourceLocation Loc) {
341 bool isNestedIn(SourceLocation Loc, FileID Parent) {
343 Loc = getIncludeOrExpansionLoc(Loc);
351 SourceLocation getStart(
const Stmt *S) {
359 SourceLocation getEnd(
const Stmt *S) {
363 return getPreciseTokenLocEnd(Loc);
371 void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
372 FileIDMapping.clear();
374 llvm::SmallSet<FileID, 8> Visited;
375 SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
376 for (
auto &Region : SourceRegions) {
377 SourceLocation Loc = Region.getBeginLoc();
380 auto NonScratchExpansionLoc = getNonScratchExpansionLoc(Loc);
381 auto EndLoc = NonScratchExpansionLoc.second;
382 if (EndLoc.has_value()) {
383 Loc = NonScratchExpansionLoc.first;
384 Region.setStartLoc(Loc);
385 Region.setEndLoc(EndLoc.value());
399 Region.setStartLoc(Loc);
400 Region.setEndLoc(SM.
getFileLoc(Region.getEndLoc()));
408 if (!Visited.insert(
File).second)
412 for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
413 Parent.
isValid(); Parent = getIncludeOrExpansionLoc(Parent))
415 FileLocs.push_back(std::make_pair(Loc, Depth));
417 llvm::stable_sort(FileLocs, llvm::less_second());
419 for (
const auto &FL : FileLocs) {
420 SourceLocation Loc = FL.first;
426 FileIDMapping[SM.
getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
427 Mapping.push_back(CVM.
getFileID(*Entry));
434 std::optional<unsigned> getCoverageFileID(SourceLocation Loc) {
435 auto Mapping = FileIDMapping.find(SM.
getFileID(Loc));
436 if (Mapping != FileIDMapping.end())
437 return Mapping->second.first;
446 std::optional<SpellingRegion> adjustSkippedRange(SourceManager &SM,
447 SourceLocation LocStart,
448 SourceLocation LocEnd,
449 SourceLocation PrevTokLoc,
450 SourceLocation NextTokLoc) {
451 SpellingRegion SR{SM, LocStart, LocEnd};
461 if (SR.isInSourceOrder())
468 void gatherSkippedRegions() {
471 llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
472 FileLineRanges.resize(
473 FileIDMapping.size(),
474 std::make_pair(std::numeric_limits<unsigned>::max(), 0));
475 for (
const auto &R : MappingRegions) {
476 FileLineRanges[
R.FileID].first =
477 std::min(FileLineRanges[
R.FileID].first,
R.LineStart);
478 FileLineRanges[
R.FileID].second =
479 std::max(FileLineRanges[
R.FileID].second,
R.LineEnd);
483 for (
auto &I : SkippedRanges) {
484 SourceRange
Range = I.Range;
485 auto LocStart =
Range.getBegin();
486 auto LocEnd =
Range.getEnd();
488 "region spans multiple files");
490 auto CovFileID = getCoverageFileID(LocStart);
493 std::optional<SpellingRegion> SR;
495 SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc,
497 else if (I.isPPIfElse() || I.isEmptyLine())
498 SR = {SM, LocStart, LocEnd};
502 auto Region = CounterMappingRegion::makeSkipped(
503 *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
507 if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
508 Region.LineEnd <= FileLineRanges[*CovFileID].second)
509 MappingRegions.push_back(Region);
515 void emitSourceRegions(
const SourceRegionFilter &Filter) {
516 for (
const auto &Region : SourceRegions) {
517 assert(Region.hasEndLoc() &&
"incomplete region");
519 SourceLocation LocStart = Region.getBeginLoc();
526 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
527 "Don't suppress the condition in system headers");
531 auto CovFileID = getCoverageFileID(LocStart);
534 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
535 "Don't suppress the condition in non-file regions");
539 SourceLocation LocEnd = Region.getEndLoc();
541 "region spans multiple files");
547 if (
Filter.count(std::make_pair(LocStart, LocEnd))) {
548 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
549 "Don't suppress the condition");
554 SpellingRegion SR{SM, LocStart, LocEnd};
555 assert(SR.isInSourceOrder() &&
"region start and end out of order");
557 if (Region.isGap()) {
558 MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
559 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
560 SR.LineEnd, SR.ColumnEnd));
561 }
else if (Region.isSkipped()) {
562 MappingRegions.push_back(CounterMappingRegion::makeSkipped(
563 *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd,
565 }
else if (Region.isBranch()) {
566 MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
567 Region.getCounter(), Region.getFalseCounter(), *CovFileID,
568 SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd,
569 Region.getMCDCParams()));
570 }
else if (Region.isMCDCDecision()) {
571 MappingRegions.push_back(CounterMappingRegion::makeDecisionRegion(
572 Region.getMCDCDecisionParams(), *CovFileID, SR.LineStart,
573 SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
575 MappingRegions.push_back(CounterMappingRegion::makeRegion(
576 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
577 SR.LineEnd, SR.ColumnEnd));
583 SourceRegionFilter emitExpansionRegions() {
584 SourceRegionFilter
Filter;
585 for (
const auto &FM : FileIDMapping) {
586 SourceLocation ExpandedLoc = FM.second.second;
587 SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc,
false);
591 auto ParentFileID = getCoverageFileID(ParentLoc);
594 auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
595 assert(ExpandedFileID &&
"expansion in uncovered file");
597 SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
599 "region spans multiple files");
600 Filter.insert(std::make_pair(ParentLoc, LocEnd));
602 SpellingRegion SR{SM, ParentLoc, LocEnd};
603 assert(SR.isInSourceOrder() &&
"region start and end out of order");
604 MappingRegions.push_back(CounterMappingRegion::makeExpansion(
605 *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
606 SR.LineEnd, SR.ColumnEnd));
614struct EmptyCoverageMappingBuilder :
public CoverageMappingBuilder {
615 EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
616 const LangOptions &LangOpts)
617 : CoverageMappingBuilder(CVM, SM, LangOpts) {}
619 void VisitDecl(
const Decl *D) {
623 SourceLocation Start = getStart(Body);
624 SourceLocation End = getEnd(Body);
628 FileID StartFileID = SM.
getFileID(Start);
630 while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
631 Start = getIncludeOrExpansionLoc(Start);
633 "Declaration start location not nested within a known region");
636 while (StartFileID != EndFileID) {
637 End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
639 "Declaration end location not nested within a known region");
643 SourceRegions.emplace_back(Counter(), Start, End);
647 void write(llvm::raw_ostream &OS) {
648 SmallVector<unsigned, 16> FileIDMapping;
649 gatherFileIDs(FileIDMapping);
650 emitSourceRegions(SourceRegionFilter());
652 if (MappingRegions.empty())
655 CoverageMappingWriter Writer(FileIDMapping, {}, MappingRegions);
668struct MCDCCoverageBuilder {
759 MCDC::State &MCDCState;
761 struct DecisionState {
763 const Expr *DecisionExpr =
nullptr;
768 mcdc::ConditionIDs CurCondIDs = {-1, -1};
771 mcdc::ConditionID NextID = 0;
776 DecisionState() =
default;
777 DecisionState(
const Expr *DecisionExpr,
bool Valid)
778 : DecisionExpr(DecisionExpr), Active(
Valid) {}
784 llvm::SmallVector<DecisionState, 2> DecisionStack;
788 llvm::DenseMap<unsigned, unsigned> DecisionEndToSince;
791 MCDCCoverageBuilder(CodeGenModule &CGM, MCDC::State &MCDCState)
792 : CGM(CGM), MCDCState(MCDCState), DecisionStack(1) {}
794 bool isActive()
const {
return DecisionStack.back().Active; }
797 void setCondID(
const Expr *Cond, mcdc::ConditionID ID) {
800 ID, DecisionStack.back().DecisionExpr};
804 mcdc::ConditionID getCondID(
const Expr *Cond)
const {
813 auto &getCurCondIDs() {
return DecisionStack.back().CurCondIDs; }
819 std::swap(getCurCondIDs()[
false], getCurCondIDs()[
true]);
822 void checkDecisionRootOrPush(
const Expr *E) {
825 assert(!isActive() &&
"The setinel should tell 'not Active'");
830 if (getCondID(SC) >= 0)
836 auto &StackTop = DecisionStack.emplace_back(SC, DI->second.isValid());
840 if (isActive() && getCondID(SC) < 0)
841 setCondID(SC, StackTop.NextID++);
845 assert((!isActive() || DecisionStack.back().NextID > 0) &&
846 "Should be Active and after assignments");
852 std::pair<mcdc::ConditionID, mcdc::ConditionID>
853 pushAndAssignIDs(
const BinaryOperator *E) {
857 checkDecisionRootOrPush(E);
861 auto &StackTop = DecisionStack.back();
864 mcdc::ConditionID LHSid = getCondID(E);
866 setCondID(E->
getLHS(), LHSid);
869 mcdc::ConditionID RHSid = StackTop.NextID++;
870 setCondID(E->
getRHS(), RHSid);
872 return {LHSid, RHSid};
877 unsigned getTotalConditionsAndPop(
const Expr *E) {
878 auto &StackTop = DecisionStack.back();
881 if (StackTop.DecisionExpr != E)
884 assert(StackTop.CurCondIDs[
false] == -1 &&
885 StackTop.CurCondIDs[
true] == -1 &&
886 "The root shouldn't depend on others.");
889 unsigned TotalConds = (StackTop.Active ? StackTop.NextID : 0);
890 DecisionStack.pop_back();
891 assert(!DecisionStack.empty() &&
"Sentiel?");
895 void addDecisionRegionRange(
unsigned Since,
unsigned End) {
896 DecisionEndToSince[End] = Since;
900 unsigned skipSourceRegionIndexForDecisions(
unsigned Idx) {
901 auto I = DecisionEndToSince.find(Idx);
902 assert(I != DecisionEndToSince.end());
903 assert(I->second <= Idx);
910struct CounterCoverageMappingBuilder
911 :
public CoverageMappingBuilder,
912 public ConstStmtVisitor<CounterCoverageMappingBuilder> {
914 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;
919 CounterExpressionBuilder::SubstMap MapToExpand;
922 unsigned NextCounterNum;
924 MCDC::State &MCDCState;
927 llvm::SmallVector<SourceMappingRegion> RegionStack;
931 llvm::DenseSet<const Stmt *> LeafExprSet;
934 MCDCCoverageBuilder MCDCBuilder;
936 CounterExpressionBuilder Builder;
942 SourceLocation MostRecentLocation;
945 bool HasTerminateStmt =
false;
948 Counter GapRegionCounter;
951 Counter subtractCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
953 "cannot add counters when single byte coverage mode is enabled");
954 return Builder.subtract(LHS, RHS, Simplify);
958 Counter addCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
959 return Builder.add(LHS, RHS, Simplify);
962 Counter addCounters(Counter C1, Counter C2, Counter C3,
963 bool Simplify =
true) {
964 return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
970 Counter getRegionCounter(
const Stmt *S) {
971 return Counter::getCounter(CounterMap[S].Executed);
974 struct BranchCounterPair {
991 getBranchCounterPair(
const Stmt *S, Counter ParentCnt,
992 std::optional<Counter> SkipCntForOld = std::nullopt) {
993 auto &TheMap = CounterMap[S];
994 auto ExecCnt = Counter::getCounter(TheMap.Executed);
996 BranchCounterPair Counters = {ExecCnt,
997 Builder.subtract(ParentCnt, ExecCnt)};
1001 !TheMap.Skipped.hasValue() &&
1002 "SkipCnt shouldn't be allocated but refer to an existing counter.");
1007 if (!TheMap.Skipped.hasValue())
1008 TheMap.Skipped = NextCounterNum++;
1011 Counter SkipCnt = Counter::getCounter(TheMap.Skipped);
1012 MapToExpand[SkipCnt] = Builder.subst(Counters.Skipped, MapToExpand);
1013 Counters.Skipped = SkipCnt;
1019 std::pair<Counter, Counter>
1020 getSwitchImplicitDefaultCounterPair(
const Stmt *Cond, Counter ParentCount,
1021 Counter CaseCountSum) {
1024 unsigned Idx = NextCounterNum++;
1025 CounterMap[Cond].Skipped = Idx;
1026 return {Counter::getZero(),
1027 Counter::getCounter(Idx)};
1034 addCounters(CaseCountSum, Counter::getZero(),
true);
1036 return {CaseCountSum, Builder.subtract(ParentCount, CaseCountSum)};
1039 bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
1040 if (OutCount == ParentCount)
1052 if (Builder.subst(Builder.subtract(OutCount, ParentCount), MapToExpand)
1063 size_t pushRegion(Counter Count,
1064 std::optional<SourceLocation> StartLoc = std::nullopt,
1065 std::optional<SourceLocation> EndLoc = std::nullopt,
1066 std::optional<Counter> FalseCount = std::nullopt,
1067 const mcdc::Parameters &BranchParams = std::monostate()) {
1069 if (StartLoc && !FalseCount) {
1070 MostRecentLocation = *StartLoc;
1075 assert((!StartLoc || StartLoc->isValid()) &&
"Start location is not valid");
1076 assert((!EndLoc || EndLoc->isValid()) &&
"End location is not valid");
1082 if (StartLoc && StartLoc->isInvalid())
1083 StartLoc = std::nullopt;
1084 if (EndLoc && EndLoc->isInvalid())
1085 EndLoc = std::nullopt;
1086 RegionStack.emplace_back(Count, FalseCount, BranchParams, StartLoc, EndLoc);
1088 return RegionStack.size() - 1;
1091 size_t pushRegion(
const mcdc::DecisionParameters &DecisionParams,
1092 std::optional<SourceLocation> StartLoc = std::nullopt,
1093 std::optional<SourceLocation> EndLoc = std::nullopt) {
1095 RegionStack.emplace_back(DecisionParams, StartLoc, EndLoc);
1097 return RegionStack.size() - 1;
1100 size_t locationDepth(SourceLocation Loc) {
1103 Loc = getIncludeOrExpansionLoc(Loc);
1113 void popRegions(
size_t ParentIndex) {
1114 assert(RegionStack.size() >= ParentIndex &&
"parent not in stack");
1115 while (RegionStack.size() > ParentIndex) {
1116 SourceMappingRegion &Region = RegionStack.back();
1117 if (Region.hasStartLoc() &&
1118 (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) {
1119 SourceLocation StartLoc = Region.getBeginLoc();
1120 SourceLocation EndLoc = Region.hasEndLoc()
1121 ? Region.getEndLoc()
1122 : RegionStack[ParentIndex].getEndLoc();
1123 bool isBranch = Region.isBranch();
1124 size_t StartDepth = locationDepth(StartLoc);
1125 size_t EndDepth = locationDepth(EndLoc);
1127 bool UnnestStart = StartDepth >= EndDepth;
1128 bool UnnestEnd = EndDepth >= StartDepth;
1136 SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
1139 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
1140 SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
1143 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
1145 llvm::report_fatal_error(
1146 "File exit not handled before popRegions");
1156 SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
1159 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
1160 SourceRegions.emplace_back(Region.getCounter(), StartLoc,
1163 StartLoc = getIncludeOrExpansionLoc(StartLoc);
1165 llvm::report_fatal_error(
1166 "File exit not handled before popRegions");
1170 Region.setStartLoc(StartLoc);
1171 Region.setEndLoc(EndLoc);
1174 MostRecentLocation = EndLoc;
1177 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
1178 EndLoc == getEndOfFileOrMacro(EndLoc))
1179 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
1183 assert(SpellingRegion(SM, Region).isInSourceOrder());
1184 SourceRegions.push_back(Region);
1186 RegionStack.pop_back();
1191 SourceMappingRegion &getRegion() {
1192 assert(!RegionStack.empty() &&
"statement has no region");
1193 return RegionStack.back();
1198 Counter propagateCounts(Counter TopCount,
const Stmt *S,
1199 bool VisitChildren =
true) {
1200 SourceLocation StartLoc = getStart(S);
1201 SourceLocation EndLoc = getEnd(S);
1202 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
1205 Counter ExitCount = getRegion().getCounter();
1211 MostRecentLocation = EndLoc;
1220 void createBranchRegion(
const Expr *
C, Counter TrueCnt, Counter FalseCnt,
1221 const mcdc::ConditionIDs &Conds = {}) {
1234 mcdc::Parameters BranchParams;
1235 mcdc::ConditionID
ID = MCDCBuilder.getCondID(
C);
1237 BranchParams = mcdc::BranchParameters{
ID, Conds};
1247 if (
Result.Val.getInt().getBoolValue())
1248 FalseCnt = Counter::getZero();
1250 TrueCnt = Counter::getZero();
1253 pushRegion(TrueCnt, getStart(
C), getEnd(
C), FalseCnt, BranchParams));
1260 void createDecisionRegion(
const Expr *
C,
1261 const mcdc::DecisionParameters &DecisionParams) {
1262 popRegions(pushRegion(DecisionParams, getStart(
C), getEnd(
C)));
1268 Counter createSwitchCaseRegion(
const SwitchCase *SC, Counter ParentCount) {
1269 Counter TrueCnt = getRegionCounter(SC);
1271 ? Counter::getZero()
1272 : subtractCounters(ParentCount, TrueCnt));
1276 popRegions(pushRegion(TrueCnt, getStart(SC), SC->
getColonLoc(), FalseCnt));
1282 bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
1283 bool isBranch =
false) {
1284 return llvm::any_of(
1285 llvm::reverse(SourceRegions), [&](
const SourceMappingRegion &Region) {
1286 return Region.getBeginLoc() == StartLoc &&
1287 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
1294 void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
1295 MostRecentLocation = EndLoc;
1301 if (getRegion().hasEndLoc() &&
1302 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
1303 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
1304 MostRecentLocation, getRegion().isBranch()))
1305 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
1313 void handleFileExit(SourceLocation NewLoc) {
1320 SourceLocation LCA = NewLoc;
1322 while (!isNestedIn(MostRecentLocation, ParentFile)) {
1323 LCA = getIncludeOrExpansionLoc(LCA);
1327 MostRecentLocation = NewLoc;
1333 llvm::SmallSet<SourceLocation, 8> StartLocs;
1334 std::optional<Counter> ParentCounter;
1335 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
1336 if (!I.hasStartLoc())
1338 SourceLocation Loc = I.getBeginLoc();
1339 if (!isNestedIn(Loc, ParentFile)) {
1340 ParentCounter = I.getCounter();
1348 if (StartLocs.insert(Loc).second) {
1350 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(),
1351 I.getMCDCParams(), Loc,
1352 getEndOfFileOrMacro(Loc), I.isBranch());
1354 SourceRegions.emplace_back(I.getCounter(), Loc,
1355 getEndOfFileOrMacro(Loc));
1357 Loc = getIncludeOrExpansionLoc(Loc);
1359 I.setStartLoc(getPreciseTokenLocEnd(Loc));
1362 if (ParentCounter) {
1366 SourceLocation Loc = MostRecentLocation;
1367 while (isNestedIn(Loc, ParentFile)) {
1368 SourceLocation FileStart = getStartOfFileOrMacro(Loc);
1369 if (StartLocs.insert(FileStart).second) {
1370 SourceRegions.emplace_back(*ParentCounter, FileStart,
1371 getEndOfFileOrMacro(Loc));
1372 assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder());
1374 Loc = getIncludeOrExpansionLoc(Loc);
1378 MostRecentLocation = NewLoc;
1382 void extendRegion(
const Stmt *S) {
1383 SourceMappingRegion &Region = getRegion();
1384 SourceLocation StartLoc = getStart(S);
1386 handleFileExit(StartLoc);
1387 if (!Region.hasStartLoc())
1388 Region.setStartLoc(StartLoc);
1392 void terminateRegion(
const Stmt *S) {
1394 SourceMappingRegion &Region = getRegion();
1395 SourceLocation EndLoc = getEnd(S);
1396 if (!Region.hasEndLoc())
1397 Region.setEndLoc(EndLoc);
1398 pushRegion(Counter::getZero());
1399 HasTerminateStmt =
true;
1403 std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
1404 SourceLocation BeforeLoc) {
1409 return std::nullopt;
1420 size_t StartDepth = locationDepth(AfterLoc);
1421 size_t EndDepth = locationDepth(BeforeLoc);
1423 bool UnnestStart = StartDepth >= EndDepth;
1424 bool UnnestEnd = EndDepth >= StartDepth;
1429 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1435 getEndOfFileOrMacro(AfterLoc)));
1437 AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
1439 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1444 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1448 return std::nullopt;
1450 !SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder())
1451 return std::nullopt;
1452 return {{AfterLoc, BeforeLoc}};
1456 void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
1458 if (StartLoc == EndLoc)
1460 assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder());
1461 handleFileExit(StartLoc);
1462 size_t Index = pushRegion(Count, StartLoc, EndLoc);
1463 getRegion().setGap(
true);
1464 handleFileExit(EndLoc);
1470 std::optional<SourceRange> findAreaStartingFromTo(SourceLocation StartingLoc,
1471 SourceLocation BeforeLoc) {
1480 size_t StartDepth = locationDepth(StartingLoc);
1481 size_t EndDepth = locationDepth(BeforeLoc);
1483 bool UnnestStart = StartDepth >= EndDepth;
1484 bool UnnestEnd = EndDepth >= StartDepth;
1489 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1495 getStartOfFileOrMacro(StartingLoc)));
1497 StartingLoc = getIncludeOrExpansionLoc(StartingLoc);
1498 assert(StartingLoc.
isValid());
1505 return std::nullopt;
1507 !SpellingRegion(SM, StartingLoc, BeforeLoc).isInSourceOrder())
1508 return std::nullopt;
1509 return {{StartingLoc, BeforeLoc}};
1512 void markSkipped(SourceLocation StartLoc, SourceLocation BeforeLoc) {
1513 const auto Skipped = findAreaStartingFromTo(StartLoc, BeforeLoc);
1518 const auto NewStartLoc = Skipped->getBegin();
1519 const auto EndLoc = Skipped->getEnd();
1521 if (NewStartLoc == EndLoc)
1523 assert(SpellingRegion(SM, NewStartLoc, EndLoc).isInSourceOrder());
1524 handleFileExit(NewStartLoc);
1525 size_t Index = pushRegion(Counter{}, NewStartLoc, EndLoc);
1526 getRegion().setSkipped(
true);
1527 handleFileExit(EndLoc);
1532 struct BreakContinue {
1534 Counter ContinueCount;
1536 SmallVector<BreakContinue, 8> BreakContinueStack;
1538 CounterCoverageMappingBuilder(
1539 CoverageMappingModuleGen &CVM,
1540 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,
1541 MCDC::State &MCDCState, SourceManager &SM,
const LangOptions &LangOpts)
1542 : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
1543 NextCounterNum(CounterMap.size()), MCDCState(MCDCState),
1544 MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {}
1547 void write(llvm::raw_ostream &OS) {
1548 llvm::SmallVector<unsigned, 8> VirtualFileMapping;
1549 gatherFileIDs(VirtualFileMapping);
1550 SourceRegionFilter
Filter = emitExpansionRegions();
1551 emitSourceRegions(Filter);
1552 gatherSkippedRegions();
1554 if (MappingRegions.empty())
1557 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
1562 void VisitStmt(
const Stmt *S) {
1565 const Stmt *LastStmt =
nullptr;
1566 bool SaveTerminateStmt = HasTerminateStmt;
1567 HasTerminateStmt =
false;
1568 GapRegionCounter = Counter::getZero();
1569 for (
const Stmt *Child : S->
children())
1573 if (LastStmt && HasTerminateStmt) {
1574 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
1576 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
1578 SaveTerminateStmt =
true;
1579 HasTerminateStmt =
false;
1584 if (SaveTerminateStmt)
1585 HasTerminateStmt =
true;
1586 handleFileExit(getEnd(S));
1589 void VisitStmtExpr(
const StmtExpr *E) {
1594 HasTerminateStmt =
false;
1597 void VisitDecl(
const Decl *D) {
1610 Counter BodyCounter = getRegionCounter(Body);
1612 if (
auto *
Method = dyn_cast<CXXMethodDecl>(D))
1614 if (
auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
1618 if (getStart(
Init).isValid() && getEnd(
Init).isValid())
1619 propagateCounts(BodyCounter,
Init);
1624 propagateCounts(BodyCounter, Body,
1626 assert(RegionStack.empty() &&
"Regions entered but never exited");
1629 void VisitReturnStmt(
const ReturnStmt *S) {
1636 void VisitCoroutineBodyStmt(
const CoroutineBodyStmt *S) {
1641 void VisitCoreturnStmt(
const CoreturnStmt *S) {
1648 void VisitCoroutineSuspendExpr(
const CoroutineSuspendExpr *E) {
1652 void VisitCXXThrowExpr(
const CXXThrowExpr *E) {
1659 void VisitGotoStmt(
const GotoStmt *S) { terminateRegion(S); }
1661 void VisitLabelStmt(
const LabelStmt *S) {
1662 Counter LabelCount = getRegionCounter(S);
1663 SourceLocation Start = getStart(S);
1665 handleFileExit(Start);
1666 pushRegion(LabelCount, Start);
1670 void VisitBreakStmt(
const BreakStmt *S) {
1671 assert(!BreakContinueStack.empty() &&
"break not in a loop or switch!");
1672 BreakContinueStack.back().BreakCount = addCounters(
1673 BreakContinueStack.back().BreakCount, getRegion().getCounter());
1679 void VisitContinueStmt(
const ContinueStmt *S) {
1680 assert(!BreakContinueStack.empty() &&
"continue stmt not in a loop!");
1681 BreakContinueStack.back().ContinueCount = addCounters(
1682 BreakContinueStack.back().ContinueCount, getRegion().getCounter());
1686 void VisitCallExpr(
const CallExpr *E) {
1696 void VisitWhileStmt(
const WhileStmt *S) {
1699 Counter ParentCount = getRegion().getCounter();
1700 Counter BodyCount = getRegionCounter(S);
1703 BreakContinueStack.push_back(BreakContinue());
1705 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1706 BreakContinue BC = BreakContinueStack.pop_back_val();
1708 bool BodyHasTerminateStmt = HasTerminateStmt;
1709 HasTerminateStmt =
false;
1713 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1714 auto BranchCount = getBranchCounterPair(S, CondCount);
1715 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1717 propagateCounts(CondCount, S->
getCond());
1718 adjustForOutOfOrderTraversal(getEnd(S));
1723 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1725 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1726 if (!IsCounterEqual(OutCount, ParentCount)) {
1727 pushRegion(OutCount);
1728 GapRegionCounter = OutCount;
1729 if (BodyHasTerminateStmt)
1730 HasTerminateStmt =
true;
1734 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1737 void VisitDoStmt(
const DoStmt *S) {
1740 Counter ParentCount = getRegion().getCounter();
1741 Counter BodyCount = getRegionCounter(S);
1743 BreakContinueStack.push_back(BreakContinue());
1746 Counter BackedgeCount =
1747 propagateCounts(addCounters(ParentCount, BodyCount), S->
getBody());
1749 BreakContinue BC = BreakContinueStack.pop_back_val();
1751 bool BodyHasTerminateStmt = HasTerminateStmt;
1752 HasTerminateStmt =
false;
1754 Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
1755 auto BranchCount = getBranchCounterPair(S, CondCount);
1756 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1758 propagateCounts(CondCount, S->
getCond());
1760 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1761 if (!IsCounterEqual(OutCount, ParentCount)) {
1762 pushRegion(OutCount);
1763 GapRegionCounter = OutCount;
1764 if (BodyHasTerminateStmt)
1765 HasTerminateStmt =
true;
1769 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1772 void VisitForStmt(
const ForStmt *S) {
1777 Counter ParentCount = getRegion().getCounter();
1778 Counter BodyCount = getRegionCounter(S);
1782 BreakContinueStack.emplace_back();
1785 BreakContinueStack.emplace_back();
1787 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1788 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1790 bool BodyHasTerminateStmt = HasTerminateStmt;
1791 HasTerminateStmt =
false;
1795 BreakContinue IncrementBC;
1796 if (
const Stmt *Inc = S->
getInc()) {
1797 propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
1798 IncrementBC = BreakContinueStack.pop_back_val();
1802 Counter CondCount = addCounters(
1803 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1804 IncrementBC.ContinueCount);
1805 auto BranchCount = getBranchCounterPair(S, CondCount);
1806 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1808 if (
const Expr *Cond = S->
getCond()) {
1809 propagateCounts(CondCount, Cond);
1810 adjustForOutOfOrderTraversal(getEnd(S));
1816 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1818 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1819 BranchCount.Skipped);
1820 if (!IsCounterEqual(OutCount, ParentCount)) {
1821 pushRegion(OutCount);
1822 GapRegionCounter = OutCount;
1823 if (BodyHasTerminateStmt)
1824 HasTerminateStmt =
true;
1828 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1831 void VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
1838 Counter ParentCount = getRegion().getCounter();
1839 Counter BodyCount = getRegionCounter(S);
1841 BreakContinueStack.push_back(BreakContinue());
1843 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1844 BreakContinue BC = BreakContinueStack.pop_back_val();
1846 bool BodyHasTerminateStmt = HasTerminateStmt;
1847 HasTerminateStmt =
false;
1852 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1855 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1856 auto BranchCount = getBranchCounterPair(S, LoopCount);
1857 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1859 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1860 if (!IsCounterEqual(OutCount, ParentCount)) {
1861 pushRegion(OutCount);
1862 GapRegionCounter = OutCount;
1863 if (BodyHasTerminateStmt)
1864 HasTerminateStmt =
true;
1868 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1871 void VisitObjCForCollectionStmt(
const ObjCForCollectionStmt *S) {
1875 Counter ParentCount = getRegion().getCounter();
1876 Counter BodyCount = getRegionCounter(S);
1878 BreakContinueStack.push_back(BreakContinue());
1880 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1881 BreakContinue BC = BreakContinueStack.pop_back_val();
1886 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1889 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1890 auto BranchCount = getBranchCounterPair(S, LoopCount);
1891 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1892 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1893 if (!IsCounterEqual(OutCount, ParentCount)) {
1894 pushRegion(OutCount);
1895 GapRegionCounter = OutCount;
1899 void VisitSwitchStmt(
const SwitchStmt *S) {
1905 BreakContinueStack.push_back(BreakContinue());
1907 const Stmt *Body = S->
getBody();
1909 if (
const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1910 if (!CS->body_empty()) {
1914 size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1915 getRegion().setGap(
true);
1919 for (
size_t i = RegionStack.size(); i != Index; --i) {
1920 if (!RegionStack[i - 1].hasEndLoc())
1921 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1927 propagateCounts(Counter::getZero(), Body);
1928 BreakContinue BC = BreakContinueStack.pop_back_val();
1930 if (!BreakContinueStack.empty())
1931 BreakContinueStack.back().ContinueCount = addCounters(
1932 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1934 Counter ParentCount = getRegion().getCounter();
1935 Counter ExitCount = getRegionCounter(S);
1936 SourceLocation ExitLoc = getEnd(S);
1937 pushRegion(ExitCount);
1938 GapRegionCounter = ExitCount;
1942 MostRecentLocation = getStart(S);
1943 handleFileExit(ExitLoc);
1947 Counter CaseCountSum;
1948 bool HasDefaultCase =
false;
1952 auto CaseCount = createSwitchCaseRegion(Case, ParentCount);
1953 CaseCountSum = addCounters(CaseCountSum, CaseCount,
false);
1958 if (!HasDefaultCase) {
1959 auto Counters = getSwitchImplicitDefaultCounterPair(
1960 S->
getCond(), ParentCount, CaseCountSum);
1961 createBranchRegion(S->
getCond(), Counters.first, Counters.second);
1965 void VisitSwitchCase(
const SwitchCase *S) {
1968 SourceMappingRegion &Parent = getRegion();
1969 Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
1973 if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
1974 Parent.setCounter(Count);
1976 pushRegion(Count, getStart(S));
1978 GapRegionCounter = Count;
1980 if (
const auto *CS = dyn_cast<CaseStmt>(S)) {
1981 Visit(CS->getLHS());
1982 if (
const Expr *RHS = CS->getRHS())
1988 void coverIfConsteval(
const IfStmt *S) {
1991 const auto *Then = S->
getThen();
1992 const auto *Else = S->
getElse();
1997 const Counter ParentCount = getRegion().getCounter();
2003 markSkipped(S->
getIfLoc(), getStart(Then));
2004 propagateCounts(ParentCount, Then);
2008 markSkipped(getEnd(Then), getEnd(Else));
2013 markSkipped(S->
getIfLoc(), Else ? getStart(Else) : getEnd(Then));
2016 propagateCounts(ParentCount, Else);
2020 void coverIfConstexpr(
const IfStmt *S) {
2033 const Counter ParentCount = getRegion().getCounter();
2036 SourceLocation startOfSkipped = S->
getIfLoc();
2039 const auto start = getStart(
Init);
2040 const auto end = getEnd(
Init);
2044 if (start.isValid() && end.isValid()) {
2045 markSkipped(startOfSkipped, start);
2046 propagateCounts(ParentCount,
Init);
2047 startOfSkipped = getEnd(
Init);
2051 const auto *Then = S->
getThen();
2052 const auto *Else = S->
getElse();
2056 markSkipped(startOfSkipped, getStart(Then));
2057 propagateCounts(ParentCount, Then);
2061 markSkipped(getEnd(Then), getEnd(Else));
2064 markSkipped(startOfSkipped, Else ? getStart(Else) : getEnd(Then));
2067 propagateCounts(ParentCount, Else);
2071 void VisitIfStmt(
const IfStmt *S) {
2075 return coverIfConsteval(S);
2077 return coverIfConstexpr(S);
2087 Counter ParentCount = getRegion().getCounter();
2088 auto [ThenCount, ElseCount] = getBranchCounterPair(S, ParentCount);
2092 propagateCounts(ParentCount, S->
getCond());
2095 std::optional<SourceRange> Gap =
2098 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
2101 Counter OutCount = propagateCounts(ThenCount, S->
getThen());
2103 if (
const Stmt *Else = S->
getElse()) {
2104 bool ThenHasTerminateStmt = HasTerminateStmt;
2105 HasTerminateStmt =
false;
2107 std::optional<SourceRange> Gap =
2108 findGapAreaBetween(getEnd(S->
getThen()), getStart(Else));
2110 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
2113 OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
2115 if (ThenHasTerminateStmt)
2116 HasTerminateStmt =
true;
2118 OutCount = addCounters(OutCount, ElseCount);
2120 if (!IsCounterEqual(OutCount, ParentCount)) {
2121 pushRegion(OutCount);
2122 GapRegionCounter = OutCount;
2126 createBranchRegion(S->
getCond(), ThenCount, ElseCount);
2129 void VisitCXXTryStmt(
const CXXTryStmt *S) {
2134 Counter ParentCount = getRegion().getCounter();
2140 Counter ExitCount = getRegionCounter(S);
2141 pushRegion(ExitCount);
2144 void VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2148 void VisitAbstractConditionalOperator(
const AbstractConditionalOperator *E) {
2151 Counter ParentCount = getRegion().getCounter();
2152 auto [TrueCount, FalseCount] = getBranchCounterPair(E, ParentCount);
2155 if (
const auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) {
2156 propagateCounts(ParentCount, BCO->getCommon());
2157 OutCount = TrueCount;
2159 propagateCounts(ParentCount, E->
getCond());
2164 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
2167 OutCount = propagateCounts(TrueCount, E->
getTrueExpr());
2172 addCounters(OutCount, propagateCounts(FalseCount, E->
getFalseExpr()));
2174 if (!IsCounterEqual(OutCount, ParentCount)) {
2175 pushRegion(OutCount);
2176 GapRegionCounter = OutCount;
2180 createBranchRegion(E->
getCond(), TrueCount, FalseCount);
2183 inline unsigned findMCDCBranchesInSourceRegion(
2184 unsigned Since,
std::function<
void(SourceMappingRegion &SR)> CB) {
2185 unsigned I = SourceRegions.size() - 1;
2187 while (I >= Since) {
2188 auto &SR = SourceRegions[I];
2189 if (SR.isMCDCDecision()) {
2191 I = MCDCBuilder.skipSourceRegionIndexForDecisions(I);
2192 }
else if (SR.isMCDCBranch()) {
2204 void createOrCancelDecision(
const Expr *E,
unsigned Since) {
2206 auto NumConds = MCDCBuilder.getTotalConditionsAndPop(SC);
2211 llvm::SmallVector<mcdc::ConditionIDs> CondIDs(NumConds);
2212 findMCDCBranchesInSourceRegion(Since, [&](
const SourceMappingRegion &SR) {
2213 auto [
ID, Conds] = SR.getMCDCBranchParams();
2214 CondIDs[
ID] = Conds;
2218 mcdc::TVIdxBuilder Builder(CondIDs);
2219 unsigned NumTVs = Builder.NumTestVectors;
2221 assert(MaxTVs < mcdc::TVIdxBuilder::HardMaxTVs);
2223 if (NumTVs > MaxTVs) {
2225 cancelDecision(SC, Since, NumTVs, MaxTVs, NumConds);
2232 std::move(Builder.Indices));
2234 auto DecisionParams = mcdc::DecisionParameters{
2240 createDecisionRegion(E, DecisionParams);
2243 assert(SourceRegions.back().isMCDCDecision());
2244 MCDCBuilder.addDecisionRegionRange(Since, SourceRegions.size() - 1);
2248 void cancelDecision(
const Expr *Decision,
unsigned Since,
int NumTVs,
2249 int MaxTVs,
unsigned NumConds) {
2251 Diag.Report(Decision->getBeginLoc(), diag::warn_pgo_test_vector_limit)
2252 << NumTVs << MaxTVs;
2255 unsigned FoundCount = findMCDCBranchesInSourceRegion(
2256 Since, [](SourceMappingRegion &SR) { SR.resetMCDCParams(); });
2257 assert(FoundCount == NumConds &&
2258 "Didn't find all MCDCBranches to be restored");
2262 MCDCState.
BranchByStmt.remove_if([&](
const auto &Entry) {
2263 return Entry.second.DecisionStmt == Decision;
2269 bool isExprInSystemHeader(
const BinaryOperator *E)
const {
2276 void VisitUnaryLNot(
const UnaryOperator *E) {
2277 MCDCBuilder.swapConds();
2279 MCDCBuilder.swapConds();
2282 void VisitBinLAnd(
const BinaryOperator *E) {
2283 if (isExprInSystemHeader(E)) {
2284 LeafExprSet.insert(E);
2288 unsigned SourceRegionsSince = SourceRegions.size();
2291 auto [_, RHSid] = MCDCBuilder.pushAndAssignIDs(E);
2294 auto &CurCondIDs = MCDCBuilder.getCurCondIDs();
2295 auto DecisionRHS = CurCondIDs;
2297 CurCondIDs[
true] = RHSid;
2298 auto DecisionLHS = CurCondIDs;
2300 extendRegion(E->
getLHS());
2301 propagateCounts(getRegion().getCounter(), E->
getLHS());
2302 handleFileExit(getEnd(E->
getLHS()));
2307 MCDCBuilder.getCurCondIDs();
2308 CurCondIDs[
true] = DecisionRHS[
true];
2309 assert(CurCondIDs == DecisionRHS);
2313 findGapAreaBetween(getEnd(E->
getLHS()), getStart(E->
getRHS()))) {
2314 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));
2318 extendRegion(E->
getRHS());
2319 propagateCounts(getRegionCounter(E), E->
getRHS());
2322 Counter ParentCnt = getRegion().getCounter();
2325 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2328 auto [RHSTrueCnt, RHSExitCnt] =
2329 getBranchCounterPair(E->
getRHS(), RHSExecCnt);
2332 createBranchRegion(E->
getLHS(), RHSExecCnt, LHSExitCnt, DecisionLHS);
2335 createBranchRegion(E->
getRHS(), RHSTrueCnt, RHSExitCnt, DecisionRHS);
2338 createOrCancelDecision(E, SourceRegionsSince);
2342 bool shouldVisitRHS(
const Expr *LHS) {
2343 bool LHSIsTrue =
false;
2344 bool LHSIsConst =
false;
2348 return !LHSIsConst || (LHSIsConst && !LHSIsTrue);
2351 void VisitBinLOr(
const BinaryOperator *E) {
2352 if (isExprInSystemHeader(E)) {
2353 LeafExprSet.insert(E);
2357 unsigned SourceRegionsSince = SourceRegions.size();
2360 auto [_, RHSid] = MCDCBuilder.pushAndAssignIDs(E);
2363 auto &CurCondIDs = MCDCBuilder.getCurCondIDs();
2364 auto DecisionRHS = CurCondIDs;
2365 CurCondIDs[
false] = RHSid;
2366 auto DecisionLHS = CurCondIDs;
2368 extendRegion(E->
getLHS());
2369 Counter OutCount = propagateCounts(getRegion().getCounter(), E->
getLHS());
2370 handleFileExit(getEnd(E->
getLHS()));
2375 MCDCBuilder.getCurCondIDs();
2376 CurCondIDs[
false] = DecisionRHS[
false];
2377 assert(CurCondIDs == DecisionRHS);
2381 findGapAreaBetween(getEnd(E->
getLHS()), getStart(E->
getRHS()))) {
2382 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));
2386 extendRegion(E->
getRHS());
2387 propagateCounts(getRegionCounter(E), E->
getRHS());
2390 Counter ParentCnt = getRegion().getCounter();
2393 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2396 auto [RHSFalseCnt, RHSExitCnt] =
2397 getBranchCounterPair(E->
getRHS(), RHSExecCnt);
2399 if (!shouldVisitRHS(E->
getLHS())) {
2400 GapRegionCounter = OutCount;
2404 createBranchRegion(E->
getLHS(), LHSExitCnt, RHSExecCnt, DecisionLHS);
2407 createBranchRegion(E->
getRHS(), RHSExitCnt, RHSFalseCnt, DecisionRHS);
2410 createOrCancelDecision(E, SourceRegionsSince);
2418 void VisitArrayInitLoopExpr(
const ArrayInitLoopExpr *AILE) {
2422 void VisitPseudoObjectExpr(
const PseudoObjectExpr *POE) {
2427 void VisitOpaqueValueExpr(
const OpaqueValueExpr* OVE) {
2435static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
2438 OS << FunctionName <<
":\n";
2439 CounterMappingContext Ctx(Expressions);
2440 for (
const auto &R : Regions) {
2443 case CounterMappingRegion::CodeRegion:
2445 case CounterMappingRegion::ExpansionRegion:
2448 case CounterMappingRegion::SkippedRegion:
2451 case CounterMappingRegion::GapRegion:
2454 case CounterMappingRegion::BranchRegion:
2455 case CounterMappingRegion::MCDCBranchRegion:
2458 case CounterMappingRegion::MCDCDecisionRegion:
2463 OS <<
"File " << R.FileID <<
", " << R.LineStart <<
":" << R.ColumnStart
2464 <<
" -> " << R.LineEnd <<
":" << R.ColumnEnd <<
" = ";
2466 if (
const auto *DecisionParams =
2467 std::get_if<mcdc::DecisionParameters>(&R.MCDCParams)) {
2468 OS <<
"M:" << DecisionParams->BitmapIdx;
2469 OS <<
", C:" << DecisionParams->NumConditions;
2471 Ctx.dump(R.Count, OS);
2475 Ctx.dump(R.FalseCount, OS);
2479 if (
const auto *BranchParams =
2480 std::get_if<mcdc::BranchParameters>(&R.MCDCParams)) {
2481 OS <<
" [" << BranchParams->ID + 1 <<
","
2482 << BranchParams->Conds[
true] + 1;
2483 OS <<
"," << BranchParams->Conds[
false] + 1 <<
"] ";
2486 if (R.Kind == CounterMappingRegion::ExpansionRegion)
2487 OS <<
" (Expanded file = " << R.ExpandedFileID <<
")";
2494 : CGM(CGM), SourceInfo(SourceInfo) {}
2496std::string CoverageMappingModuleGen::getCurrentDirname() {
2500std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
2502 llvm::sys::path::remove_dots(Path,
true);
2507 for (
const auto &[From, To] :
2509 if (llvm::sys::path::replace_path_prefix(Path, From, To))
2512 return Path.str().str();
2516 llvm::InstrProfSectKind SK) {
2517 return llvm::getInstrProfSectionName(
2521void CoverageMappingModuleGen::emitFunctionMappingRecord(
2522 const FunctionInfo &Info, uint64_t FilenamesRef) {
2523 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
2526 std::string FuncRecordName =
"__covrec_" + llvm::utohexstr(Info.NameHash);
2533 FuncRecordName +=
"u";
2536 const uint64_t NameHash = Info.NameHash;
2537 const uint64_t FuncHash = Info.FuncHash;
2538 const std::string &CoverageMapping = Info.CoverageMapping;
2539#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
2540 llvm::Type *FunctionRecordTypes[] = {
2541#include "llvm/ProfileData/InstrProfData.inc"
2543 auto *FunctionRecordTy =
2544 llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes),
2548#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
2549 llvm::Constant *FunctionRecordVals[] = {
2550 #include "llvm/ProfileData/InstrProfData.inc"
2552 auto *FuncRecordConstant =
2553 llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals));
2556 auto *FuncRecord =
new llvm::GlobalVariable(
2557 CGM.getModule(), FunctionRecordTy,
true,
2558 llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
2560 FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
2562 FuncRecord->setAlignment(llvm::Align(8));
2563 if (CGM.supportsCOMDAT())
2564 FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
2567 CGM.addUsedGlobal(FuncRecord);
2571 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
2572 const std::string &CoverageMapping,
bool IsUsed) {
2573 const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
2574 FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
2577 FunctionNames.push_back(NamePtr);
2579 if (CGM.getCodeGenOpts().DumpCoverageMapping) {
2586 std::vector<StringRef> Filenames;
2587 std::vector<CounterExpression> Expressions;
2588 std::vector<CounterMappingRegion> Regions;
2589 FilenameStrs.resize(FileEntries.size() + 1);
2590 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2591 for (
const auto &Entry : FileEntries) {
2592 auto I = Entry.second;
2593 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2596 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
2597 Expressions, Regions);
2600 dump(llvm::outs(), NameValue, Expressions, Regions);
2605 if (FunctionRecords.empty())
2607 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
2608 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
2612 FilenameStrs.resize(FileEntries.size() + 1);
2614 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2615 for (
const auto &Entry : FileEntries) {
2616 auto I = Entry.second;
2617 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2620 std::string Filenames;
2622 llvm::raw_string_ostream OS(Filenames);
2623 CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
2625 auto *FilenamesVal =
2626 llvm::ConstantDataArray::getString(Ctx, Filenames,
false);
2627 const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
2630 for (
const FunctionInfo &Info : FunctionRecords)
2631 emitFunctionMappingRecord(Info, FilenamesRef);
2633 const unsigned NRecords = 0;
2634 const size_t FilenamesSize = Filenames.size();
2635 const unsigned CoverageMappingSize = 0;
2636 llvm::Type *CovDataHeaderTypes[] = {
2637#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
2638#include "llvm/ProfileData/InstrProfData.inc"
2640 auto CovDataHeaderTy =
2641 llvm::StructType::get(Ctx,
ArrayRef(CovDataHeaderTypes));
2642 llvm::Constant *CovDataHeaderVals[] = {
2643#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
2644#include "llvm/ProfileData/InstrProfData.inc"
2646 auto CovDataHeaderVal =
2647 llvm::ConstantStruct::get(CovDataHeaderTy,
ArrayRef(CovDataHeaderVals));
2650 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
2651 auto CovDataTy = llvm::StructType::get(Ctx,
ArrayRef(CovDataTypes));
2652 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
2653 auto CovDataVal = llvm::ConstantStruct::get(CovDataTy,
ArrayRef(TUDataVals));
2654 auto CovData =
new llvm::GlobalVariable(
2655 CGM.getModule(), CovDataTy,
true, llvm::GlobalValue::PrivateLinkage,
2656 CovDataVal, llvm::getCoverageMappingVarName());
2659 CovData->setAlignment(llvm::Align(8));
2662 CGM.addUsedGlobal(CovData);
2664 if (!FunctionNames.empty()) {
2665 auto AddrSpace = FunctionNames.front()->getType()->getPointerAddressSpace();
2666 auto NamesArrTy = llvm::ArrayType::get(
2667 llvm::PointerType::get(Ctx, AddrSpace), FunctionNames.size());
2668 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
2671 new llvm::GlobalVariable(CGM.getModule(), NamesArrTy,
true,
2672 llvm::GlobalValue::InternalLinkage, NamesArrVal,
2673 llvm::getCoverageUnusedNamesVarName());
2678 return FileEntries.try_emplace(
File, FileEntries.size() + 1).first->second;
2682 llvm::raw_ostream &OS) {
2683 assert(CounterMap && MCDCState);
2684 CounterCoverageMappingBuilder Walker(CVM, *CounterMap, *MCDCState, SM,
2686 Walker.VisitDecl(D);
2691 llvm::raw_ostream &OS) {
2692 EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
2693 Walker.VisitDecl(D);
Defines the Diagnostic-related interfaces.
static std::string getInstrProfSection(const CodeGenModule &CGM, llvm::InstrProfSectKind SK)
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
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)
Result
Implement __builtin_bit_cast and related operations.
static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)
Produce a diagnostic highlighting some portion of a literal.
const TargetInfo & getTargetInfo() const
Expr * getCond() const
getCond - Return the expression representing the condition for the ?
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
SourceLocation getQuestionLoc() const
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
OpaqueValueExpr * getCommonExpr() const
Get the common subexpression shared by all initializations (the source array).
SourceLocation getBeginLoc() const LLVM_READONLY
SourceLocation getOperatorLoc() const
SourceLocation getEndLoc() const LLVM_READONLY
Stmt * getHandlerBlock() const
DeclStmt * getLoopVarStmt()
DeclStmt * getRangeStmt()
SourceLocation getRParenLoc() const
const Expr * getSubExpr() const
CXXCatchStmt * getHandler(unsigned i)
unsigned getNumHandlers() const
CompoundStmt * getTryBlock()
SourceLocation getBegin() const
llvm::SmallVector< std::pair< std::string, std::string >, 0 > CoveragePrefixMap
Prefix replacement map for source-based code coverage to remap source file paths in coverage mapping.
std::string CoverageCompilationDir
The string to embed in coverage mapping as the current working directory.
static bool isInstrumentedCondition(const Expr *C)
isInstrumentedCondition - Determine whether the given condition is an instrumentable condition (i....
static const Expr * stripCond(const Expr *C)
Ignore parentheses and logical-NOT to track conditions consistently.
This class organizes the cross-function state that is used while generating LLVM code.
DiagnosticsEngine & getDiags() const
ASTContext & getContext() const
const CodeGenOptions & getCodeGenOpts() const
void emitEmptyMapping(const Decl *D, llvm::raw_ostream &OS)
Emit the coverage mapping data for an unused function.
void emitCounterMapping(const Decl *D, llvm::raw_ostream &OS)
Emit the coverage mapping data which maps the regions of code to counters that will be used to find t...
void addFunctionMappingRecord(llvm::GlobalVariable *FunctionName, StringRef FunctionNameValue, uint64_t FunctionHash, const std::string &CoverageMapping, bool IsUsed=true)
Add a function's coverage mapping record to the collection of the function mapping records.
CoverageSourceInfo & getSourceInfo() const
static CoverageSourceInfo * setUpCoverageCallbacks(Preprocessor &PP)
CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
void emit()
Emit the coverage mapping data for a translation unit.
CodeGenModule & getCodeGenModule()
Return an interface into CodeGenModule.
unsigned getFileID(FileEntryRef File)
Return the coverage mapping translation unit file id for the given file.
Expr * getOperand() const
Retrieve the operand of the 'co_return' statement.
CompoundStmt * getBody() const
Retrieve the body of the coroutine as written.
Expr * getOperand() const
Stores additional source code information like skipped ranges which is required by the coverage mappi...
void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override
Hook called when a source range is skipped.
void updateNextTokLoc(SourceLocation Loc)
void AddSkippedRange(SourceRange Range, SkippedRange::Kind RangeKind)
std::vector< SkippedRange > & getSkippedRanges()
bool HandleComment(Preprocessor &PP, SourceRange Range) override
SourceLocation PrevTokLoc
void HandleEmptyline(SourceRange Range) override
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
bool isValueDependent() const
Determines whether the value of this expression depends on.
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsBooleanCondition - Return true if this is a constant which we can fold and convert to a boo...
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
SourceLocation getRParenLoc() const
SourceLocation getIfLoc() const
bool isNonNegatedConsteval() const
bool isNegatedConsteval() const
SourceLocation getRParenLoc() const
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
SourceLocation getRParenLoc() const
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
void addCommentHandler(CommentHandler *Handler)
Add the specified comment handler to the preprocessor.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
SourceManager & getSourceManager() const
void setPreprocessToken(bool Preprocess)
void setTokenWatcher(llvm::unique_function< void(const clang::Token &)> F)
Register a function that would be called on each token in the final expanded token stream.
void setEmptylineHandler(EmptylineHandler *Handler)
Set empty line handler.
Expr * getSyntacticForm()
Return the syntactic form of this expression, i.e.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
SourceLocation getFileLoc(SourceLocation Loc) const
Given Loc, if it is a macro location return the expansion location or the spelling location,...
StringRef getBufferName(SourceLocation Loc, bool *Invalid=nullptr) const
Return the filename or buffer identifier of the buffer the location is in.
bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc=nullptr) const
Tests whether the given source location represents a macro argument's expansion into the function-lik...
unsigned getSpellingColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID.
SourceLocation getLocForEndOfFile(FileID FID) const
Return the source location corresponding to the last byte of the specified file.
FileIDAndOffset getDecomposedSpellingLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
SourceLocation getIncludeLoc(FileID FID) const
Returns the include location if FID is a #include'd file otherwise it returns an invalid location.
unsigned getFileIDSize(FileID FID) const
The size of the SLocEntry that FID represents.
CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
bool isWrittenInScratchSpace(SourceLocation Loc) const
Returns whether Loc is located in a <scratch space> file.
bool isInFileID(SourceLocation Loc, FileID FID, unsigned *RelativeOffset=nullptr) const
Given a specific FileID, returns true if Loc is inside that FileID chunk and sets relative offset (of...
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file.
bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const
Returns true if the spelling locations for both SourceLocations are part of the same file buffer.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
A trivial tuple used to represent a source range.
SourceLocation getExpansionLocStart() const
bool isFunctionMacroExpansion() const
SourceLocation getExpansionLocEnd() const
const ExpansionInfo & getExpansion() const
CompoundStmt * getSubStmt()
SourceLocation getEndLoc() const LLVM_READONLY
SourceLocation getBeginLoc() const LLVM_READONLY
SourceLocation getColonLoc() const
const SwitchCase * getNextSwitchCase() const
SwitchCase * getSwitchCaseList()
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Token - This structure provides full information about a lexed token.
Expr * getSubExpr() const
SourceLocation getRParenLoc() const
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
FunctionType::ExtInfo getFunctionExtInfo(const Type &t)
cl::opt< bool > SystemHeadersCoverage
Diagnostic wrappers for TextAPI types for error reporting.
cl::opt< bool > EnableSingleByteCoverage
int const char * function
llvm::DenseMap< const Stmt *, Branch > BranchByStmt
llvm::DenseMap< const Stmt *, Decision > DecisionByStmt