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"
38 llvm::cl::desc(
"Enable single byte coverage"),
39 llvm::cl::Hidden, llvm::cl::init(
false));
43 "emptyline-comment-coverage",
44 llvm::cl::desc(
"Emit emptylines and comment lines as skipped regions (only "
45 "disable it on test)"),
46 llvm::cl::init(
true), llvm::cl::Hidden);
50 "system-headers-coverage",
51 cl::desc(
"Enable collecting coverage from system headers"), cl::init(
false),
71 if (
Tok.getKind() != clang::tok::eod)
81 PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
82 SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
84 SkippedRanges.back().Range.setEnd(Range.getEnd());
86 SkippedRanges.push_back({Range, RangeKind,
PrevTokLoc});
103 if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
104 SkippedRanges.back().NextTokLoc = Loc;
109class SourceMappingRegion {
114 std::optional<Counter> FalseCount;
117 mcdc::Parameters MCDCParams;
120 std::optional<SourceLocation> LocStart;
123 std::optional<SourceLocation> LocEnd;
134 SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart,
135 std::optional<SourceLocation> LocEnd,
136 bool GapRegion =
false)
137 : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
138 SkippedRegion(
false) {}
140 SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount,
141 mcdc::Parameters MCDCParams,
142 std::optional<SourceLocation> LocStart,
143 std::optional<SourceLocation> LocEnd,
144 bool GapRegion =
false)
145 : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams),
146 LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
147 SkippedRegion(
false) {}
149 SourceMappingRegion(mcdc::Parameters MCDCParams,
150 std::optional<SourceLocation> LocStart,
151 std::optional<SourceLocation> LocEnd)
152 : MCDCParams(MCDCParams), LocStart(LocStart), LocEnd(LocEnd),
155 const Counter &getCounter()
const {
return Count; }
157 const Counter &getFalseCounter()
const {
158 assert(FalseCount &&
"Region has no alternate counter");
162 void setCounter(Counter
C) { Count =
C; }
164 bool hasStartLoc()
const {
return LocStart.has_value(); }
166 void setStartLoc(SourceLocation Loc) { LocStart = Loc; }
168 SourceLocation getBeginLoc()
const {
169 assert(LocStart &&
"Region has no start location");
173 bool hasEndLoc()
const {
return LocEnd.has_value(); }
175 void setEndLoc(SourceLocation Loc) {
176 assert(Loc.
isValid() &&
"Setting an invalid end location");
180 SourceLocation getEndLoc()
const {
181 assert(LocEnd &&
"Region has no end location");
185 bool isGap()
const {
return GapRegion; }
187 void setGap(
bool Gap) { GapRegion = Gap; }
189 bool isSkipped()
const {
return SkippedRegion; }
191 void setSkipped(
bool Skipped) { SkippedRegion = Skipped; }
193 bool isBranch()
const {
return FalseCount.has_value(); }
195 bool isMCDCBranch()
const {
196 return std::holds_alternative<mcdc::BranchParameters>(MCDCParams);
199 const auto &getMCDCBranchParams()
const {
200 return mcdc::getParams<const mcdc::BranchParameters>(MCDCParams);
203 bool isMCDCDecision()
const {
204 return std::holds_alternative<mcdc::DecisionParameters>(MCDCParams);
207 const auto &getMCDCDecisionParams()
const {
208 return mcdc::getParams<const mcdc::DecisionParameters>(MCDCParams);
211 const mcdc::Parameters &getMCDCParams()
const {
return MCDCParams; }
213 void resetMCDCParams() { MCDCParams = mcdc::Parameters(); }
217struct SpellingRegion {
222 unsigned ColumnStart;
230 SpellingRegion(SourceManager &
SM, SourceLocation LocStart,
231 SourceLocation LocEnd) {
232 LineStart =
SM.getSpellingLineNumber(LocStart);
233 ColumnStart =
SM.getSpellingColumnNumber(LocStart);
234 LineEnd =
SM.getSpellingLineNumber(LocEnd);
235 ColumnEnd =
SM.getSpellingColumnNumber(LocEnd);
238 SpellingRegion(SourceManager &
SM, SourceMappingRegion &R)
239 : SpellingRegion(
SM,
R.getBeginLoc(),
R.getEndLoc()) {}
243 bool isInSourceOrder()
const {
244 return (LineStart < LineEnd) ||
245 (LineStart == LineEnd && ColumnStart <= ColumnEnd);
251class CoverageMappingBuilder {
253 CoverageMappingModuleGen &CVM;
255 const LangOptions &LangOpts;
259 llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
264 llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
266 std::vector<SourceMappingRegion> SourceRegions;
273 typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
276 CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &
SM,
277 const LangOptions &LangOpts)
278 : CVM(CVM),
SM(
SM), LangOpts(LangOpts) {}
281 SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
290 SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
293 return SM.getLocForStartOfFile(
SM.getFileID(Loc));
297 SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
300 SM.getFileOffset(Loc));
301 return SM.getLocForEndOfFile(
SM.getFileID(Loc));
311 std::pair<SourceLocation, std::optional<SourceLocation>>
312 getNonScratchExpansionLoc(SourceLocation Loc) {
313 std::optional<SourceLocation> EndLoc = std::nullopt;
315 SM.isWrittenInScratchSpace(
SM.getSpellingLoc(Loc))) {
316 auto ExpansionRange =
SM.getImmediateExpansionRange(Loc);
317 Loc = ExpansionRange.getBegin();
318 EndLoc = ExpansionRange.getEnd();
320 return std::make_pair(Loc, EndLoc);
326 SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc,
327 bool AcceptScratch =
true) {
329 return SM.getIncludeLoc(
SM.getFileID(Loc));
330 Loc =
SM.getImmediateExpansionRange(Loc).getBegin();
333 return getNonScratchExpansionLoc(Loc).first;
337 bool isInBuiltin(SourceLocation Loc) {
338 return SM.getBufferName(
SM.getSpellingLoc(Loc)) ==
"<built-in>";
342 bool isNestedIn(SourceLocation Loc, FileID Parent) {
344 Loc = getIncludeOrExpansionLoc(Loc);
347 }
while (!
SM.isInFileID(Loc, Parent));
352 SourceLocation getStart(
const Stmt *S) {
354 while (
SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
355 Loc =
SM.getImmediateExpansionRange(Loc).getBegin();
360 SourceLocation getEnd(
const Stmt *S) {
362 while (
SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
363 Loc =
SM.getImmediateExpansionRange(Loc).getBegin();
364 return getPreciseTokenLocEnd(Loc);
372 void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
373 FileIDMapping.clear();
375 llvm::SmallSet<FileID, 8> Visited;
376 SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
377 for (
auto &Region : SourceRegions) {
378 SourceLocation Loc = Region.getBeginLoc();
381 auto NonScratchExpansionLoc = getNonScratchExpansionLoc(Loc);
382 auto EndLoc = NonScratchExpansionLoc.second;
383 if (EndLoc.has_value()) {
384 Loc = NonScratchExpansionLoc.first;
385 Region.setStartLoc(Loc);
386 Region.setEndLoc(EndLoc.value());
394 SM.isInSystemHeader(
SM.getSpellingLoc(Loc))) {
396 auto BeginLoc =
SM.getSpellingLoc(Loc);
397 auto EndLoc =
SM.getSpellingLoc(Region.getEndLoc());
398 if (
SM.isWrittenInSameFile(BeginLoc, EndLoc)) {
399 Loc =
SM.getFileLoc(Loc);
400 Region.setStartLoc(Loc);
401 Region.setEndLoc(
SM.getFileLoc(Region.getEndLoc()));
404 if (
SM.isInSystemHeader(
SM.getSpellingLoc(Loc)))
408 FileID
File =
SM.getFileID(Loc);
409 if (!Visited.insert(
File).second)
413 for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
414 Parent.
isValid(); Parent = getIncludeOrExpansionLoc(Parent))
416 FileLocs.push_back(std::make_pair(Loc, Depth));
418 llvm::stable_sort(FileLocs, llvm::less_second());
420 for (
const auto &FL : FileLocs) {
421 SourceLocation Loc = FL.first;
422 FileID SpellingFile =
SM.getDecomposedSpellingLoc(Loc).first;
423 auto Entry =
SM.getFileEntryRefForID(SpellingFile);
427 FileIDMapping[
SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
428 Mapping.push_back(CVM.
getFileID(*Entry));
435 std::optional<unsigned> getCoverageFileID(SourceLocation Loc) {
436 auto Mapping = FileIDMapping.find(
SM.getFileID(Loc));
437 if (Mapping != FileIDMapping.end())
438 return Mapping->second.first;
447 std::optional<SpellingRegion> adjustSkippedRange(SourceManager &
SM,
448 SourceLocation LocStart,
449 SourceLocation LocEnd,
450 SourceLocation PrevTokLoc,
451 SourceLocation NextTokLoc) {
452 SpellingRegion SR{
SM, LocStart, LocEnd};
454 if (PrevTokLoc.
isValid() &&
SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
455 SR.LineStart ==
SM.getSpellingLineNumber(PrevTokLoc))
457 if (NextTokLoc.
isValid() &&
SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
458 SR.LineEnd ==
SM.getSpellingLineNumber(NextTokLoc)) {
462 if (SR.isInSourceOrder())
469 void gatherSkippedRegions() {
472 llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
473 FileLineRanges.resize(
474 FileIDMapping.size(),
475 std::make_pair(std::numeric_limits<unsigned>::max(), 0));
476 for (
const auto &R : MappingRegions) {
477 FileLineRanges[
R.FileID].first =
478 std::min(FileLineRanges[
R.FileID].first,
R.LineStart);
479 FileLineRanges[
R.FileID].second =
480 std::max(FileLineRanges[
R.FileID].second,
R.LineEnd);
484 for (
auto &I : SkippedRanges) {
485 SourceRange
Range = I.Range;
486 auto LocStart =
Range.getBegin();
487 auto LocEnd =
Range.getEnd();
488 assert(
SM.isWrittenInSameFile(LocStart, LocEnd) &&
489 "region spans multiple files");
491 auto CovFileID = getCoverageFileID(LocStart);
494 std::optional<SpellingRegion> SR;
496 SR = adjustSkippedRange(
SM, LocStart, LocEnd, I.PrevTokLoc,
498 else if (I.isPPIfElse() || I.isEmptyLine())
499 SR = {
SM, LocStart, LocEnd};
503 auto Region = CounterMappingRegion::makeSkipped(
504 *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
508 if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
509 Region.LineEnd <= FileLineRanges[*CovFileID].second)
510 MappingRegions.push_back(Region);
516 void emitSourceRegions(
const SourceRegionFilter &Filter) {
517 for (
const auto &Region : SourceRegions) {
518 assert(Region.hasEndLoc() &&
"incomplete region");
520 SourceLocation LocStart = Region.getBeginLoc();
521 assert(
SM.getFileID(LocStart).isValid() &&
"region in invalid file");
526 SM.isInSystemHeader(
SM.getSpellingLoc(LocStart))) {
527 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
528 "Don't suppress the condition in system headers");
532 auto CovFileID = getCoverageFileID(LocStart);
535 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
536 "Don't suppress the condition in non-file regions");
540 SourceLocation LocEnd = Region.getEndLoc();
541 assert(
SM.isWrittenInSameFile(LocStart, LocEnd) &&
542 "region spans multiple files");
548 if (
Filter.count(std::make_pair(LocStart, LocEnd))) {
549 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
550 "Don't suppress the condition");
555 SpellingRegion SR{
SM, LocStart, LocEnd};
556 assert(SR.isInSourceOrder() &&
"region start and end out of order");
558 if (Region.isGap()) {
559 MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
560 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
561 SR.LineEnd, SR.ColumnEnd));
562 }
else if (Region.isSkipped()) {
563 MappingRegions.push_back(CounterMappingRegion::makeSkipped(
564 *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd,
566 }
else if (Region.isBranch()) {
567 MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
568 Region.getCounter(), Region.getFalseCounter(), *CovFileID,
569 SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd,
570 Region.getMCDCParams()));
571 }
else if (Region.isMCDCDecision()) {
572 MappingRegions.push_back(CounterMappingRegion::makeDecisionRegion(
573 Region.getMCDCDecisionParams(), *CovFileID, SR.LineStart,
574 SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
576 MappingRegions.push_back(CounterMappingRegion::makeRegion(
577 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
578 SR.LineEnd, SR.ColumnEnd));
584 SourceRegionFilter emitExpansionRegions() {
585 SourceRegionFilter
Filter;
586 for (
const auto &FM : FileIDMapping) {
587 SourceLocation ExpandedLoc = FM.second.second;
588 SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc,
false);
592 auto ParentFileID = getCoverageFileID(ParentLoc);
595 auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
596 assert(ExpandedFileID &&
"expansion in uncovered file");
598 SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
599 assert(
SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
600 "region spans multiple files");
601 Filter.insert(std::make_pair(ParentLoc, LocEnd));
603 SpellingRegion SR{
SM, ParentLoc, LocEnd};
604 assert(SR.isInSourceOrder() &&
"region start and end out of order");
605 MappingRegions.push_back(CounterMappingRegion::makeExpansion(
606 *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
607 SR.LineEnd, SR.ColumnEnd));
615struct EmptyCoverageMappingBuilder :
public CoverageMappingBuilder {
616 EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &
SM,
617 const LangOptions &LangOpts)
618 : CoverageMappingBuilder(CVM,
SM, LangOpts) {}
620 void VisitDecl(
const Decl *D) {
624 SourceLocation Start = getStart(Body);
625 SourceLocation End = getEnd(Body);
626 if (!
SM.isWrittenInSameFile(Start, End)) {
629 FileID StartFileID =
SM.getFileID(Start);
630 FileID EndFileID =
SM.getFileID(End);
631 while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
632 Start = getIncludeOrExpansionLoc(Start);
634 "Declaration start location not nested within a known region");
635 StartFileID =
SM.getFileID(Start);
637 while (StartFileID != EndFileID) {
638 End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
640 "Declaration end location not nested within a known region");
641 EndFileID =
SM.getFileID(End);
644 SourceRegions.emplace_back(Counter(), Start, End);
648 void write(llvm::raw_ostream &OS) {
649 SmallVector<unsigned, 16> FileIDMapping;
650 gatherFileIDs(FileIDMapping);
651 emitSourceRegions(SourceRegionFilter());
653 if (MappingRegions.empty())
656 CoverageMappingWriter Writer(FileIDMapping, {}, MappingRegions);
669struct MCDCCoverageBuilder {
760 MCDC::State &MCDCState;
762 struct DecisionState {
764 const Expr *DecisionExpr =
nullptr;
769 mcdc::ConditionIDs CurCondIDs = {-1, -1};
772 mcdc::ConditionID NextID = 0;
777 DecisionState() =
default;
778 DecisionState(
const Expr *DecisionExpr,
bool Valid)
779 : DecisionExpr(DecisionExpr), Active(
Valid) {}
785 llvm::SmallVector<DecisionState, 2> DecisionStack;
789 llvm::DenseMap<unsigned, unsigned> DecisionEndToSince;
792 MCDCCoverageBuilder(CodeGenModule &CGM, MCDC::State &MCDCState)
793 : CGM(CGM), MCDCState(MCDCState), DecisionStack(1) {}
795 bool isActive()
const {
return DecisionStack.back().Active; }
798 void setCondID(
const Expr *
Cond, mcdc::ConditionID ID) {
801 ID, DecisionStack.back().DecisionExpr};
805 mcdc::ConditionID getCondID(
const Expr *
Cond)
const {
814 auto &getCurCondIDs() {
return DecisionStack.back().CurCondIDs; }
820 std::swap(getCurCondIDs()[
false], getCurCondIDs()[
true]);
823 void checkDecisionRootOrPush(
const Expr *E) {
826 assert(!isActive() &&
"The setinel should tell 'not Active'");
831 if (getCondID(SC) >= 0)
837 auto &StackTop = DecisionStack.emplace_back(SC, DI->second.isValid());
841 if (isActive() && getCondID(SC) < 0)
842 setCondID(SC, StackTop.NextID++);
846 assert((!isActive() || DecisionStack.back().NextID > 0) &&
847 "Should be Active and after assignments");
853 std::pair<mcdc::ConditionID, mcdc::ConditionID>
854 pushAndAssignIDs(
const BinaryOperator *E) {
858 checkDecisionRootOrPush(E);
862 auto &StackTop = DecisionStack.back();
865 mcdc::ConditionID LHSid = getCondID(E);
867 setCondID(E->
getLHS(), LHSid);
870 mcdc::ConditionID RHSid = StackTop.NextID++;
871 setCondID(E->
getRHS(), RHSid);
873 return {LHSid, RHSid};
878 unsigned getTotalConditionsAndPop(
const Expr *E) {
879 auto &StackTop = DecisionStack.back();
882 if (StackTop.DecisionExpr != E)
885 assert(StackTop.CurCondIDs[
false] == -1 &&
886 StackTop.CurCondIDs[
true] == -1 &&
887 "The root shouldn't depend on others.");
890 unsigned TotalConds = (StackTop.Active ? StackTop.NextID : 0);
891 DecisionStack.pop_back();
892 assert(!DecisionStack.empty() &&
"Sentiel?");
896 void addDecisionRegionRange(
unsigned Since,
unsigned End) {
897 DecisionEndToSince[End] = Since;
901 unsigned skipSourceRegionIndexForDecisions(
unsigned Idx) {
902 auto I = DecisionEndToSince.find(Idx);
903 assert(I != DecisionEndToSince.end());
904 assert(I->second <= Idx);
911struct CounterCoverageMappingBuilder
912 :
public CoverageMappingBuilder,
913 public ConstStmtVisitor<CounterCoverageMappingBuilder> {
915 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;
920 CounterExpressionBuilder::SubstMap MapToExpand;
923 unsigned NextCounterNum;
925 MCDC::State &MCDCState;
928 llvm::SmallVector<SourceMappingRegion> RegionStack;
932 llvm::DenseSet<const Stmt *> LeafExprSet;
935 MCDCCoverageBuilder MCDCBuilder;
937 CounterExpressionBuilder Builder;
943 SourceLocation MostRecentLocation;
946 bool HasTerminateStmt =
false;
949 Counter GapRegionCounter;
952 Counter subtractCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
954 "cannot add counters when single byte coverage mode is enabled");
955 return Builder.subtract(LHS, RHS, Simplify);
959 Counter addCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
960 return Builder.add(LHS, RHS, Simplify);
963 Counter addCounters(Counter C1, Counter C2, Counter C3,
964 bool Simplify =
true) {
965 return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
971 Counter getRegionCounter(
const Stmt *S) {
972 return Counter::getCounter(CounterMap[S].Executed);
975 struct BranchCounterPair {
992 getBranchCounterPair(
const Stmt *S, Counter ParentCnt,
993 std::optional<Counter> SkipCntForOld = std::nullopt) {
994 auto &TheMap = CounterMap[S];
995 auto ExecCnt = Counter::getCounter(TheMap.Executed);
997 BranchCounterPair Counters = {ExecCnt,
998 Builder.subtract(ParentCnt, ExecCnt)};
1002 !TheMap.Skipped.hasValue() &&
1003 "SkipCnt shouldn't be allocated but refer to an existing counter.");
1008 if (!TheMap.Skipped.hasValue())
1009 TheMap.Skipped = NextCounterNum++;
1012 Counter SkipCnt = Counter::getCounter(TheMap.Skipped);
1013 MapToExpand[SkipCnt] = Builder.subst(Counters.Skipped, MapToExpand);
1014 Counters.Skipped = SkipCnt;
1020 std::pair<Counter, Counter>
1021 getSwitchImplicitDefaultCounterPair(
const Stmt *
Cond, Counter ParentCount,
1022 Counter CaseCountSum) {
1025 unsigned Idx = NextCounterNum++;
1026 CounterMap[
Cond].Skipped = Idx;
1027 return {Counter::getZero(),
1028 Counter::getCounter(Idx)};
1035 addCounters(CaseCountSum, Counter::getZero(),
true);
1037 return {CaseCountSum, Builder.subtract(ParentCount, CaseCountSum)};
1040 bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
1041 if (OutCount == ParentCount)
1053 if (Builder.subst(Builder.subtract(OutCount, ParentCount), MapToExpand)
1064 size_t pushRegion(Counter Count,
1065 std::optional<SourceLocation> StartLoc = std::nullopt,
1066 std::optional<SourceLocation> EndLoc = std::nullopt,
1067 std::optional<Counter> FalseCount = std::nullopt,
1068 const mcdc::Parameters &BranchParams = std::monostate()) {
1070 if (StartLoc && !FalseCount) {
1071 MostRecentLocation = *StartLoc;
1076 assert((!StartLoc || StartLoc->isValid()) &&
"Start location is not valid");
1077 assert((!EndLoc || EndLoc->isValid()) &&
"End location is not valid");
1083 if (StartLoc && StartLoc->isInvalid())
1084 StartLoc = std::nullopt;
1085 if (EndLoc && EndLoc->isInvalid())
1086 EndLoc = std::nullopt;
1087 RegionStack.emplace_back(Count, FalseCount, BranchParams, StartLoc, EndLoc);
1089 return RegionStack.size() - 1;
1092 size_t pushRegion(
const mcdc::DecisionParameters &DecisionParams,
1093 std::optional<SourceLocation> StartLoc = std::nullopt,
1094 std::optional<SourceLocation> EndLoc = std::nullopt) {
1096 RegionStack.emplace_back(DecisionParams, StartLoc, EndLoc);
1098 return RegionStack.size() - 1;
1101 size_t locationDepth(SourceLocation Loc) {
1104 Loc = getIncludeOrExpansionLoc(Loc);
1114 void popRegions(
size_t ParentIndex) {
1115 assert(RegionStack.size() >= ParentIndex &&
"parent not in stack");
1116 while (RegionStack.size() > ParentIndex) {
1117 SourceMappingRegion &Region = RegionStack.back();
1118 if (Region.hasStartLoc() &&
1119 (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) {
1120 SourceLocation StartLoc = Region.getBeginLoc();
1121 SourceLocation EndLoc = Region.hasEndLoc()
1122 ? Region.getEndLoc()
1123 : RegionStack[ParentIndex].getEndLoc();
1124 bool isBranch = Region.isBranch();
1125 size_t StartDepth = locationDepth(StartLoc);
1126 size_t EndDepth = locationDepth(EndLoc);
1127 while (!
SM.isWrittenInSameFile(StartLoc, EndLoc)) {
1128 bool UnnestStart = StartDepth >= EndDepth;
1129 bool UnnestEnd = EndDepth >= StartDepth;
1137 SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
1138 assert(
SM.isWrittenInSameFile(NestedLoc, EndLoc));
1140 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
1141 SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
1144 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
1146 llvm::report_fatal_error(
1147 "File exit not handled before popRegions");
1157 SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
1158 assert(
SM.isWrittenInSameFile(StartLoc, NestedLoc));
1160 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
1161 SourceRegions.emplace_back(Region.getCounter(), StartLoc,
1164 StartLoc = getIncludeOrExpansionLoc(StartLoc);
1166 llvm::report_fatal_error(
1167 "File exit not handled before popRegions");
1171 Region.setStartLoc(StartLoc);
1172 Region.setEndLoc(EndLoc);
1175 MostRecentLocation = EndLoc;
1178 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
1179 EndLoc == getEndOfFileOrMacro(EndLoc))
1180 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
1183 assert(
SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
1184 assert(SpellingRegion(
SM, Region).isInSourceOrder());
1185 SourceRegions.push_back(Region);
1187 RegionStack.pop_back();
1193 assert(!RegionStack.empty() &&
"statement has no region");
1194 return RegionStack.back();
1199 Counter propagateCounts(Counter TopCount,
const Stmt *S,
1200 bool VisitChildren =
true) {
1201 SourceLocation StartLoc = getStart(S);
1202 SourceLocation EndLoc = getEnd(S);
1203 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
1206 Counter ExitCount =
getRegion().getCounter();
1211 if (
SM.isBeforeInTranslationUnit(StartLoc, S->
getBeginLoc()))
1212 MostRecentLocation = EndLoc;
1221 void createBranchRegion(
const Expr *
C, Counter TrueCnt, Counter FalseCnt,
1222 const mcdc::ConditionIDs &Conds = {}) {
1235 mcdc::Parameters BranchParams;
1236 mcdc::ConditionID
ID = MCDCBuilder.getCondID(
C);
1238 BranchParams = mcdc::BranchParameters{
ID, Conds};
1248 if (
Result.Val.getInt().getBoolValue())
1249 FalseCnt = Counter::getZero();
1251 TrueCnt = Counter::getZero();
1254 pushRegion(TrueCnt, getStart(
C), getEnd(
C), FalseCnt, BranchParams));
1261 void createDecisionRegion(
const Expr *
C,
1262 const mcdc::DecisionParameters &DecisionParams) {
1263 popRegions(pushRegion(DecisionParams, getStart(
C), getEnd(
C)));
1269 Counter createSwitchCaseRegion(
const SwitchCase *SC, Counter ParentCount) {
1270 Counter TrueCnt = getRegionCounter(SC);
1272 ? Counter::getZero()
1273 : subtractCounters(ParentCount, TrueCnt));
1277 popRegions(pushRegion(TrueCnt, getStart(SC), SC->
getColonLoc(), FalseCnt));
1283 bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
1284 bool isBranch =
false) {
1285 return llvm::any_of(
1286 llvm::reverse(SourceRegions), [&](
const SourceMappingRegion &Region) {
1287 return Region.getBeginLoc() == StartLoc &&
1288 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
1295 void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
1296 MostRecentLocation = EndLoc;
1303 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
1304 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
1305 MostRecentLocation,
getRegion().isBranch()))
1306 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
1314 void handleFileExit(SourceLocation NewLoc) {
1316 SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
1321 SourceLocation LCA = NewLoc;
1322 FileID ParentFile =
SM.getFileID(LCA);
1323 while (!isNestedIn(MostRecentLocation, ParentFile)) {
1324 LCA = getIncludeOrExpansionLoc(LCA);
1325 if (LCA.
isInvalid() ||
SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
1328 MostRecentLocation = NewLoc;
1331 ParentFile =
SM.getFileID(LCA);
1334 llvm::SmallSet<SourceLocation, 8> StartLocs;
1335 std::optional<Counter> ParentCounter;
1336 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
1337 if (!I.hasStartLoc())
1339 SourceLocation Loc = I.getBeginLoc();
1340 if (!isNestedIn(Loc, ParentFile)) {
1341 ParentCounter = I.getCounter();
1345 while (!
SM.isInFileID(Loc, ParentFile)) {
1349 if (StartLocs.insert(Loc).second) {
1351 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(),
1352 I.getMCDCParams(), Loc,
1353 getEndOfFileOrMacro(Loc), I.isBranch());
1355 SourceRegions.emplace_back(I.getCounter(), Loc,
1356 getEndOfFileOrMacro(Loc));
1358 Loc = getIncludeOrExpansionLoc(Loc);
1360 I.setStartLoc(getPreciseTokenLocEnd(Loc));
1363 if (ParentCounter) {
1367 SourceLocation Loc = MostRecentLocation;
1368 while (isNestedIn(Loc, ParentFile)) {
1369 SourceLocation FileStart = getStartOfFileOrMacro(Loc);
1370 if (StartLocs.insert(FileStart).second) {
1371 SourceRegions.emplace_back(*ParentCounter, FileStart,
1372 getEndOfFileOrMacro(Loc));
1373 assert(SpellingRegion(
SM, SourceRegions.back()).isInSourceOrder());
1375 Loc = getIncludeOrExpansionLoc(Loc);
1379 MostRecentLocation = NewLoc;
1383 void extendRegion(
const Stmt *S) {
1384 SourceMappingRegion &Region =
getRegion();
1385 SourceLocation StartLoc = getStart(S);
1387 handleFileExit(StartLoc);
1388 if (!Region.hasStartLoc())
1389 Region.setStartLoc(StartLoc);
1393 void terminateRegion(
const Stmt *S) {
1395 SourceMappingRegion &Region =
getRegion();
1396 SourceLocation EndLoc = getEnd(S);
1397 if (!Region.hasEndLoc())
1398 Region.setEndLoc(EndLoc);
1399 pushRegion(Counter::getZero());
1400 HasTerminateStmt =
true;
1404 std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
1405 SourceLocation BeforeLoc) {
1410 return std::nullopt;
1415 FileID FID =
SM.getFileID(AfterLoc);
1416 const SrcMgr::ExpansionInfo *EI = &
SM.getSLocEntry(FID).getExpansion();
1421 size_t StartDepth = locationDepth(AfterLoc);
1422 size_t EndDepth = locationDepth(BeforeLoc);
1423 while (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
1424 bool UnnestStart = StartDepth >= EndDepth;
1425 bool UnnestEnd = EndDepth >= StartDepth;
1427 assert(
SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1430 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1435 assert(
SM.isWrittenInSameFile(AfterLoc,
1436 getEndOfFileOrMacro(AfterLoc)));
1438 AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
1440 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1445 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1449 return std::nullopt;
1450 if (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
1451 !SpellingRegion(
SM, AfterLoc, BeforeLoc).isInSourceOrder())
1452 return std::nullopt;
1453 return {{AfterLoc, BeforeLoc}};
1457 void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
1459 if (StartLoc == EndLoc)
1461 assert(SpellingRegion(
SM, StartLoc, EndLoc).isInSourceOrder());
1462 handleFileExit(StartLoc);
1463 size_t Index = pushRegion(Count, StartLoc, EndLoc);
1465 handleFileExit(EndLoc);
1471 std::optional<SourceRange> findAreaStartingFromTo(SourceLocation StartingLoc,
1472 SourceLocation BeforeLoc) {
1475 FileID FID =
SM.getFileID(StartingLoc);
1476 const SrcMgr::ExpansionInfo *EI = &
SM.getSLocEntry(FID).getExpansion();
1481 size_t StartDepth = locationDepth(StartingLoc);
1482 size_t EndDepth = locationDepth(BeforeLoc);
1483 while (!
SM.isWrittenInSameFile(StartingLoc, BeforeLoc)) {
1484 bool UnnestStart = StartDepth >= EndDepth;
1485 bool UnnestEnd = EndDepth >= StartDepth;
1487 assert(
SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1490 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1495 assert(
SM.isWrittenInSameFile(StartingLoc,
1496 getStartOfFileOrMacro(StartingLoc)));
1498 StartingLoc = getIncludeOrExpansionLoc(StartingLoc);
1499 assert(StartingLoc.
isValid());
1506 return std::nullopt;
1507 if (!
SM.isWrittenInSameFile(StartingLoc, BeforeLoc) ||
1508 !SpellingRegion(
SM, StartingLoc, BeforeLoc).isInSourceOrder())
1509 return std::nullopt;
1510 return {{StartingLoc, BeforeLoc}};
1513 void markSkipped(SourceLocation StartLoc, SourceLocation BeforeLoc) {
1514 const auto Skipped = findAreaStartingFromTo(StartLoc, BeforeLoc);
1519 const auto NewStartLoc = Skipped->getBegin();
1520 const auto EndLoc = Skipped->getEnd();
1522 if (NewStartLoc == EndLoc)
1524 assert(SpellingRegion(
SM, NewStartLoc, EndLoc).isInSourceOrder());
1525 handleFileExit(NewStartLoc);
1526 size_t Index = pushRegion(Counter{}, NewStartLoc, EndLoc);
1528 handleFileExit(EndLoc);
1533 struct BreakContinue {
1535 Counter ContinueCount;
1537 SmallVector<BreakContinue, 8> BreakContinueStack;
1539 CounterCoverageMappingBuilder(
1540 CoverageMappingModuleGen &CVM,
1541 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,
1542 MCDC::State &MCDCState, SourceManager &
SM,
const LangOptions &LangOpts)
1543 : CoverageMappingBuilder(CVM,
SM, LangOpts), CounterMap(CounterMap),
1544 NextCounterNum(CounterMap.size()), MCDCState(MCDCState),
1545 MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {}
1548 void write(llvm::raw_ostream &OS) {
1549 llvm::SmallVector<unsigned, 8> VirtualFileMapping;
1550 gatherFileIDs(VirtualFileMapping);
1551 SourceRegionFilter
Filter = emitExpansionRegions();
1552 emitSourceRegions(Filter);
1553 gatherSkippedRegions();
1555 if (MappingRegions.empty())
1558 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
1563 void VisitStmt(
const Stmt *S) {
1566 const Stmt *LastStmt =
nullptr;
1567 bool SaveTerminateStmt = HasTerminateStmt;
1568 HasTerminateStmt =
false;
1569 GapRegionCounter = Counter::getZero();
1570 for (
const Stmt *Child : S->
children())
1574 if (LastStmt && HasTerminateStmt) {
1575 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
1577 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
1579 SaveTerminateStmt =
true;
1580 HasTerminateStmt =
false;
1585 if (SaveTerminateStmt)
1586 HasTerminateStmt =
true;
1587 handleFileExit(getEnd(S));
1590 void VisitStmtExpr(
const StmtExpr *E) {
1595 HasTerminateStmt =
false;
1598 void VisitDecl(
const Decl *D) {
1604 SM.isInSystemHeader(
SM.getSpellingLoc(getStart(Body))))
1611 Counter BodyCounter = getRegionCounter(Body);
1613 if (
auto *
Method = dyn_cast<CXXMethodDecl>(D))
1615 if (
auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
1619 if (getStart(
Init).isValid() && getEnd(
Init).isValid())
1620 propagateCounts(BodyCounter,
Init);
1625 propagateCounts(BodyCounter, Body,
1627 assert(RegionStack.empty() &&
"Regions entered but never exited");
1630 void VisitReturnStmt(
const ReturnStmt *S) {
1637 void VisitCoroutineBodyStmt(
const CoroutineBodyStmt *S) {
1642 void VisitCoreturnStmt(
const CoreturnStmt *S) {
1649 void VisitCoroutineSuspendExpr(
const CoroutineSuspendExpr *E) {
1653 void VisitCXXThrowExpr(
const CXXThrowExpr *E) {
1660 void VisitGotoStmt(
const GotoStmt *S) { terminateRegion(S); }
1662 void VisitLabelStmt(
const LabelStmt *S) {
1663 Counter LabelCount = getRegionCounter(S);
1664 SourceLocation Start = getStart(S);
1666 handleFileExit(Start);
1667 pushRegion(LabelCount, Start);
1671 void VisitBreakStmt(
const BreakStmt *S) {
1672 assert(!BreakContinueStack.empty() &&
"break not in a loop or switch!");
1673 BreakContinueStack.back().BreakCount = addCounters(
1674 BreakContinueStack.back().BreakCount,
getRegion().getCounter());
1680 void VisitContinueStmt(
const ContinueStmt *S) {
1681 assert(!BreakContinueStack.empty() &&
"continue stmt not in a loop!");
1682 BreakContinueStack.back().ContinueCount = addCounters(
1683 BreakContinueStack.back().ContinueCount,
getRegion().getCounter());
1687 void VisitCallExpr(
const CallExpr *E) {
1697 void VisitWhileStmt(
const WhileStmt *S) {
1700 Counter ParentCount =
getRegion().getCounter();
1701 Counter BodyCount = getRegionCounter(S);
1704 BreakContinueStack.push_back(BreakContinue());
1706 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1707 BreakContinue BC = BreakContinueStack.pop_back_val();
1709 bool BodyHasTerminateStmt = HasTerminateStmt;
1710 HasTerminateStmt =
false;
1714 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1715 auto BranchCount = getBranchCounterPair(S, CondCount);
1716 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1718 propagateCounts(CondCount, S->
getCond());
1719 adjustForOutOfOrderTraversal(getEnd(S));
1724 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1726 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1727 if (!IsCounterEqual(OutCount, ParentCount)) {
1728 pushRegion(OutCount);
1729 GapRegionCounter = OutCount;
1730 if (BodyHasTerminateStmt)
1731 HasTerminateStmt =
true;
1735 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1738 void VisitDoStmt(
const DoStmt *S) {
1741 Counter ParentCount =
getRegion().getCounter();
1742 Counter BodyCount = getRegionCounter(S);
1744 BreakContinueStack.push_back(BreakContinue());
1747 Counter BackedgeCount =
1748 propagateCounts(addCounters(ParentCount, BodyCount), S->
getBody());
1750 BreakContinue BC = BreakContinueStack.pop_back_val();
1752 bool BodyHasTerminateStmt = HasTerminateStmt;
1753 HasTerminateStmt =
false;
1755 Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
1756 auto BranchCount = getBranchCounterPair(S, CondCount);
1757 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1759 propagateCounts(CondCount, S->
getCond());
1761 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1762 if (!IsCounterEqual(OutCount, ParentCount)) {
1763 pushRegion(OutCount);
1764 GapRegionCounter = OutCount;
1765 if (BodyHasTerminateStmt)
1766 HasTerminateStmt =
true;
1770 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1773 void VisitForStmt(
const ForStmt *S) {
1778 Counter ParentCount =
getRegion().getCounter();
1779 Counter BodyCount = getRegionCounter(S);
1783 BreakContinueStack.emplace_back();
1786 BreakContinueStack.emplace_back();
1788 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1789 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1791 bool BodyHasTerminateStmt = HasTerminateStmt;
1792 HasTerminateStmt =
false;
1796 BreakContinue IncrementBC;
1797 if (
const Stmt *Inc = S->
getInc()) {
1798 propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
1799 IncrementBC = BreakContinueStack.pop_back_val();
1803 Counter CondCount = addCounters(
1804 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1805 IncrementBC.ContinueCount);
1806 auto BranchCount = getBranchCounterPair(S, CondCount);
1807 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1810 propagateCounts(CondCount,
Cond);
1811 adjustForOutOfOrderTraversal(getEnd(S));
1817 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1819 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1820 BranchCount.Skipped);
1821 if (!IsCounterEqual(OutCount, ParentCount)) {
1822 pushRegion(OutCount);
1823 GapRegionCounter = OutCount;
1824 if (BodyHasTerminateStmt)
1825 HasTerminateStmt =
true;
1829 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1832 void VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
1839 Counter ParentCount =
getRegion().getCounter();
1840 Counter BodyCount = getRegionCounter(S);
1842 BreakContinueStack.push_back(BreakContinue());
1844 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1845 BreakContinue BC = BreakContinueStack.pop_back_val();
1847 bool BodyHasTerminateStmt = HasTerminateStmt;
1848 HasTerminateStmt =
false;
1853 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1856 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1857 auto BranchCount = getBranchCounterPair(S, LoopCount);
1858 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1860 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1861 if (!IsCounterEqual(OutCount, ParentCount)) {
1862 pushRegion(OutCount);
1863 GapRegionCounter = OutCount;
1864 if (BodyHasTerminateStmt)
1865 HasTerminateStmt =
true;
1869 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1872 void VisitObjCForCollectionStmt(
const ObjCForCollectionStmt *S) {
1876 Counter ParentCount =
getRegion().getCounter();
1877 Counter BodyCount = getRegionCounter(S);
1879 BreakContinueStack.push_back(BreakContinue());
1881 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1882 BreakContinue BC = BreakContinueStack.pop_back_val();
1887 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1890 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1891 auto BranchCount = getBranchCounterPair(S, LoopCount);
1892 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1893 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1894 if (!IsCounterEqual(OutCount, ParentCount)) {
1895 pushRegion(OutCount);
1896 GapRegionCounter = OutCount;
1900 void VisitSwitchStmt(
const SwitchStmt *S) {
1906 BreakContinueStack.push_back(BreakContinue());
1908 const Stmt *Body = S->
getBody();
1910 if (
const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1911 if (!CS->body_empty()) {
1915 size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1920 for (
size_t i = RegionStack.size(); i != Index; --i) {
1921 if (!RegionStack[i - 1].hasEndLoc())
1922 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1928 propagateCounts(Counter::getZero(), Body);
1929 BreakContinue BC = BreakContinueStack.pop_back_val();
1931 if (!BreakContinueStack.empty())
1932 BreakContinueStack.back().ContinueCount = addCounters(
1933 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1935 Counter ParentCount =
getRegion().getCounter();
1936 Counter ExitCount = getRegionCounter(S);
1937 SourceLocation ExitLoc = getEnd(S);
1938 pushRegion(ExitCount);
1939 GapRegionCounter = ExitCount;
1943 MostRecentLocation = getStart(S);
1944 handleFileExit(ExitLoc);
1948 Counter CaseCountSum;
1949 bool HasDefaultCase =
false;
1953 auto CaseCount = createSwitchCaseRegion(Case, ParentCount);
1954 CaseCountSum = addCounters(CaseCountSum, CaseCount,
false);
1959 if (!HasDefaultCase) {
1960 auto Counters = getSwitchImplicitDefaultCounterPair(
1961 S->
getCond(), ParentCount, CaseCountSum);
1962 createBranchRegion(S->
getCond(), Counters.first, Counters.second);
1966 void VisitSwitchCase(
const SwitchCase *S) {
1969 SourceMappingRegion &Parent =
getRegion();
1970 Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
1974 if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
1975 Parent.setCounter(Count);
1977 pushRegion(Count, getStart(S));
1979 GapRegionCounter = Count;
1981 if (
const auto *CS = dyn_cast<CaseStmt>(S)) {
1982 Visit(CS->getLHS());
1983 if (
const Expr *RHS = CS->getRHS())
1989 void coverIfConsteval(
const IfStmt *S) {
1992 const auto *Then = S->
getThen();
1993 const auto *Else = S->
getElse();
1998 const Counter ParentCount =
getRegion().getCounter();
2004 markSkipped(S->
getIfLoc(), getStart(Then));
2005 propagateCounts(ParentCount, Then);
2009 markSkipped(getEnd(Then), getEnd(Else));
2014 markSkipped(S->
getIfLoc(), Else ? getStart(Else) : getEnd(Then));
2017 propagateCounts(ParentCount, Else);
2021 void coverIfConstexpr(
const IfStmt *S) {
2034 const Counter ParentCount =
getRegion().getCounter();
2037 SourceLocation startOfSkipped = S->
getIfLoc();
2040 const auto start = getStart(
Init);
2041 const auto end = getEnd(
Init);
2045 if (start.isValid() && end.isValid()) {
2046 markSkipped(startOfSkipped, start);
2047 propagateCounts(ParentCount,
Init);
2048 startOfSkipped = getEnd(
Init);
2052 const auto *Then = S->
getThen();
2053 const auto *Else = S->
getElse();
2057 markSkipped(startOfSkipped, getStart(Then));
2058 propagateCounts(ParentCount, Then);
2062 markSkipped(getEnd(Then), getEnd(Else));
2065 markSkipped(startOfSkipped, Else ? getStart(Else) : getEnd(Then));
2068 propagateCounts(ParentCount, Else);
2072 void VisitIfStmt(
const IfStmt *S) {
2076 return coverIfConsteval(S);
2078 return coverIfConstexpr(S);
2088 Counter ParentCount =
getRegion().getCounter();
2089 auto [ThenCount, ElseCount] = getBranchCounterPair(S, ParentCount);
2093 propagateCounts(ParentCount, S->
getCond());
2096 std::optional<SourceRange> Gap =
2099 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
2102 Counter OutCount = propagateCounts(ThenCount, S->
getThen());
2104 if (
const Stmt *Else = S->
getElse()) {
2105 bool ThenHasTerminateStmt = HasTerminateStmt;
2106 HasTerminateStmt =
false;
2108 std::optional<SourceRange> Gap =
2109 findGapAreaBetween(getEnd(S->
getThen()), getStart(Else));
2111 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
2114 OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
2116 if (ThenHasTerminateStmt)
2117 HasTerminateStmt =
true;
2119 OutCount = addCounters(OutCount, ElseCount);
2121 if (!IsCounterEqual(OutCount, ParentCount)) {
2122 pushRegion(OutCount);
2123 GapRegionCounter = OutCount;
2127 createBranchRegion(S->
getCond(), ThenCount, ElseCount);
2130 void VisitCXXTryStmt(
const CXXTryStmt *S) {
2135 Counter ParentCount =
getRegion().getCounter();
2141 Counter ExitCount = getRegionCounter(S);
2142 pushRegion(ExitCount);
2145 void VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2149 void VisitAbstractConditionalOperator(
const AbstractConditionalOperator *E) {
2152 Counter ParentCount =
getRegion().getCounter();
2153 auto [TrueCount, FalseCount] = getBranchCounterPair(E, ParentCount);
2156 if (
const auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) {
2157 propagateCounts(ParentCount, BCO->getCommon());
2158 OutCount = TrueCount;
2160 propagateCounts(ParentCount, E->
getCond());
2165 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
2168 OutCount = propagateCounts(TrueCount, E->
getTrueExpr());
2173 addCounters(OutCount, propagateCounts(FalseCount, E->
getFalseExpr()));
2175 if (!IsCounterEqual(OutCount, ParentCount)) {
2176 pushRegion(OutCount);
2177 GapRegionCounter = OutCount;
2181 createBranchRegion(E->
getCond(), TrueCount, FalseCount);
2184 inline unsigned findMCDCBranchesInSourceRegion(
2185 unsigned Since,
std::function<
void(SourceMappingRegion &SR)> CB) {
2186 unsigned I = SourceRegions.size() - 1;
2188 while (I >= Since) {
2189 auto &SR = SourceRegions[I];
2190 if (SR.isMCDCDecision()) {
2192 I = MCDCBuilder.skipSourceRegionIndexForDecisions(I);
2193 }
else if (SR.isMCDCBranch()) {
2205 void createOrCancelDecision(
const Expr *E,
unsigned Since) {
2207 auto NumConds = MCDCBuilder.getTotalConditionsAndPop(SC);
2212 llvm::SmallVector<mcdc::ConditionIDs> CondIDs(NumConds);
2213 findMCDCBranchesInSourceRegion(Since, [&](
const SourceMappingRegion &SR) {
2214 auto [
ID, Conds] = SR.getMCDCBranchParams();
2215 CondIDs[
ID] = Conds;
2219 mcdc::TVIdxBuilder Builder(CondIDs);
2220 unsigned NumTVs = Builder.NumTestVectors;
2222 assert(MaxTVs < mcdc::TVIdxBuilder::HardMaxTVs);
2224 if (NumTVs > MaxTVs) {
2226 cancelDecision(SC, Since, NumTVs, MaxTVs, NumConds);
2233 std::move(Builder.Indices));
2235 auto DecisionParams = mcdc::DecisionParameters{
2241 createDecisionRegion(E, DecisionParams);
2244 assert(SourceRegions.back().isMCDCDecision());
2245 MCDCBuilder.addDecisionRegionRange(Since, SourceRegions.size() - 1);
2249 void cancelDecision(
const Expr *Decision,
unsigned Since,
int NumTVs,
2250 int MaxTVs,
unsigned NumConds) {
2252 Diag.Report(Decision->getBeginLoc(), diag::warn_pgo_test_vector_limit)
2253 << NumTVs << MaxTVs;
2256 unsigned FoundCount = findMCDCBranchesInSourceRegion(
2257 Since, [](SourceMappingRegion &SR) { SR.resetMCDCParams(); });
2258 assert(FoundCount == NumConds &&
2259 "Didn't find all MCDCBranches to be restored");
2267 if (II->second.DecisionStmt == Decision)
2274 bool isExprInSystemHeader(
const BinaryOperator *E)
const {
2281 void VisitUnaryLNot(
const UnaryOperator *E) {
2282 MCDCBuilder.swapConds();
2284 MCDCBuilder.swapConds();
2287 void VisitBinLAnd(
const BinaryOperator *E) {
2288 if (isExprInSystemHeader(E)) {
2289 LeafExprSet.insert(E);
2293 unsigned SourceRegionsSince = SourceRegions.size();
2296 auto [_, RHSid] = MCDCBuilder.pushAndAssignIDs(E);
2299 auto &CurCondIDs = MCDCBuilder.getCurCondIDs();
2300 auto DecisionRHS = CurCondIDs;
2302 CurCondIDs[
true] = RHSid;
2303 auto DecisionLHS = CurCondIDs;
2305 extendRegion(E->
getLHS());
2307 handleFileExit(getEnd(E->
getLHS()));
2312 MCDCBuilder.getCurCondIDs();
2313 CurCondIDs[
true] = DecisionRHS[
true];
2314 assert(CurCondIDs == DecisionRHS);
2318 findGapAreaBetween(getEnd(E->
getLHS()), getStart(E->
getRHS()))) {
2319 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));
2323 extendRegion(E->
getRHS());
2324 propagateCounts(getRegionCounter(E), E->
getRHS());
2327 Counter ParentCnt =
getRegion().getCounter();
2330 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2333 auto [RHSTrueCnt, RHSExitCnt] =
2334 getBranchCounterPair(E->
getRHS(), RHSExecCnt);
2337 createBranchRegion(E->
getLHS(), RHSExecCnt, LHSExitCnt, DecisionLHS);
2340 createBranchRegion(E->
getRHS(), RHSTrueCnt, RHSExitCnt, DecisionRHS);
2343 createOrCancelDecision(E, SourceRegionsSince);
2347 bool shouldVisitRHS(
const Expr *LHS) {
2348 bool LHSIsTrue =
false;
2349 bool LHSIsConst =
false;
2353 return !LHSIsConst || (LHSIsConst && !LHSIsTrue);
2356 void VisitBinLOr(
const BinaryOperator *E) {
2357 if (isExprInSystemHeader(E)) {
2358 LeafExprSet.insert(E);
2362 unsigned SourceRegionsSince = SourceRegions.size();
2365 auto [_, RHSid] = MCDCBuilder.pushAndAssignIDs(E);
2368 auto &CurCondIDs = MCDCBuilder.getCurCondIDs();
2369 auto DecisionRHS = CurCondIDs;
2370 CurCondIDs[
false] = RHSid;
2371 auto DecisionLHS = CurCondIDs;
2373 extendRegion(E->
getLHS());
2374 Counter OutCount = propagateCounts(
getRegion().getCounter(), E->
getLHS());
2375 handleFileExit(getEnd(E->
getLHS()));
2380 MCDCBuilder.getCurCondIDs();
2381 CurCondIDs[
false] = DecisionRHS[
false];
2382 assert(CurCondIDs == DecisionRHS);
2386 findGapAreaBetween(getEnd(E->
getLHS()), getStart(E->
getRHS()))) {
2387 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));
2391 extendRegion(E->
getRHS());
2392 propagateCounts(getRegionCounter(E), E->
getRHS());
2395 Counter ParentCnt =
getRegion().getCounter();
2398 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2401 auto [RHSFalseCnt, RHSExitCnt] =
2402 getBranchCounterPair(E->
getRHS(), RHSExecCnt);
2404 if (!shouldVisitRHS(E->
getLHS())) {
2405 GapRegionCounter = OutCount;
2409 createBranchRegion(E->
getLHS(), LHSExitCnt, RHSExecCnt, DecisionLHS);
2412 createBranchRegion(E->
getRHS(), RHSExitCnt, RHSFalseCnt, DecisionRHS);
2415 createOrCancelDecision(E, SourceRegionsSince);
2423 void VisitArrayInitLoopExpr(
const ArrayInitLoopExpr *AILE) {
2427 void VisitPseudoObjectExpr(
const PseudoObjectExpr *POE) {
2432 void VisitOpaqueValueExpr(
const OpaqueValueExpr* OVE) {
2440static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
2443 OS << FunctionName <<
":\n";
2444 CounterMappingContext Ctx(Expressions);
2445 for (
const auto &R : Regions) {
2448 case CounterMappingRegion::CodeRegion:
2450 case CounterMappingRegion::ExpansionRegion:
2453 case CounterMappingRegion::SkippedRegion:
2456 case CounterMappingRegion::GapRegion:
2459 case CounterMappingRegion::BranchRegion:
2460 case CounterMappingRegion::MCDCBranchRegion:
2463 case CounterMappingRegion::MCDCDecisionRegion:
2468 OS <<
"File " << R.FileID <<
", " << R.LineStart <<
":" << R.ColumnStart
2469 <<
" -> " << R.LineEnd <<
":" << R.ColumnEnd <<
" = ";
2471 if (
const auto *DecisionParams =
2472 std::get_if<mcdc::DecisionParameters>(&R.MCDCParams)) {
2473 OS <<
"M:" << DecisionParams->BitmapIdx;
2474 OS <<
", C:" << DecisionParams->NumConditions;
2476 Ctx.dump(R.Count, OS);
2480 Ctx.dump(R.FalseCount, OS);
2484 if (
const auto *BranchParams =
2485 std::get_if<mcdc::BranchParameters>(&R.MCDCParams)) {
2486 OS <<
" [" << BranchParams->ID + 1 <<
","
2487 << BranchParams->Conds[
true] + 1;
2488 OS <<
"," << BranchParams->Conds[
false] + 1 <<
"] ";
2491 if (R.Kind == CounterMappingRegion::ExpansionRegion)
2492 OS <<
" (Expanded file = " << R.ExpandedFileID <<
")";
2499 : CGM(CGM), SourceInfo(SourceInfo) {}
2501std::string CoverageMappingModuleGen::getCurrentDirname() {
2505std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
2507 llvm::sys::path::remove_dots(Path,
true);
2512 for (
const auto &[From, To] :
2514 if (llvm::sys::path::replace_path_prefix(Path, From, To))
2517 return Path.str().str();
2521 llvm::InstrProfSectKind SK) {
2522 return llvm::getInstrProfSectionName(
2526void CoverageMappingModuleGen::emitFunctionMappingRecord(
2527 const FunctionInfo &Info, uint64_t FilenamesRef) {
2528 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
2531 std::string FuncRecordName =
"__covrec_" + llvm::utohexstr(Info.NameHash);
2538 FuncRecordName +=
"u";
2541 const uint64_t NameHash = Info.NameHash;
2542 const uint64_t FuncHash = Info.FuncHash;
2543 const std::string &CoverageMapping = Info.CoverageMapping;
2544#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
2545 llvm::Type *FunctionRecordTypes[] = {
2546#include "llvm/ProfileData/InstrProfData.inc"
2548 auto *FunctionRecordTy =
2549 llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes),
2553#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
2554 llvm::Constant *FunctionRecordVals[] = {
2555 #include "llvm/ProfileData/InstrProfData.inc"
2557 auto *FuncRecordConstant =
2558 llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals));
2561 auto *FuncRecord =
new llvm::GlobalVariable(
2562 CGM.getModule(), FunctionRecordTy,
true,
2563 llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
2565 FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
2567 FuncRecord->setAlignment(llvm::Align(8));
2568 if (CGM.supportsCOMDAT())
2569 FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
2572 CGM.addUsedGlobal(FuncRecord);
2576 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
2577 const std::string &CoverageMapping,
bool IsUsed) {
2578 const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
2579 FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
2582 FunctionNames.push_back(NamePtr);
2584 if (CGM.getCodeGenOpts().DumpCoverageMapping) {
2591 std::vector<StringRef> Filenames;
2592 std::vector<CounterExpression> Expressions;
2593 std::vector<CounterMappingRegion> Regions;
2594 FilenameStrs.resize(FileEntries.size() + 1);
2595 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2596 for (
const auto &Entry : FileEntries) {
2597 auto I = Entry.second;
2598 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2601 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
2602 Expressions, Regions);
2605 dump(llvm::outs(), NameValue, Expressions, Regions);
2610 if (FunctionRecords.empty())
2612 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
2613 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
2617 FilenameStrs.resize(FileEntries.size() + 1);
2619 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2620 for (
const auto &Entry : FileEntries) {
2621 auto I = Entry.second;
2622 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2625 std::string Filenames;
2627 llvm::raw_string_ostream OS(Filenames);
2628 CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
2630 auto *FilenamesVal =
2631 llvm::ConstantDataArray::getString(Ctx, Filenames,
false);
2632 const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
2635 for (
const FunctionInfo &Info : FunctionRecords)
2636 emitFunctionMappingRecord(Info, FilenamesRef);
2638 const unsigned NRecords = 0;
2639 const size_t FilenamesSize = Filenames.size();
2640 const unsigned CoverageMappingSize = 0;
2641 llvm::Type *CovDataHeaderTypes[] = {
2642#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
2643#include "llvm/ProfileData/InstrProfData.inc"
2645 auto CovDataHeaderTy =
2646 llvm::StructType::get(Ctx,
ArrayRef(CovDataHeaderTypes));
2647 llvm::Constant *CovDataHeaderVals[] = {
2648#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
2649#include "llvm/ProfileData/InstrProfData.inc"
2651 auto CovDataHeaderVal =
2652 llvm::ConstantStruct::get(CovDataHeaderTy,
ArrayRef(CovDataHeaderVals));
2655 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
2656 auto CovDataTy = llvm::StructType::get(Ctx,
ArrayRef(CovDataTypes));
2657 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
2658 auto CovDataVal = llvm::ConstantStruct::get(CovDataTy,
ArrayRef(TUDataVals));
2659 auto CovData =
new llvm::GlobalVariable(
2660 CGM.getModule(), CovDataTy,
true, llvm::GlobalValue::PrivateLinkage,
2661 CovDataVal, llvm::getCoverageMappingVarName());
2664 CovData->setAlignment(llvm::Align(8));
2667 CGM.addUsedGlobal(CovData);
2669 if (!FunctionNames.empty()) {
2670 auto AddrSpace = FunctionNames.front()->getType()->getPointerAddressSpace();
2671 auto NamesArrTy = llvm::ArrayType::get(
2672 llvm::PointerType::get(Ctx, AddrSpace), FunctionNames.size());
2673 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
2676 new llvm::GlobalVariable(CGM.getModule(), NamesArrTy,
true,
2677 llvm::GlobalValue::InternalLinkage, NamesArrVal,
2678 llvm::getCoverageUnusedNamesVarName());
2683 return FileEntries.try_emplace(
File, FileEntries.size() + 1).first->second;
2687 llvm::raw_ostream &OS) {
2688 assert(CounterMap && MCDCState);
2689 CounterCoverageMappingBuilder Walker(CVM, *CounterMap, *MCDCState, SM,
2691 Walker.VisitDecl(D);
2696 llvm::raw_ostream &OS) {
2697 EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
2698 Walker.VisitDecl(D);
Defines the Diagnostic-related interfaces.
static const MemRegion * getRegion(const CallEvent &Call, const MutexDescriptor &Descriptor, bool IsLock)
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()
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...
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
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.
A trivial tuple used to represent a source range.
SourceLocation getExpansionLocStart() const
bool isFunctionMacroExpansion() const
SourceLocation getExpansionLocEnd() 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 ...
The JSON file list parser is used to communicate input to InstallAPI.
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