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());
391 auto BeginLoc =
SM.getSpellingLoc(Loc);
392 auto EndLoc =
SM.getSpellingLoc(Region.getEndLoc());
393 if (
SM.isWrittenInSameFile(BeginLoc, EndLoc)) {
394 Loc =
SM.getFileLoc(Loc);
395 Region.setStartLoc(Loc);
396 Region.setEndLoc(
SM.getFileLoc(Region.getEndLoc()));
400 FileID
File =
SM.getFileID(Loc);
401 if (!Visited.insert(
File).second)
405 !
SM.isInSystemHeader(
SM.getSpellingLoc(Loc)));
408 for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
409 Parent.
isValid(); Parent = getIncludeOrExpansionLoc(Parent))
411 FileLocs.push_back(std::make_pair(Loc, Depth));
413 llvm::stable_sort(FileLocs, llvm::less_second());
415 for (
const auto &FL : FileLocs) {
416 SourceLocation Loc = FL.first;
417 FileID SpellingFile =
SM.getDecomposedSpellingLoc(Loc).first;
418 auto Entry =
SM.getFileEntryRefForID(SpellingFile);
422 FileIDMapping[
SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
423 Mapping.push_back(CVM.
getFileID(*Entry));
430 std::optional<unsigned> getCoverageFileID(SourceLocation Loc) {
431 auto Mapping = FileIDMapping.find(
SM.getFileID(Loc));
432 if (Mapping != FileIDMapping.end())
433 return Mapping->second.first;
442 std::optional<SpellingRegion> adjustSkippedRange(SourceManager &
SM,
443 SourceLocation LocStart,
444 SourceLocation LocEnd,
445 SourceLocation PrevTokLoc,
446 SourceLocation NextTokLoc) {
447 SpellingRegion SR{
SM, LocStart, LocEnd};
449 if (PrevTokLoc.
isValid() &&
SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
450 SR.LineStart ==
SM.getSpellingLineNumber(PrevTokLoc))
452 if (NextTokLoc.
isValid() &&
SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
453 SR.LineEnd ==
SM.getSpellingLineNumber(NextTokLoc)) {
457 if (SR.isInSourceOrder())
464 void gatherSkippedRegions() {
467 llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
468 FileLineRanges.resize(
469 FileIDMapping.size(),
470 std::make_pair(std::numeric_limits<unsigned>::max(), 0));
471 for (
const auto &R : MappingRegions) {
472 FileLineRanges[R.FileID].first =
473 std::min(FileLineRanges[R.FileID].first, R.LineStart);
474 FileLineRanges[R.FileID].second =
475 std::max(FileLineRanges[R.FileID].second, R.LineEnd);
479 for (
auto &I : SkippedRanges) {
480 SourceRange
Range = I.Range;
481 auto LocStart =
Range.getBegin();
482 auto LocEnd =
Range.getEnd();
483 assert(
SM.isWrittenInSameFile(LocStart, LocEnd) &&
484 "region spans multiple files");
486 auto CovFileID = getCoverageFileID(LocStart);
489 std::optional<SpellingRegion> SR;
491 SR = adjustSkippedRange(
SM, LocStart, LocEnd, I.PrevTokLoc,
493 else if (I.isPPIfElse() || I.isEmptyLine())
494 SR = {
SM, LocStart, LocEnd};
498 auto Region = CounterMappingRegion::makeSkipped(
499 *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
503 if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
504 Region.LineEnd <= FileLineRanges[*CovFileID].second)
505 MappingRegions.push_back(Region);
511 void emitSourceRegions(
const SourceRegionFilter &Filter) {
512 for (
const auto &Region : SourceRegions) {
513 assert(Region.hasEndLoc() &&
"incomplete region");
515 SourceLocation LocStart = Region.getBeginLoc();
516 assert(
SM.getFileID(LocStart).isValid() &&
"region in invalid file");
521 SM.isInSystemHeader(
SM.getSpellingLoc(LocStart))) {
522 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
523 "Don't suppress the condition in system headers");
527 auto CovFileID = getCoverageFileID(LocStart);
530 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
531 "Don't suppress the condition in non-file regions");
535 SourceLocation LocEnd = Region.getEndLoc();
536 assert(
SM.isWrittenInSameFile(LocStart, LocEnd) &&
537 "region spans multiple files");
543 if (
Filter.count(std::make_pair(LocStart, LocEnd))) {
544 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
545 "Don't suppress the condition");
550 SpellingRegion SR{
SM, LocStart, LocEnd};
551 assert(SR.isInSourceOrder() &&
"region start and end out of order");
553 if (Region.isGap()) {
554 MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
555 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
556 SR.LineEnd, SR.ColumnEnd));
557 }
else if (Region.isSkipped()) {
558 MappingRegions.push_back(CounterMappingRegion::makeSkipped(
559 *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd,
561 }
else if (Region.isBranch()) {
562 MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
563 Region.getCounter(), Region.getFalseCounter(), *CovFileID,
564 SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd,
565 Region.getMCDCParams()));
566 }
else if (Region.isMCDCDecision()) {
567 MappingRegions.push_back(CounterMappingRegion::makeDecisionRegion(
568 Region.getMCDCDecisionParams(), *CovFileID, SR.LineStart,
569 SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
571 MappingRegions.push_back(CounterMappingRegion::makeRegion(
572 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
573 SR.LineEnd, SR.ColumnEnd));
579 SourceRegionFilter emitExpansionRegions() {
580 SourceRegionFilter
Filter;
581 for (
const auto &FM : FileIDMapping) {
582 SourceLocation ExpandedLoc = FM.second.second;
583 SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc,
false);
587 auto ParentFileID = getCoverageFileID(ParentLoc);
590 auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
591 assert(ExpandedFileID &&
"expansion in uncovered file");
593 SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
594 assert(
SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
595 "region spans multiple files");
596 Filter.insert(std::make_pair(ParentLoc, LocEnd));
598 SpellingRegion SR{
SM, ParentLoc, LocEnd};
599 assert(SR.isInSourceOrder() &&
"region start and end out of order");
600 MappingRegions.push_back(CounterMappingRegion::makeExpansion(
601 *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
602 SR.LineEnd, SR.ColumnEnd));
610struct EmptyCoverageMappingBuilder :
public CoverageMappingBuilder {
611 EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &
SM,
612 const LangOptions &LangOpts)
613 : CoverageMappingBuilder(CVM,
SM, LangOpts) {}
615 void VisitDecl(
const Decl *D) {
619 SourceLocation Start = getStart(Body);
620 SourceLocation End = getEnd(Body);
621 if (!
SM.isWrittenInSameFile(Start, End)) {
624 FileID StartFileID =
SM.getFileID(Start);
625 FileID EndFileID =
SM.getFileID(End);
626 while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
627 Start = getIncludeOrExpansionLoc(Start);
629 "Declaration start location not nested within a known region");
630 StartFileID =
SM.getFileID(Start);
632 while (StartFileID != EndFileID) {
633 End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
635 "Declaration end location not nested within a known region");
636 EndFileID =
SM.getFileID(End);
639 SourceRegions.emplace_back(Counter(), Start, End);
643 void write(llvm::raw_ostream &OS) {
644 SmallVector<unsigned, 16> FileIDMapping;
645 gatherFileIDs(FileIDMapping);
646 emitSourceRegions(SourceRegionFilter());
648 if (MappingRegions.empty())
651 CoverageMappingWriter Writer(FileIDMapping, {}, MappingRegions);
664struct MCDCCoverageBuilder {
755 MCDC::State &MCDCState;
757 struct DecisionState {
759 const Expr *DecisionExpr =
nullptr;
764 mcdc::ConditionIDs CurCondIDs = {-1, -1};
767 mcdc::ConditionID NextID = 0;
772 DecisionState() =
default;
773 DecisionState(
const Expr *DecisionExpr,
bool Valid)
774 : DecisionExpr(DecisionExpr), Active(
Valid) {}
780 llvm::SmallVector<DecisionState, 2> DecisionStack;
784 llvm::DenseMap<unsigned, unsigned> DecisionEndToSince;
787 MCDCCoverageBuilder(CodeGenModule &CGM, MCDC::State &MCDCState)
788 : CGM(CGM), MCDCState(MCDCState), DecisionStack(1) {}
790 bool isActive()
const {
return DecisionStack.back().Active; }
793 void setCondID(
const Expr *
Cond, mcdc::ConditionID ID) {
796 ID, DecisionStack.back().DecisionExpr};
800 mcdc::ConditionID getCondID(
const Expr *
Cond)
const {
809 auto &getCurCondIDs() {
return DecisionStack.back().CurCondIDs; }
815 std::swap(getCurCondIDs()[
false], getCurCondIDs()[
true]);
818 void checkDecisionRootOrPush(
const Expr *E) {
821 assert(!isActive() &&
"The setinel should tell 'not Active'");
826 if (getCondID(SC) >= 0)
832 auto &StackTop = DecisionStack.emplace_back(SC, DI->second.isValid());
836 if (isActive() && getCondID(SC) < 0)
837 setCondID(SC, StackTop.NextID++);
841 assert((!isActive() || DecisionStack.back().NextID > 0) &&
842 "Should be Active and after assignments");
848 std::pair<mcdc::ConditionID, mcdc::ConditionID>
849 pushAndAssignIDs(
const BinaryOperator *E) {
853 checkDecisionRootOrPush(E);
857 auto &StackTop = DecisionStack.back();
860 mcdc::ConditionID LHSid = getCondID(E);
862 setCondID(E->
getLHS(), LHSid);
865 mcdc::ConditionID RHSid = StackTop.NextID++;
866 setCondID(E->
getRHS(), RHSid);
868 return {LHSid, RHSid};
873 unsigned getTotalConditionsAndPop(
const Expr *E) {
874 auto &StackTop = DecisionStack.back();
877 if (StackTop.DecisionExpr != E)
880 assert(StackTop.CurCondIDs[
false] == -1 &&
881 StackTop.CurCondIDs[
true] == -1 &&
882 "The root shouldn't depend on others.");
885 unsigned TotalConds = (StackTop.Active ? StackTop.NextID : 0);
886 DecisionStack.pop_back();
887 assert(!DecisionStack.empty() &&
"Sentiel?");
891 void addDecisionRegionRange(
unsigned Since,
unsigned End) {
892 DecisionEndToSince[End] = Since;
896 unsigned skipSourceRegionIndexForDecisions(
unsigned Idx) {
897 auto I = DecisionEndToSince.find(Idx);
898 assert(I != DecisionEndToSince.end());
899 assert(I->second <= Idx);
906struct CounterCoverageMappingBuilder
907 :
public CoverageMappingBuilder,
908 public ConstStmtVisitor<CounterCoverageMappingBuilder> {
910 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;
915 CounterExpressionBuilder::SubstMap MapToExpand;
918 unsigned NextCounterNum;
920 MCDC::State &MCDCState;
923 llvm::SmallVector<SourceMappingRegion> RegionStack;
927 llvm::DenseSet<const Stmt *> LeafExprSet;
930 MCDCCoverageBuilder MCDCBuilder;
932 CounterExpressionBuilder Builder;
938 SourceLocation MostRecentLocation;
941 bool HasTerminateStmt =
false;
944 Counter GapRegionCounter;
947 Counter subtractCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
949 "cannot add counters when single byte coverage mode is enabled");
950 return Builder.subtract(LHS, RHS, Simplify);
954 Counter addCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
955 return Builder.add(LHS, RHS, Simplify);
958 Counter addCounters(Counter C1, Counter C2, Counter C3,
959 bool Simplify =
true) {
960 return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
966 Counter getRegionCounter(
const Stmt *S) {
967 return Counter::getCounter(CounterMap[S].Executed);
970 struct BranchCounterPair {
987 getBranchCounterPair(
const Stmt *S, Counter ParentCnt,
988 std::optional<Counter> SkipCntForOld = std::nullopt) {
989 auto &TheMap = CounterMap[S];
990 auto ExecCnt = Counter::getCounter(TheMap.Executed);
992 BranchCounterPair Counters = {ExecCnt,
993 Builder.subtract(ParentCnt, ExecCnt)};
997 !TheMap.Skipped.hasValue() &&
998 "SkipCnt shouldn't be allocated but refer to an existing counter.");
1003 if (!TheMap.Skipped.hasValue())
1004 TheMap.Skipped = NextCounterNum++;
1007 Counter SkipCnt = Counter::getCounter(TheMap.Skipped);
1008 MapToExpand[SkipCnt] = Builder.subst(Counters.Skipped, MapToExpand);
1009 Counters.Skipped = SkipCnt;
1015 std::pair<Counter, Counter>
1016 getSwitchImplicitDefaultCounterPair(
const Stmt *
Cond, Counter ParentCount,
1017 Counter CaseCountSum) {
1020 unsigned Idx = NextCounterNum++;
1021 CounterMap[
Cond].Skipped = Idx;
1022 return {Counter::getZero(),
1023 Counter::getCounter(Idx)};
1030 addCounters(CaseCountSum, Counter::getZero(),
true);
1032 return {CaseCountSum, Builder.subtract(ParentCount, CaseCountSum)};
1035 bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
1036 if (OutCount == ParentCount)
1048 if (Builder.subst(Builder.subtract(OutCount, ParentCount), MapToExpand)
1059 size_t pushRegion(Counter Count,
1060 std::optional<SourceLocation> StartLoc = std::nullopt,
1061 std::optional<SourceLocation> EndLoc = std::nullopt,
1062 std::optional<Counter> FalseCount = std::nullopt,
1063 const mcdc::Parameters &BranchParams = std::monostate()) {
1065 if (StartLoc && !FalseCount) {
1066 MostRecentLocation = *StartLoc;
1071 assert((!StartLoc || StartLoc->isValid()) &&
"Start location is not valid");
1072 assert((!EndLoc || EndLoc->isValid()) &&
"End location is not valid");
1078 if (StartLoc && StartLoc->isInvalid())
1079 StartLoc = std::nullopt;
1080 if (EndLoc && EndLoc->isInvalid())
1081 EndLoc = std::nullopt;
1082 RegionStack.emplace_back(Count, FalseCount, BranchParams, StartLoc, EndLoc);
1084 return RegionStack.size() - 1;
1087 size_t pushRegion(
const mcdc::DecisionParameters &DecisionParams,
1088 std::optional<SourceLocation> StartLoc = std::nullopt,
1089 std::optional<SourceLocation> EndLoc = std::nullopt) {
1091 RegionStack.emplace_back(DecisionParams, StartLoc, EndLoc);
1093 return RegionStack.size() - 1;
1096 size_t locationDepth(SourceLocation Loc) {
1099 Loc = getIncludeOrExpansionLoc(Loc);
1109 void popRegions(
size_t ParentIndex) {
1110 assert(RegionStack.size() >= ParentIndex &&
"parent not in stack");
1111 while (RegionStack.size() > ParentIndex) {
1112 SourceMappingRegion &Region = RegionStack.back();
1113 if (Region.hasStartLoc() &&
1114 (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) {
1115 SourceLocation StartLoc = Region.getBeginLoc();
1116 SourceLocation EndLoc = Region.hasEndLoc()
1117 ? Region.getEndLoc()
1118 : RegionStack[ParentIndex].getEndLoc();
1119 bool isBranch = Region.isBranch();
1120 size_t StartDepth = locationDepth(StartLoc);
1121 size_t EndDepth = locationDepth(EndLoc);
1122 while (!
SM.isWrittenInSameFile(StartLoc, EndLoc)) {
1123 bool UnnestStart = StartDepth >= EndDepth;
1124 bool UnnestEnd = EndDepth >= StartDepth;
1132 SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
1133 assert(
SM.isWrittenInSameFile(NestedLoc, EndLoc));
1135 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
1136 SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
1139 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
1141 llvm::report_fatal_error(
1142 "File exit not handled before popRegions");
1152 SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
1153 assert(
SM.isWrittenInSameFile(StartLoc, NestedLoc));
1155 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
1156 SourceRegions.emplace_back(Region.getCounter(), StartLoc,
1159 StartLoc = getIncludeOrExpansionLoc(StartLoc);
1161 llvm::report_fatal_error(
1162 "File exit not handled before popRegions");
1166 Region.setStartLoc(StartLoc);
1167 Region.setEndLoc(EndLoc);
1170 MostRecentLocation = EndLoc;
1173 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
1174 EndLoc == getEndOfFileOrMacro(EndLoc))
1175 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
1178 assert(
SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
1179 assert(SpellingRegion(
SM, Region).isInSourceOrder());
1180 SourceRegions.push_back(Region);
1182 RegionStack.pop_back();
1188 assert(!RegionStack.empty() &&
"statement has no region");
1189 return RegionStack.back();
1194 Counter propagateCounts(Counter TopCount,
const Stmt *S,
1195 bool VisitChildren =
true) {
1196 SourceLocation StartLoc = getStart(S);
1197 SourceLocation EndLoc = getEnd(S);
1198 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
1201 Counter ExitCount =
getRegion().getCounter();
1206 if (
SM.isBeforeInTranslationUnit(StartLoc, S->
getBeginLoc()))
1207 MostRecentLocation = EndLoc;
1216 void createBranchRegion(
const Expr *
C, Counter TrueCnt, Counter FalseCnt,
1217 const mcdc::ConditionIDs &Conds = {}) {
1230 mcdc::Parameters BranchParams;
1231 mcdc::ConditionID
ID = MCDCBuilder.getCondID(
C);
1233 BranchParams = mcdc::BranchParameters{
ID, Conds};
1243 if (
Result.Val.getInt().getBoolValue())
1244 FalseCnt = Counter::getZero();
1246 TrueCnt = Counter::getZero();
1249 pushRegion(TrueCnt, getStart(
C), getEnd(
C), FalseCnt, BranchParams));
1256 void createDecisionRegion(
const Expr *
C,
1257 const mcdc::DecisionParameters &DecisionParams) {
1258 popRegions(pushRegion(DecisionParams, getStart(
C), getEnd(
C)));
1264 Counter createSwitchCaseRegion(
const SwitchCase *SC, Counter ParentCount) {
1265 Counter TrueCnt = getRegionCounter(SC);
1267 ? Counter::getZero()
1268 : subtractCounters(ParentCount, TrueCnt));
1272 popRegions(pushRegion(TrueCnt, getStart(SC), SC->
getColonLoc(), FalseCnt));
1278 bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
1279 bool isBranch =
false) {
1280 return llvm::any_of(
1281 llvm::reverse(SourceRegions), [&](
const SourceMappingRegion &Region) {
1282 return Region.getBeginLoc() == StartLoc &&
1283 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
1290 void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
1291 MostRecentLocation = EndLoc;
1298 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
1299 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
1300 MostRecentLocation,
getRegion().isBranch()))
1301 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
1309 void handleFileExit(SourceLocation NewLoc) {
1311 SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
1316 SourceLocation LCA = NewLoc;
1317 FileID ParentFile =
SM.getFileID(LCA);
1318 while (!isNestedIn(MostRecentLocation, ParentFile)) {
1319 LCA = getIncludeOrExpansionLoc(LCA);
1320 if (LCA.
isInvalid() ||
SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
1323 MostRecentLocation = NewLoc;
1326 ParentFile =
SM.getFileID(LCA);
1329 llvm::SmallSet<SourceLocation, 8> StartLocs;
1330 std::optional<Counter> ParentCounter;
1331 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
1332 if (!I.hasStartLoc())
1334 SourceLocation Loc = I.getBeginLoc();
1335 if (!isNestedIn(Loc, ParentFile)) {
1336 ParentCounter = I.getCounter();
1340 while (!
SM.isInFileID(Loc, ParentFile)) {
1344 if (StartLocs.insert(Loc).second) {
1346 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(),
1347 I.getMCDCParams(), Loc,
1348 getEndOfFileOrMacro(Loc), I.isBranch());
1350 SourceRegions.emplace_back(I.getCounter(), Loc,
1351 getEndOfFileOrMacro(Loc));
1353 Loc = getIncludeOrExpansionLoc(Loc);
1355 I.setStartLoc(getPreciseTokenLocEnd(Loc));
1358 if (ParentCounter) {
1362 SourceLocation Loc = MostRecentLocation;
1363 while (isNestedIn(Loc, ParentFile)) {
1364 SourceLocation FileStart = getStartOfFileOrMacro(Loc);
1365 if (StartLocs.insert(FileStart).second) {
1366 SourceRegions.emplace_back(*ParentCounter, FileStart,
1367 getEndOfFileOrMacro(Loc));
1368 assert(SpellingRegion(
SM, SourceRegions.back()).isInSourceOrder());
1370 Loc = getIncludeOrExpansionLoc(Loc);
1374 MostRecentLocation = NewLoc;
1378 void extendRegion(
const Stmt *S) {
1379 SourceMappingRegion &Region =
getRegion();
1380 SourceLocation StartLoc = getStart(S);
1382 handleFileExit(StartLoc);
1383 if (!Region.hasStartLoc())
1384 Region.setStartLoc(StartLoc);
1388 void terminateRegion(
const Stmt *S) {
1390 SourceMappingRegion &Region =
getRegion();
1391 SourceLocation EndLoc = getEnd(S);
1392 if (!Region.hasEndLoc())
1393 Region.setEndLoc(EndLoc);
1394 pushRegion(Counter::getZero());
1395 HasTerminateStmt =
true;
1399 std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
1400 SourceLocation BeforeLoc) {
1405 return std::nullopt;
1410 FileID FID =
SM.getFileID(AfterLoc);
1411 const SrcMgr::ExpansionInfo *EI = &
SM.getSLocEntry(FID).getExpansion();
1416 size_t StartDepth = locationDepth(AfterLoc);
1417 size_t EndDepth = locationDepth(BeforeLoc);
1418 while (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
1419 bool UnnestStart = StartDepth >= EndDepth;
1420 bool UnnestEnd = EndDepth >= StartDepth;
1422 assert(
SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1425 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1430 assert(
SM.isWrittenInSameFile(AfterLoc,
1431 getEndOfFileOrMacro(AfterLoc)));
1433 AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
1435 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1440 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1444 return std::nullopt;
1445 if (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
1446 !SpellingRegion(
SM, AfterLoc, BeforeLoc).isInSourceOrder())
1447 return std::nullopt;
1448 return {{AfterLoc, BeforeLoc}};
1452 void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
1454 if (StartLoc == EndLoc)
1456 assert(SpellingRegion(
SM, StartLoc, EndLoc).isInSourceOrder());
1457 handleFileExit(StartLoc);
1458 size_t Index = pushRegion(Count, StartLoc, EndLoc);
1460 handleFileExit(EndLoc);
1466 std::optional<SourceRange> findAreaStartingFromTo(SourceLocation StartingLoc,
1467 SourceLocation BeforeLoc) {
1470 FileID FID =
SM.getFileID(StartingLoc);
1471 const SrcMgr::ExpansionInfo *EI = &
SM.getSLocEntry(FID).getExpansion();
1476 size_t StartDepth = locationDepth(StartingLoc);
1477 size_t EndDepth = locationDepth(BeforeLoc);
1478 while (!
SM.isWrittenInSameFile(StartingLoc, BeforeLoc)) {
1479 bool UnnestStart = StartDepth >= EndDepth;
1480 bool UnnestEnd = EndDepth >= StartDepth;
1482 assert(
SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1485 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1490 assert(
SM.isWrittenInSameFile(StartingLoc,
1491 getStartOfFileOrMacro(StartingLoc)));
1493 StartingLoc = getIncludeOrExpansionLoc(StartingLoc);
1494 assert(StartingLoc.
isValid());
1501 return std::nullopt;
1502 if (!
SM.isWrittenInSameFile(StartingLoc, BeforeLoc) ||
1503 !SpellingRegion(
SM, StartingLoc, BeforeLoc).isInSourceOrder())
1504 return std::nullopt;
1505 return {{StartingLoc, BeforeLoc}};
1508 void markSkipped(SourceLocation StartLoc, SourceLocation BeforeLoc) {
1509 const auto Skipped = findAreaStartingFromTo(StartLoc, BeforeLoc);
1514 const auto NewStartLoc = Skipped->getBegin();
1515 const auto EndLoc = Skipped->getEnd();
1517 if (NewStartLoc == EndLoc)
1519 assert(SpellingRegion(
SM, NewStartLoc, EndLoc).isInSourceOrder());
1520 handleFileExit(NewStartLoc);
1521 size_t Index = pushRegion(Counter{}, NewStartLoc, EndLoc);
1523 handleFileExit(EndLoc);
1528 struct BreakContinue {
1530 Counter ContinueCount;
1532 SmallVector<BreakContinue, 8> BreakContinueStack;
1534 CounterCoverageMappingBuilder(
1535 CoverageMappingModuleGen &CVM,
1536 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,
1537 MCDC::State &MCDCState, SourceManager &
SM,
const LangOptions &LangOpts)
1538 : CoverageMappingBuilder(CVM,
SM, LangOpts), CounterMap(CounterMap),
1539 NextCounterNum(CounterMap.size()), MCDCState(MCDCState),
1540 MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {}
1543 void write(llvm::raw_ostream &OS) {
1544 llvm::SmallVector<unsigned, 8> VirtualFileMapping;
1545 gatherFileIDs(VirtualFileMapping);
1546 SourceRegionFilter
Filter = emitExpansionRegions();
1547 emitSourceRegions(Filter);
1548 gatherSkippedRegions();
1550 if (MappingRegions.empty())
1553 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
1558 void VisitStmt(
const Stmt *S) {
1561 const Stmt *LastStmt =
nullptr;
1562 bool SaveTerminateStmt = HasTerminateStmt;
1563 HasTerminateStmt =
false;
1564 GapRegionCounter = Counter::getZero();
1565 for (
const Stmt *Child : S->
children())
1569 if (LastStmt && HasTerminateStmt) {
1570 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
1572 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
1574 SaveTerminateStmt =
true;
1575 HasTerminateStmt =
false;
1580 if (SaveTerminateStmt)
1581 HasTerminateStmt =
true;
1582 handleFileExit(getEnd(S));
1585 void VisitStmtExpr(
const StmtExpr *E) {
1590 HasTerminateStmt =
false;
1593 void VisitDecl(
const Decl *D) {
1599 SM.isInSystemHeader(
SM.getSpellingLoc(getStart(Body))))
1606 Counter BodyCounter = getRegionCounter(Body);
1608 if (
auto *
Method = dyn_cast<CXXMethodDecl>(D))
1610 if (
auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
1614 if (getStart(
Init).isValid() && getEnd(
Init).isValid())
1615 propagateCounts(BodyCounter,
Init);
1620 propagateCounts(BodyCounter, Body,
1622 assert(RegionStack.empty() &&
"Regions entered but never exited");
1625 void VisitReturnStmt(
const ReturnStmt *S) {
1632 void VisitCoroutineBodyStmt(
const CoroutineBodyStmt *S) {
1637 void VisitCoreturnStmt(
const CoreturnStmt *S) {
1644 void VisitCoroutineSuspendExpr(
const CoroutineSuspendExpr *E) {
1648 void VisitCXXThrowExpr(
const CXXThrowExpr *E) {
1655 void VisitGotoStmt(
const GotoStmt *S) { terminateRegion(S); }
1657 void VisitLabelStmt(
const LabelStmt *S) {
1658 Counter LabelCount = getRegionCounter(S);
1659 SourceLocation Start = getStart(S);
1661 handleFileExit(Start);
1662 pushRegion(LabelCount, Start);
1666 void VisitBreakStmt(
const BreakStmt *S) {
1667 assert(!BreakContinueStack.empty() &&
"break not in a loop or switch!");
1668 BreakContinueStack.back().BreakCount = addCounters(
1669 BreakContinueStack.back().BreakCount,
getRegion().getCounter());
1675 void VisitContinueStmt(
const ContinueStmt *S) {
1676 assert(!BreakContinueStack.empty() &&
"continue stmt not in a loop!");
1677 BreakContinueStack.back().ContinueCount = addCounters(
1678 BreakContinueStack.back().ContinueCount,
getRegion().getCounter());
1682 void VisitCallExpr(
const CallExpr *E) {
1692 void VisitWhileStmt(
const WhileStmt *S) {
1695 Counter ParentCount =
getRegion().getCounter();
1696 Counter BodyCount = getRegionCounter(S);
1699 BreakContinueStack.push_back(BreakContinue());
1701 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1702 BreakContinue BC = BreakContinueStack.pop_back_val();
1704 bool BodyHasTerminateStmt = HasTerminateStmt;
1705 HasTerminateStmt =
false;
1709 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1710 auto BranchCount = getBranchCounterPair(S, CondCount);
1711 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1713 propagateCounts(CondCount, S->
getCond());
1714 adjustForOutOfOrderTraversal(getEnd(S));
1719 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1721 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1722 if (!IsCounterEqual(OutCount, ParentCount)) {
1723 pushRegion(OutCount);
1724 GapRegionCounter = OutCount;
1725 if (BodyHasTerminateStmt)
1726 HasTerminateStmt =
true;
1730 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1733 void VisitDoStmt(
const DoStmt *S) {
1736 Counter ParentCount =
getRegion().getCounter();
1737 Counter BodyCount = getRegionCounter(S);
1739 BreakContinueStack.push_back(BreakContinue());
1742 Counter BackedgeCount =
1743 propagateCounts(addCounters(ParentCount, BodyCount), S->
getBody());
1745 BreakContinue BC = BreakContinueStack.pop_back_val();
1747 bool BodyHasTerminateStmt = HasTerminateStmt;
1748 HasTerminateStmt =
false;
1750 Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
1751 auto BranchCount = getBranchCounterPair(S, CondCount);
1752 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1754 propagateCounts(CondCount, S->
getCond());
1756 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1757 if (!IsCounterEqual(OutCount, ParentCount)) {
1758 pushRegion(OutCount);
1759 GapRegionCounter = OutCount;
1760 if (BodyHasTerminateStmt)
1761 HasTerminateStmt =
true;
1765 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1768 void VisitForStmt(
const ForStmt *S) {
1773 Counter ParentCount =
getRegion().getCounter();
1774 Counter BodyCount = getRegionCounter(S);
1778 BreakContinueStack.emplace_back();
1781 BreakContinueStack.emplace_back();
1783 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1784 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1786 bool BodyHasTerminateStmt = HasTerminateStmt;
1787 HasTerminateStmt =
false;
1791 BreakContinue IncrementBC;
1792 if (
const Stmt *Inc = S->
getInc()) {
1793 propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
1794 IncrementBC = BreakContinueStack.pop_back_val();
1798 Counter CondCount = addCounters(
1799 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1800 IncrementBC.ContinueCount);
1801 auto BranchCount = getBranchCounterPair(S, CondCount);
1802 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1805 propagateCounts(CondCount,
Cond);
1806 adjustForOutOfOrderTraversal(getEnd(S));
1812 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1814 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1815 BranchCount.Skipped);
1816 if (!IsCounterEqual(OutCount, ParentCount)) {
1817 pushRegion(OutCount);
1818 GapRegionCounter = OutCount;
1819 if (BodyHasTerminateStmt)
1820 HasTerminateStmt =
true;
1824 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1827 void VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
1834 Counter ParentCount =
getRegion().getCounter();
1835 Counter BodyCount = getRegionCounter(S);
1837 BreakContinueStack.push_back(BreakContinue());
1839 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1840 BreakContinue BC = BreakContinueStack.pop_back_val();
1842 bool BodyHasTerminateStmt = HasTerminateStmt;
1843 HasTerminateStmt =
false;
1848 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1851 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1852 auto BranchCount = getBranchCounterPair(S, LoopCount);
1853 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1855 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1856 if (!IsCounterEqual(OutCount, ParentCount)) {
1857 pushRegion(OutCount);
1858 GapRegionCounter = OutCount;
1859 if (BodyHasTerminateStmt)
1860 HasTerminateStmt =
true;
1864 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1867 void VisitObjCForCollectionStmt(
const ObjCForCollectionStmt *S) {
1871 Counter ParentCount =
getRegion().getCounter();
1872 Counter BodyCount = getRegionCounter(S);
1874 BreakContinueStack.push_back(BreakContinue());
1876 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1877 BreakContinue BC = BreakContinueStack.pop_back_val();
1882 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1885 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1886 auto BranchCount = getBranchCounterPair(S, LoopCount);
1887 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1888 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1889 if (!IsCounterEqual(OutCount, ParentCount)) {
1890 pushRegion(OutCount);
1891 GapRegionCounter = OutCount;
1895 void VisitSwitchStmt(
const SwitchStmt *S) {
1901 BreakContinueStack.push_back(BreakContinue());
1903 const Stmt *Body = S->
getBody();
1905 if (
const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1906 if (!CS->body_empty()) {
1910 size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1915 for (
size_t i = RegionStack.size(); i != Index; --i) {
1916 if (!RegionStack[i - 1].hasEndLoc())
1917 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1923 propagateCounts(Counter::getZero(), Body);
1924 BreakContinue BC = BreakContinueStack.pop_back_val();
1926 if (!BreakContinueStack.empty())
1927 BreakContinueStack.back().ContinueCount = addCounters(
1928 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1930 Counter ParentCount =
getRegion().getCounter();
1931 Counter ExitCount = getRegionCounter(S);
1932 SourceLocation ExitLoc = getEnd(S);
1933 pushRegion(ExitCount);
1934 GapRegionCounter = ExitCount;
1938 MostRecentLocation = getStart(S);
1939 handleFileExit(ExitLoc);
1943 Counter CaseCountSum;
1944 bool HasDefaultCase =
false;
1948 auto CaseCount = createSwitchCaseRegion(Case, ParentCount);
1949 CaseCountSum = addCounters(CaseCountSum, CaseCount,
false);
1954 if (!HasDefaultCase) {
1955 auto Counters = getSwitchImplicitDefaultCounterPair(
1956 S->
getCond(), ParentCount, CaseCountSum);
1957 createBranchRegion(S->
getCond(), Counters.first, Counters.second);
1961 void VisitSwitchCase(
const SwitchCase *S) {
1964 SourceMappingRegion &Parent =
getRegion();
1965 Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
1969 if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
1970 Parent.setCounter(Count);
1972 pushRegion(Count, getStart(S));
1974 GapRegionCounter = Count;
1976 if (
const auto *CS = dyn_cast<CaseStmt>(S)) {
1977 Visit(CS->getLHS());
1978 if (
const Expr *RHS = CS->getRHS())
1984 void coverIfConsteval(
const IfStmt *S) {
1987 const auto *Then = S->
getThen();
1988 const auto *Else = S->
getElse();
1993 const Counter ParentCount =
getRegion().getCounter();
1999 markSkipped(S->
getIfLoc(), getStart(Then));
2000 propagateCounts(ParentCount, Then);
2004 markSkipped(getEnd(Then), getEnd(Else));
2009 markSkipped(S->
getIfLoc(), Else ? getStart(Else) : getEnd(Then));
2012 propagateCounts(ParentCount, Else);
2016 void coverIfConstexpr(
const IfStmt *S) {
2029 const Counter ParentCount =
getRegion().getCounter();
2032 SourceLocation startOfSkipped = S->
getIfLoc();
2035 const auto start = getStart(
Init);
2036 const auto end = getEnd(
Init);
2040 if (start.isValid() && end.isValid()) {
2041 markSkipped(startOfSkipped, start);
2042 propagateCounts(ParentCount,
Init);
2043 startOfSkipped = getEnd(
Init);
2047 const auto *Then = S->
getThen();
2048 const auto *Else = S->
getElse();
2052 markSkipped(startOfSkipped, getStart(Then));
2053 propagateCounts(ParentCount, Then);
2057 markSkipped(getEnd(Then), getEnd(Else));
2060 markSkipped(startOfSkipped, Else ? getStart(Else) : getEnd(Then));
2063 propagateCounts(ParentCount, Else);
2067 void VisitIfStmt(
const IfStmt *S) {
2071 return coverIfConsteval(S);
2073 return coverIfConstexpr(S);
2083 Counter ParentCount =
getRegion().getCounter();
2084 auto [ThenCount, ElseCount] = getBranchCounterPair(S, ParentCount);
2088 propagateCounts(ParentCount, S->
getCond());
2091 std::optional<SourceRange> Gap =
2094 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
2097 Counter OutCount = propagateCounts(ThenCount, S->
getThen());
2099 if (
const Stmt *Else = S->
getElse()) {
2100 bool ThenHasTerminateStmt = HasTerminateStmt;
2101 HasTerminateStmt =
false;
2103 std::optional<SourceRange> Gap =
2104 findGapAreaBetween(getEnd(S->
getThen()), getStart(Else));
2106 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
2109 OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
2111 if (ThenHasTerminateStmt)
2112 HasTerminateStmt =
true;
2114 OutCount = addCounters(OutCount, ElseCount);
2116 if (!IsCounterEqual(OutCount, ParentCount)) {
2117 pushRegion(OutCount);
2118 GapRegionCounter = OutCount;
2122 createBranchRegion(S->
getCond(), ThenCount, ElseCount);
2125 void VisitCXXTryStmt(
const CXXTryStmt *S) {
2130 Counter ParentCount =
getRegion().getCounter();
2136 Counter ExitCount = getRegionCounter(S);
2137 pushRegion(ExitCount);
2140 void VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2144 void VisitAbstractConditionalOperator(
const AbstractConditionalOperator *E) {
2147 Counter ParentCount =
getRegion().getCounter();
2148 auto [TrueCount, FalseCount] = getBranchCounterPair(E, ParentCount);
2151 if (
const auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) {
2152 propagateCounts(ParentCount, BCO->getCommon());
2153 OutCount = TrueCount;
2155 propagateCounts(ParentCount, E->
getCond());
2160 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
2163 OutCount = propagateCounts(TrueCount, E->
getTrueExpr());
2168 addCounters(OutCount, propagateCounts(FalseCount, E->
getFalseExpr()));
2170 if (!IsCounterEqual(OutCount, ParentCount)) {
2171 pushRegion(OutCount);
2172 GapRegionCounter = OutCount;
2176 createBranchRegion(E->
getCond(), TrueCount, FalseCount);
2179 inline unsigned findMCDCBranchesInSourceRegion(
2180 unsigned Since,
std::function<
void(SourceMappingRegion &SR)> CB) {
2181 unsigned I = SourceRegions.size() - 1;
2183 while (I >= Since) {
2184 auto &SR = SourceRegions[I];
2185 if (SR.isMCDCDecision()) {
2187 I = MCDCBuilder.skipSourceRegionIndexForDecisions(I);
2188 }
else if (SR.isMCDCBranch()) {
2200 void createOrCancelDecision(
const Expr *E,
unsigned Since) {
2202 auto NumConds = MCDCBuilder.getTotalConditionsAndPop(SC);
2207 llvm::SmallVector<mcdc::ConditionIDs> CondIDs(NumConds);
2208 findMCDCBranchesInSourceRegion(Since, [&](
const SourceMappingRegion &SR) {
2209 auto [
ID, Conds] = SR.getMCDCBranchParams();
2210 CondIDs[
ID] = Conds;
2214 mcdc::TVIdxBuilder Builder(CondIDs);
2215 unsigned NumTVs = Builder.NumTestVectors;
2217 assert(MaxTVs < mcdc::TVIdxBuilder::HardMaxTVs);
2219 if (NumTVs > MaxTVs) {
2221 cancelDecision(SC, Since, NumTVs, MaxTVs, NumConds);
2228 std::move(Builder.Indices));
2230 auto DecisionParams = mcdc::DecisionParameters{
2236 createDecisionRegion(E, DecisionParams);
2239 assert(SourceRegions.back().isMCDCDecision());
2240 MCDCBuilder.addDecisionRegionRange(Since, SourceRegions.size() - 1);
2244 void cancelDecision(
const Expr *Decision,
unsigned Since,
int NumTVs,
2245 int MaxTVs,
unsigned NumConds) {
2247 Diag.Report(Decision->getBeginLoc(), diag::warn_pgo_test_vector_limit)
2248 << NumTVs << MaxTVs;
2251 unsigned FoundCount = findMCDCBranchesInSourceRegion(
2252 Since, [](SourceMappingRegion &SR) { SR.resetMCDCParams(); });
2253 assert(FoundCount == NumConds &&
2254 "Didn't find all MCDCBranches to be restored");
2262 if (II->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());
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 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)
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)
@ Result
The result type of a method or function.
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