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 {
756 llvm::SmallVector<mcdc::ConditionIDs> DecisionStack;
757 MCDC::State &MCDCState;
758 const Stmt *DecisionStmt =
nullptr;
759 mcdc::ConditionID NextID = 0;
760 bool NotMapped =
false;
764 static constexpr mcdc::ConditionIDs DecisionStackSentinel{-1, -1};
767 bool isLAnd(
const BinaryOperator *E)
const {
772 MCDCCoverageBuilder(CodeGenModule &CGM, MCDC::State &MCDCState)
773 : CGM(CGM), DecisionStack(1, DecisionStackSentinel),
774 MCDCState(MCDCState) {}
779 bool isIdle()
const {
return (NextID == 0 && !NotMapped); }
784 bool isBuilding()
const {
return (NextID > 0); }
787 void setCondID(
const Expr *
Cond, mcdc::ConditionID ID) {
793 mcdc::ConditionID getCondID(
const Expr *
Cond)
const {
802 const mcdc::ConditionIDs &back()
const {
return DecisionStack.back(); }
807 void pushAndAssignIDs(
const BinaryOperator *E) {
825 const mcdc::ConditionIDs &ParentDecision = DecisionStack.back();
831 setCondID(E->
getLHS(), getCondID(E));
833 setCondID(E->
getLHS(), NextID++);
836 mcdc::ConditionID RHSid = NextID++;
837 setCondID(E->
getRHS(), RHSid);
841 DecisionStack.push_back({ParentDecision[
false], RHSid});
843 DecisionStack.push_back({RHSid, ParentDecision[
true]});
847 mcdc::ConditionIDs pop() {
849 return DecisionStackSentinel;
851 assert(DecisionStack.size() > 1);
852 return DecisionStack.pop_back_val();
857 unsigned getTotalConditionsAndReset(
const BinaryOperator *E) {
862 assert(DecisionStack.size() == 1);
872 unsigned TotalConds = NextID;
883struct CounterCoverageMappingBuilder
884 :
public CoverageMappingBuilder,
885 public ConstStmtVisitor<CounterCoverageMappingBuilder> {
887 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;
889 MCDC::State &MCDCState;
892 llvm::SmallVector<SourceMappingRegion> RegionStack;
896 llvm::DenseSet<const Stmt *> LeafExprSet;
899 MCDCCoverageBuilder MCDCBuilder;
901 CounterExpressionBuilder Builder;
907 SourceLocation MostRecentLocation;
910 bool HasTerminateStmt =
false;
913 Counter GapRegionCounter;
916 Counter subtractCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
918 "cannot add counters when single byte coverage mode is enabled");
919 return Builder.subtract(LHS, RHS, Simplify);
923 Counter addCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
924 return Builder.add(LHS, RHS, Simplify);
927 Counter addCounters(Counter C1, Counter C2, Counter C3,
928 bool Simplify =
true) {
929 return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
935 Counter getRegionCounter(
const Stmt *S) {
936 return Counter::getCounter(CounterMap[S].Executed);
939 struct BranchCounterPair {
961 getBranchCounterPair(
const Stmt *S, Counter ParentCnt,
962 std::optional<Counter> SkipCntForOld = std::nullopt) {
963 Counter ExecCnt = getRegionCounter(S);
968 assert(SkipCntForOld &&
969 "SingleByte must provide SkipCntForOld as a fake Skipped count.");
970 return {ExecCnt, *SkipCntForOld};
973 return {ExecCnt, Builder.subtract(ParentCnt, ExecCnt)};
976 bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
977 if (OutCount == ParentCount)
987 size_t pushRegion(Counter Count,
988 std::optional<SourceLocation> StartLoc = std::nullopt,
989 std::optional<SourceLocation> EndLoc = std::nullopt,
990 std::optional<Counter> FalseCount = std::nullopt,
991 const mcdc::Parameters &BranchParams = std::monostate()) {
993 if (StartLoc && !FalseCount) {
994 MostRecentLocation = *StartLoc;
999 assert((!StartLoc || StartLoc->isValid()) &&
"Start location is not valid");
1000 assert((!EndLoc || EndLoc->isValid()) &&
"End location is not valid");
1006 if (StartLoc && StartLoc->isInvalid())
1007 StartLoc = std::nullopt;
1008 if (EndLoc && EndLoc->isInvalid())
1009 EndLoc = std::nullopt;
1010 RegionStack.emplace_back(Count, FalseCount, BranchParams, StartLoc, EndLoc);
1012 return RegionStack.size() - 1;
1015 size_t pushRegion(
const mcdc::DecisionParameters &DecisionParams,
1016 std::optional<SourceLocation> StartLoc = std::nullopt,
1017 std::optional<SourceLocation> EndLoc = std::nullopt) {
1019 RegionStack.emplace_back(DecisionParams, StartLoc, EndLoc);
1021 return RegionStack.size() - 1;
1024 size_t locationDepth(SourceLocation Loc) {
1027 Loc = getIncludeOrExpansionLoc(Loc);
1037 void popRegions(
size_t ParentIndex) {
1038 assert(RegionStack.size() >= ParentIndex &&
"parent not in stack");
1039 while (RegionStack.size() > ParentIndex) {
1040 SourceMappingRegion &Region = RegionStack.back();
1041 if (Region.hasStartLoc() &&
1042 (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) {
1043 SourceLocation StartLoc = Region.getBeginLoc();
1044 SourceLocation EndLoc = Region.hasEndLoc()
1045 ? Region.getEndLoc()
1046 : RegionStack[ParentIndex].getEndLoc();
1047 bool isBranch = Region.isBranch();
1048 size_t StartDepth = locationDepth(StartLoc);
1049 size_t EndDepth = locationDepth(EndLoc);
1050 while (!
SM.isWrittenInSameFile(StartLoc, EndLoc)) {
1051 bool UnnestStart = StartDepth >= EndDepth;
1052 bool UnnestEnd = EndDepth >= StartDepth;
1060 SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
1061 assert(
SM.isWrittenInSameFile(NestedLoc, EndLoc));
1063 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
1064 SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
1067 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
1069 llvm::report_fatal_error(
1070 "File exit not handled before popRegions");
1080 SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
1081 assert(
SM.isWrittenInSameFile(StartLoc, NestedLoc));
1083 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
1084 SourceRegions.emplace_back(Region.getCounter(), StartLoc,
1087 StartLoc = getIncludeOrExpansionLoc(StartLoc);
1089 llvm::report_fatal_error(
1090 "File exit not handled before popRegions");
1094 Region.setStartLoc(StartLoc);
1095 Region.setEndLoc(EndLoc);
1098 MostRecentLocation = EndLoc;
1101 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
1102 EndLoc == getEndOfFileOrMacro(EndLoc))
1103 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
1106 assert(
SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
1107 assert(SpellingRegion(
SM, Region).isInSourceOrder());
1108 SourceRegions.push_back(Region);
1110 RegionStack.pop_back();
1116 assert(!RegionStack.empty() &&
"statement has no region");
1117 return RegionStack.back();
1122 Counter propagateCounts(Counter TopCount,
const Stmt *S,
1123 bool VisitChildren =
true) {
1124 SourceLocation StartLoc = getStart(S);
1125 SourceLocation EndLoc = getEnd(S);
1126 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
1129 Counter ExitCount =
getRegion().getCounter();
1134 if (
SM.isBeforeInTranslationUnit(StartLoc, S->
getBeginLoc()))
1135 MostRecentLocation = EndLoc;
1144 void createBranchRegion(
const Expr *
C, Counter TrueCnt, Counter FalseCnt,
1145 const mcdc::ConditionIDs &Conds = {}) {
1158 mcdc::Parameters BranchParams;
1159 mcdc::ConditionID
ID = MCDCBuilder.getCondID(
C);
1161 BranchParams = mcdc::BranchParameters{
ID, Conds};
1171 if (
Result.Val.getInt().getBoolValue())
1172 FalseCnt = Counter::getZero();
1174 TrueCnt = Counter::getZero();
1177 pushRegion(TrueCnt, getStart(
C), getEnd(
C), FalseCnt, BranchParams));
1184 void createDecisionRegion(
const Expr *
C,
1185 const mcdc::DecisionParameters &DecisionParams) {
1186 popRegions(pushRegion(DecisionParams, getStart(
C), getEnd(
C)));
1192 Counter createSwitchCaseRegion(
const SwitchCase *SC, Counter ParentCount) {
1196 Counter TrueCnt = getRegionCounter(SC);
1197 popRegions(pushRegion(TrueCnt, getStart(SC), SC->
getColonLoc(),
1198 subtractCounters(ParentCount, TrueCnt)));
1204 bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
1205 bool isBranch =
false) {
1206 return llvm::any_of(
1207 llvm::reverse(SourceRegions), [&](
const SourceMappingRegion &Region) {
1208 return Region.getBeginLoc() == StartLoc &&
1209 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
1216 void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
1217 MostRecentLocation = EndLoc;
1224 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
1225 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
1226 MostRecentLocation,
getRegion().isBranch()))
1227 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
1235 void handleFileExit(SourceLocation NewLoc) {
1237 SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
1242 SourceLocation LCA = NewLoc;
1243 FileID ParentFile =
SM.getFileID(LCA);
1244 while (!isNestedIn(MostRecentLocation, ParentFile)) {
1245 LCA = getIncludeOrExpansionLoc(LCA);
1246 if (LCA.
isInvalid() ||
SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
1249 MostRecentLocation = NewLoc;
1252 ParentFile =
SM.getFileID(LCA);
1255 llvm::SmallSet<SourceLocation, 8> StartLocs;
1256 std::optional<Counter> ParentCounter;
1257 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
1258 if (!I.hasStartLoc())
1260 SourceLocation Loc = I.getBeginLoc();
1261 if (!isNestedIn(Loc, ParentFile)) {
1262 ParentCounter = I.getCounter();
1266 while (!
SM.isInFileID(Loc, ParentFile)) {
1270 if (StartLocs.insert(Loc).second) {
1272 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(),
1273 I.getMCDCParams(), Loc,
1274 getEndOfFileOrMacro(Loc), I.isBranch());
1276 SourceRegions.emplace_back(I.getCounter(), Loc,
1277 getEndOfFileOrMacro(Loc));
1279 Loc = getIncludeOrExpansionLoc(Loc);
1281 I.setStartLoc(getPreciseTokenLocEnd(Loc));
1284 if (ParentCounter) {
1288 SourceLocation Loc = MostRecentLocation;
1289 while (isNestedIn(Loc, ParentFile)) {
1290 SourceLocation FileStart = getStartOfFileOrMacro(Loc);
1291 if (StartLocs.insert(FileStart).second) {
1292 SourceRegions.emplace_back(*ParentCounter, FileStart,
1293 getEndOfFileOrMacro(Loc));
1294 assert(SpellingRegion(
SM, SourceRegions.back()).isInSourceOrder());
1296 Loc = getIncludeOrExpansionLoc(Loc);
1300 MostRecentLocation = NewLoc;
1304 void extendRegion(
const Stmt *S) {
1305 SourceMappingRegion &Region =
getRegion();
1306 SourceLocation StartLoc = getStart(S);
1308 handleFileExit(StartLoc);
1309 if (!Region.hasStartLoc())
1310 Region.setStartLoc(StartLoc);
1314 void terminateRegion(
const Stmt *S) {
1316 SourceMappingRegion &Region =
getRegion();
1317 SourceLocation EndLoc = getEnd(S);
1318 if (!Region.hasEndLoc())
1319 Region.setEndLoc(EndLoc);
1320 pushRegion(Counter::getZero());
1321 HasTerminateStmt =
true;
1325 std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
1326 SourceLocation BeforeLoc) {
1331 return std::nullopt;
1336 FileID FID =
SM.getFileID(AfterLoc);
1337 const SrcMgr::ExpansionInfo *EI = &
SM.getSLocEntry(FID).getExpansion();
1342 size_t StartDepth = locationDepth(AfterLoc);
1343 size_t EndDepth = locationDepth(BeforeLoc);
1344 while (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
1345 bool UnnestStart = StartDepth >= EndDepth;
1346 bool UnnestEnd = EndDepth >= StartDepth;
1348 assert(
SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1351 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1356 assert(
SM.isWrittenInSameFile(AfterLoc,
1357 getEndOfFileOrMacro(AfterLoc)));
1359 AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
1361 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1366 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1370 return std::nullopt;
1371 if (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
1372 !SpellingRegion(
SM, AfterLoc, BeforeLoc).isInSourceOrder())
1373 return std::nullopt;
1374 return {{AfterLoc, BeforeLoc}};
1378 void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
1380 if (StartLoc == EndLoc)
1382 assert(SpellingRegion(
SM, StartLoc, EndLoc).isInSourceOrder());
1383 handleFileExit(StartLoc);
1384 size_t Index = pushRegion(Count, StartLoc, EndLoc);
1386 handleFileExit(EndLoc);
1392 std::optional<SourceRange> findAreaStartingFromTo(SourceLocation StartingLoc,
1393 SourceLocation BeforeLoc) {
1396 FileID FID =
SM.getFileID(StartingLoc);
1397 const SrcMgr::ExpansionInfo *EI = &
SM.getSLocEntry(FID).getExpansion();
1402 size_t StartDepth = locationDepth(StartingLoc);
1403 size_t EndDepth = locationDepth(BeforeLoc);
1404 while (!
SM.isWrittenInSameFile(StartingLoc, BeforeLoc)) {
1405 bool UnnestStart = StartDepth >= EndDepth;
1406 bool UnnestEnd = EndDepth >= StartDepth;
1408 assert(
SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1411 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1416 assert(
SM.isWrittenInSameFile(StartingLoc,
1417 getStartOfFileOrMacro(StartingLoc)));
1419 StartingLoc = getIncludeOrExpansionLoc(StartingLoc);
1420 assert(StartingLoc.
isValid());
1427 return std::nullopt;
1428 if (!
SM.isWrittenInSameFile(StartingLoc, BeforeLoc) ||
1429 !SpellingRegion(
SM, StartingLoc, BeforeLoc).isInSourceOrder())
1430 return std::nullopt;
1431 return {{StartingLoc, BeforeLoc}};
1434 void markSkipped(SourceLocation StartLoc, SourceLocation BeforeLoc) {
1435 const auto Skipped = findAreaStartingFromTo(StartLoc, BeforeLoc);
1440 const auto NewStartLoc = Skipped->getBegin();
1441 const auto EndLoc = Skipped->getEnd();
1443 if (NewStartLoc == EndLoc)
1445 assert(SpellingRegion(
SM, NewStartLoc, EndLoc).isInSourceOrder());
1446 handleFileExit(NewStartLoc);
1447 size_t Index = pushRegion(Counter{}, NewStartLoc, EndLoc);
1449 handleFileExit(EndLoc);
1454 struct BreakContinue {
1456 Counter ContinueCount;
1458 SmallVector<BreakContinue, 8> BreakContinueStack;
1460 CounterCoverageMappingBuilder(
1461 CoverageMappingModuleGen &CVM,
1462 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,
1463 MCDC::State &MCDCState, SourceManager &
SM,
const LangOptions &LangOpts)
1464 : CoverageMappingBuilder(CVM,
SM, LangOpts), CounterMap(CounterMap),
1465 MCDCState(MCDCState), MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {}
1468 void write(llvm::raw_ostream &OS) {
1469 llvm::SmallVector<unsigned, 8> VirtualFileMapping;
1470 gatherFileIDs(VirtualFileMapping);
1471 SourceRegionFilter
Filter = emitExpansionRegions();
1472 emitSourceRegions(Filter);
1473 gatherSkippedRegions();
1475 if (MappingRegions.empty())
1478 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
1483 void VisitStmt(
const Stmt *S) {
1486 const Stmt *LastStmt =
nullptr;
1487 bool SaveTerminateStmt = HasTerminateStmt;
1488 HasTerminateStmt =
false;
1489 GapRegionCounter = Counter::getZero();
1490 for (
const Stmt *Child : S->
children())
1494 if (LastStmt && HasTerminateStmt) {
1495 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
1497 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
1499 SaveTerminateStmt =
true;
1500 HasTerminateStmt =
false;
1505 if (SaveTerminateStmt)
1506 HasTerminateStmt =
true;
1507 handleFileExit(getEnd(S));
1510 void VisitStmtExpr(
const StmtExpr *E) {
1515 HasTerminateStmt =
false;
1518 void VisitDecl(
const Decl *D) {
1524 SM.isInSystemHeader(
SM.getSpellingLoc(getStart(Body))))
1531 Counter BodyCounter = getRegionCounter(Body);
1533 if (
auto *
Method = dyn_cast<CXXMethodDecl>(D))
1535 if (
auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
1539 if (getStart(
Init).isValid() && getEnd(
Init).isValid())
1540 propagateCounts(BodyCounter,
Init);
1545 propagateCounts(BodyCounter, Body,
1547 assert(RegionStack.empty() &&
"Regions entered but never exited");
1550 void VisitReturnStmt(
const ReturnStmt *S) {
1557 void VisitCoroutineBodyStmt(
const CoroutineBodyStmt *S) {
1562 void VisitCoreturnStmt(
const CoreturnStmt *S) {
1569 void VisitCoroutineSuspendExpr(
const CoroutineSuspendExpr *E) {
1573 void VisitCXXThrowExpr(
const CXXThrowExpr *E) {
1580 void VisitGotoStmt(
const GotoStmt *S) { terminateRegion(S); }
1582 void VisitLabelStmt(
const LabelStmt *S) {
1583 Counter LabelCount = getRegionCounter(S);
1584 SourceLocation Start = getStart(S);
1586 handleFileExit(Start);
1587 pushRegion(LabelCount, Start);
1591 void VisitBreakStmt(
const BreakStmt *S) {
1592 assert(!BreakContinueStack.empty() &&
"break not in a loop or switch!");
1594 BreakContinueStack.back().BreakCount = addCounters(
1595 BreakContinueStack.back().BreakCount,
getRegion().getCounter());
1601 void VisitContinueStmt(
const ContinueStmt *S) {
1602 assert(!BreakContinueStack.empty() &&
"continue stmt not in a loop!");
1604 BreakContinueStack.back().ContinueCount = addCounters(
1605 BreakContinueStack.back().ContinueCount,
getRegion().getCounter());
1609 void VisitCallExpr(
const CallExpr *E) {
1619 void VisitWhileStmt(
const WhileStmt *S) {
1622 Counter ParentCount =
getRegion().getCounter();
1624 ? getRegionCounter(S->
getBody())
1625 : getRegionCounter(S);
1628 BreakContinueStack.push_back(BreakContinue());
1630 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1631 BreakContinue BC = BreakContinueStack.pop_back_val();
1633 bool BodyHasTerminateStmt = HasTerminateStmt;
1634 HasTerminateStmt =
false;
1639 ? getRegionCounter(S->
getCond())
1640 : addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1641 auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
1642 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1645 propagateCounts(CondCount, S->
getCond());
1646 adjustForOutOfOrderTraversal(getEnd(S));
1651 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1655 (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
1656 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1657 if (!IsCounterEqual(OutCount, ParentCount)) {
1658 pushRegion(OutCount);
1659 GapRegionCounter = OutCount;
1660 if (BodyHasTerminateStmt)
1661 HasTerminateStmt =
true;
1666 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1669 void VisitDoStmt(
const DoStmt *S) {
1672 Counter ParentCount =
getRegion().getCounter();
1674 ? getRegionCounter(S->
getBody())
1675 : getRegionCounter(S);
1677 BreakContinueStack.push_back(BreakContinue());
1680 Counter BackedgeCount;
1682 propagateCounts(BodyCount, S->
getBody());
1685 propagateCounts(addCounters(ParentCount, BodyCount), S->
getBody());
1687 BreakContinue BC = BreakContinueStack.pop_back_val();
1689 bool BodyHasTerminateStmt = HasTerminateStmt;
1690 HasTerminateStmt =
false;
1693 ? getRegionCounter(S->
getCond())
1694 : addCounters(BackedgeCount, BC.ContinueCount);
1695 auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
1696 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1699 propagateCounts(CondCount, S->
getCond());
1703 (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
1704 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1705 if (!IsCounterEqual(OutCount, ParentCount)) {
1706 pushRegion(OutCount);
1707 GapRegionCounter = OutCount;
1708 if (BodyHasTerminateStmt)
1709 HasTerminateStmt =
true;
1714 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1717 void VisitForStmt(
const ForStmt *S) {
1722 Counter ParentCount =
getRegion().getCounter();
1724 ? getRegionCounter(S->
getBody())
1725 : getRegionCounter(S);
1729 BreakContinueStack.emplace_back();
1732 BreakContinueStack.emplace_back();
1734 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1735 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1737 bool BodyHasTerminateStmt = HasTerminateStmt;
1738 HasTerminateStmt =
false;
1742 BreakContinue IncrementBC;
1743 if (
const Stmt *Inc = S->
getInc()) {
1745 if (llvm::EnableSingleByteCoverage)
1746 IncCount = getRegionCounter(S->getInc());
1748 IncCount = addCounters(BackedgeCount, BodyBC.ContinueCount);
1749 propagateCounts(IncCount, Inc);
1750 IncrementBC = BreakContinueStack.pop_back_val();
1756 ? getRegionCounter(S->
getCond())
1758 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1759 IncrementBC.ContinueCount);
1760 auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
1761 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1765 propagateCounts(CondCount,
Cond);
1766 adjustForOutOfOrderTraversal(getEnd(S));
1772 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1775 (BodyBC.BreakCount.isZero() && IncrementBC.BreakCount.isZero()));
1776 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1777 BranchCount.Skipped);
1778 if (!IsCounterEqual(OutCount, ParentCount)) {
1779 pushRegion(OutCount);
1780 GapRegionCounter = OutCount;
1781 if (BodyHasTerminateStmt)
1782 HasTerminateStmt =
true;
1787 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1790 void VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
1797 Counter ParentCount =
getRegion().getCounter();
1799 ? getRegionCounter(S->
getBody())
1800 : getRegionCounter(S);
1802 BreakContinueStack.push_back(BreakContinue());
1804 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1805 BreakContinue BC = BreakContinueStack.pop_back_val();
1807 bool BodyHasTerminateStmt = HasTerminateStmt;
1808 HasTerminateStmt =
false;
1813 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1816 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1817 auto BranchCount = getBranchCounterPair(S, LoopCount, getRegionCounter(S));
1818 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1822 (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
1824 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1825 if (!IsCounterEqual(OutCount, ParentCount)) {
1826 pushRegion(OutCount);
1827 GapRegionCounter = OutCount;
1828 if (BodyHasTerminateStmt)
1829 HasTerminateStmt =
true;
1834 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1837 void VisitObjCForCollectionStmt(
const ObjCForCollectionStmt *S) {
1841 Counter ParentCount =
getRegion().getCounter();
1842 Counter BodyCount = getRegionCounter(S);
1844 BreakContinueStack.push_back(BreakContinue());
1846 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1847 BreakContinue BC = BreakContinueStack.pop_back_val();
1852 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1855 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1856 auto BranchCount = getBranchCounterPair(S, LoopCount);
1857 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1858 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1859 if (!IsCounterEqual(OutCount, ParentCount)) {
1860 pushRegion(OutCount);
1861 GapRegionCounter = OutCount;
1865 void VisitSwitchStmt(
const SwitchStmt *S) {
1871 BreakContinueStack.push_back(BreakContinue());
1873 const Stmt *Body = S->
getBody();
1875 if (
const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1876 if (!CS->body_empty()) {
1880 size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1885 for (
size_t i = RegionStack.size(); i != Index; --i) {
1886 if (!RegionStack[i - 1].hasEndLoc())
1887 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1893 propagateCounts(Counter::getZero(), Body);
1894 BreakContinue BC = BreakContinueStack.pop_back_val();
1897 BreakContinueStack.back().ContinueCount = addCounters(
1898 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1900 Counter ParentCount =
getRegion().getCounter();
1901 Counter ExitCount = getRegionCounter(S);
1902 SourceLocation ExitLoc = getEnd(S);
1903 pushRegion(ExitCount);
1904 GapRegionCounter = ExitCount;
1908 MostRecentLocation = getStart(S);
1909 handleFileExit(ExitLoc);
1918 Counter CaseCountSum;
1919 bool HasDefaultCase =
false;
1923 auto CaseCount = createSwitchCaseRegion(Case, ParentCount);
1924 CaseCountSum = addCounters(CaseCountSum, CaseCount,
false);
1929 if (!HasDefaultCase) {
1934 addCounters(CaseCountSum, Counter::getZero(),
true);
1937 Counter SwitchFalse = subtractCounters(ParentCount, CaseCountSum);
1938 createBranchRegion(S->
getCond(), CaseCountSum, SwitchFalse);
1942 void VisitSwitchCase(
const SwitchCase *S) {
1945 SourceMappingRegion &Parent =
getRegion();
1947 ? getRegionCounter(S)
1948 : addCounters(Parent.getCounter(), getRegionCounter(S));
1952 if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
1953 Parent.setCounter(Count);
1955 pushRegion(Count, getStart(S));
1957 GapRegionCounter = Count;
1959 if (
const auto *CS = dyn_cast<CaseStmt>(S)) {
1960 Visit(CS->getLHS());
1961 if (
const Expr *RHS = CS->getRHS())
1967 void coverIfConsteval(
const IfStmt *S) {
1970 const auto *Then = S->
getThen();
1971 const auto *Else = S->
getElse();
1976 const Counter ParentCount =
getRegion().getCounter();
1982 markSkipped(S->
getIfLoc(), getStart(Then));
1983 propagateCounts(ParentCount, Then);
1987 markSkipped(getEnd(Then), getEnd(Else));
1992 markSkipped(S->
getIfLoc(), Else ? getStart(Else) : getEnd(Then));
1995 propagateCounts(ParentCount, Else);
1999 void coverIfConstexpr(
const IfStmt *S) {
2012 const Counter ParentCount =
getRegion().getCounter();
2015 SourceLocation startOfSkipped = S->
getIfLoc();
2018 const auto start = getStart(
Init);
2019 const auto end = getEnd(
Init);
2023 if (start.isValid() && end.isValid()) {
2024 markSkipped(startOfSkipped, start);
2025 propagateCounts(ParentCount,
Init);
2026 startOfSkipped = getEnd(
Init);
2030 const auto *Then = S->
getThen();
2031 const auto *Else = S->
getElse();
2035 markSkipped(startOfSkipped, getStart(Then));
2036 propagateCounts(ParentCount, Then);
2040 markSkipped(getEnd(Then), getEnd(Else));
2043 markSkipped(startOfSkipped, Else ? getStart(Else) : getEnd(Then));
2046 propagateCounts(ParentCount, Else);
2050 void VisitIfStmt(
const IfStmt *S) {
2054 return coverIfConsteval(S);
2056 return coverIfConstexpr(S);
2066 Counter ParentCount =
getRegion().getCounter();
2067 auto [ThenCount, ElseCount] =
2069 ? BranchCounterPair{getRegionCounter(S->
getThen()),
2071 : Counter::getZero())}
2072 : getBranchCounterPair(S, ParentCount));
2076 propagateCounts(ParentCount, S->
getCond());
2079 std::optional<SourceRange> Gap =
2082 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
2085 Counter OutCount = propagateCounts(ThenCount, S->
getThen());
2087 if (
const Stmt *Else = S->
getElse()) {
2088 bool ThenHasTerminateStmt = HasTerminateStmt;
2089 HasTerminateStmt =
false;
2091 std::optional<SourceRange> Gap =
2092 findGapAreaBetween(getEnd(S->
getThen()), getStart(Else));
2094 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
2097 Counter ElseOutCount = propagateCounts(ElseCount, Else);
2099 OutCount = addCounters(OutCount, ElseOutCount);
2101 if (ThenHasTerminateStmt)
2102 HasTerminateStmt =
true;
2104 OutCount = addCounters(OutCount, ElseCount);
2107 OutCount = getRegionCounter(S);
2109 if (!IsCounterEqual(OutCount, ParentCount)) {
2110 pushRegion(OutCount);
2111 GapRegionCounter = OutCount;
2116 createBranchRegion(S->
getCond(), ThenCount, ElseCount);
2119 void VisitCXXTryStmt(
const CXXTryStmt *S) {
2124 Counter ParentCount =
getRegion().getCounter();
2130 Counter ExitCount = getRegionCounter(S);
2131 pushRegion(ExitCount);
2134 void VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2138 void VisitAbstractConditionalOperator(
const AbstractConditionalOperator *E) {
2141 Counter ParentCount =
getRegion().getCounter();
2142 auto [TrueCount, FalseCount] =
2144 ? BranchCounterPair{getRegionCounter(E->
getTrueExpr()),
2146 : getBranchCounterPair(E, ParentCount));
2149 if (
const auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) {
2150 propagateCounts(ParentCount, BCO->getCommon());
2151 OutCount = TrueCount;
2153 propagateCounts(ParentCount, E->
getCond());
2158 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
2161 OutCount = propagateCounts(TrueCount, E->
getTrueExpr());
2165 Counter FalseOutCount = propagateCounts(FalseCount, E->
getFalseExpr());
2167 OutCount = getRegionCounter(E);
2169 OutCount = addCounters(OutCount, FalseOutCount);
2171 if (!IsCounterEqual(OutCount, ParentCount)) {
2172 pushRegion(OutCount);
2173 GapRegionCounter = OutCount;
2178 createBranchRegion(E->
getCond(), TrueCount, FalseCount);
2181 void createOrCancelDecision(
const BinaryOperator *E,
unsigned Since) {
2182 unsigned NumConds = MCDCBuilder.getTotalConditionsAndReset(E);
2187 llvm::SmallVector<mcdc::ConditionIDs> CondIDs(NumConds);
2188 for (
const auto &SR : ArrayRef(SourceRegions).slice(Since)) {
2189 if (SR.isMCDCBranch()) {
2190 auto [
ID, Conds] = SR.getMCDCBranchParams();
2191 CondIDs[
ID] = Conds;
2196 mcdc::TVIdxBuilder Builder(CondIDs);
2197 unsigned NumTVs = Builder.NumTestVectors;
2199 assert(MaxTVs < mcdc::TVIdxBuilder::HardMaxTVs);
2201 if (NumTVs > MaxTVs) {
2203 cancelDecision(E, Since, NumTVs, MaxTVs);
2211 std::move(Builder.Indices),
2214 auto DecisionParams = mcdc::DecisionParameters{
2220 createDecisionRegion(E, DecisionParams);
2224 void cancelDecision(
const BinaryOperator *E,
unsigned Since,
int NumTVs,
2228 << NumTVs << MaxTVs;
2231 for (
auto &SR : MutableArrayRef(SourceRegions).slice(Since)) {
2232 assert(!SR.isMCDCDecision() &&
"Decision shouldn't be seen here");
2233 if (SR.isMCDCBranch())
2234 SR.resetMCDCParams();
2242 bool isExprInSystemHeader(
const BinaryOperator *E)
const {
2249 void VisitBinLAnd(
const BinaryOperator *E) {
2250 if (isExprInSystemHeader(E)) {
2251 LeafExprSet.insert(E);
2255 bool IsRootNode = MCDCBuilder.isIdle();
2257 unsigned SourceRegionsSince = SourceRegions.size();
2260 MCDCBuilder.pushAndAssignIDs(E);
2262 extendRegion(E->
getLHS());
2264 handleFileExit(getEnd(E->
getLHS()));
2267 const auto DecisionLHS = MCDCBuilder.pop();
2270 findGapAreaBetween(getEnd(E->
getLHS()), getStart(E->
getRHS()))) {
2271 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));
2275 extendRegion(E->
getRHS());
2276 propagateCounts(getRegionCounter(E), E->
getRHS());
2282 const auto DecisionRHS = MCDCBuilder.back();
2285 Counter ParentCnt =
getRegion().getCounter();
2288 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2291 auto [RHSTrueCnt, RHSExitCnt] =
2292 getBranchCounterPair(E->
getRHS(), RHSExecCnt);
2295 createBranchRegion(E->
getLHS(), RHSExecCnt, LHSExitCnt, DecisionLHS);
2298 createBranchRegion(E->
getRHS(), RHSTrueCnt, RHSExitCnt, DecisionRHS);
2302 createOrCancelDecision(E, SourceRegionsSince);
2306 bool shouldVisitRHS(
const Expr *LHS) {
2307 bool LHSIsTrue =
false;
2308 bool LHSIsConst =
false;
2312 return !LHSIsConst || (LHSIsConst && !LHSIsTrue);
2315 void VisitBinLOr(
const BinaryOperator *E) {
2316 if (isExprInSystemHeader(E)) {
2317 LeafExprSet.insert(E);
2321 bool IsRootNode = MCDCBuilder.isIdle();
2323 unsigned SourceRegionsSince = SourceRegions.size();
2326 MCDCBuilder.pushAndAssignIDs(E);
2328 extendRegion(E->
getLHS());
2329 Counter OutCount = propagateCounts(
getRegion().getCounter(), E->
getLHS());
2330 handleFileExit(getEnd(E->
getLHS()));
2333 const auto DecisionLHS = MCDCBuilder.pop();
2336 findGapAreaBetween(getEnd(E->
getLHS()), getStart(E->
getRHS()))) {
2337 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));
2341 extendRegion(E->
getRHS());
2342 propagateCounts(getRegionCounter(E), E->
getRHS());
2348 const auto DecisionRHS = MCDCBuilder.back();
2351 Counter ParentCnt =
getRegion().getCounter();
2354 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2357 auto [RHSFalseCnt, RHSExitCnt] =
2358 getBranchCounterPair(E->
getRHS(), RHSExecCnt);
2360 if (!shouldVisitRHS(E->
getLHS())) {
2361 GapRegionCounter = OutCount;
2365 createBranchRegion(E->
getLHS(), LHSExitCnt, RHSExecCnt, DecisionLHS);
2368 createBranchRegion(E->
getRHS(), RHSExitCnt, RHSFalseCnt, DecisionRHS);
2372 createOrCancelDecision(E, SourceRegionsSince);
2380 void VisitArrayInitLoopExpr(
const ArrayInitLoopExpr *AILE) {
2384 void VisitPseudoObjectExpr(
const PseudoObjectExpr *POE) {
2389 void VisitOpaqueValueExpr(
const OpaqueValueExpr* OVE) {
2397static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
2400 OS << FunctionName <<
":\n";
2401 CounterMappingContext Ctx(Expressions);
2402 for (
const auto &R : Regions) {
2405 case CounterMappingRegion::CodeRegion:
2407 case CounterMappingRegion::ExpansionRegion:
2410 case CounterMappingRegion::SkippedRegion:
2413 case CounterMappingRegion::GapRegion:
2416 case CounterMappingRegion::BranchRegion:
2417 case CounterMappingRegion::MCDCBranchRegion:
2420 case CounterMappingRegion::MCDCDecisionRegion:
2425 OS <<
"File " << R.FileID <<
", " << R.LineStart <<
":" << R.ColumnStart
2426 <<
" -> " << R.LineEnd <<
":" << R.ColumnEnd <<
" = ";
2428 if (
const auto *DecisionParams =
2429 std::get_if<mcdc::DecisionParameters>(&R.MCDCParams)) {
2430 OS <<
"M:" << DecisionParams->BitmapIdx;
2431 OS <<
", C:" << DecisionParams->NumConditions;
2433 Ctx.dump(R.Count, OS);
2437 Ctx.dump(R.FalseCount, OS);
2441 if (
const auto *BranchParams =
2442 std::get_if<mcdc::BranchParameters>(&R.MCDCParams)) {
2443 OS <<
" [" << BranchParams->ID + 1 <<
","
2444 << BranchParams->Conds[
true] + 1;
2445 OS <<
"," << BranchParams->Conds[
false] + 1 <<
"] ";
2448 if (R.Kind == CounterMappingRegion::ExpansionRegion)
2449 OS <<
" (Expanded file = " << R.ExpandedFileID <<
")";
2456 : CGM(CGM), SourceInfo(SourceInfo) {}
2458std::string CoverageMappingModuleGen::getCurrentDirname() {
2462std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
2464 llvm::sys::path::remove_dots(Path,
true);
2469 for (
const auto &[From, To] :
2471 if (llvm::sys::path::replace_path_prefix(Path, From, To))
2474 return Path.str().str();
2478 llvm::InstrProfSectKind SK) {
2479 return llvm::getInstrProfSectionName(
2483void CoverageMappingModuleGen::emitFunctionMappingRecord(
2484 const FunctionInfo &Info, uint64_t FilenamesRef) {
2485 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
2488 std::string FuncRecordName =
"__covrec_" + llvm::utohexstr(Info.NameHash);
2495 FuncRecordName +=
"u";
2498 const uint64_t NameHash = Info.NameHash;
2499 const uint64_t FuncHash = Info.FuncHash;
2500 const std::string &CoverageMapping = Info.CoverageMapping;
2501#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
2502 llvm::Type *FunctionRecordTypes[] = {
2503#include "llvm/ProfileData/InstrProfData.inc"
2505 auto *FunctionRecordTy =
2506 llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes),
2510#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
2511 llvm::Constant *FunctionRecordVals[] = {
2512 #include "llvm/ProfileData/InstrProfData.inc"
2514 auto *FuncRecordConstant =
2515 llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals));
2518 auto *FuncRecord =
new llvm::GlobalVariable(
2519 CGM.getModule(), FunctionRecordTy,
true,
2520 llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
2522 FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
2524 FuncRecord->setAlignment(llvm::Align(8));
2525 if (CGM.supportsCOMDAT())
2526 FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
2529 CGM.addUsedGlobal(FuncRecord);
2533 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
2534 const std::string &CoverageMapping,
bool IsUsed) {
2535 const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
2536 FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
2539 FunctionNames.push_back(NamePtr);
2541 if (CGM.getCodeGenOpts().DumpCoverageMapping) {
2548 std::vector<StringRef> Filenames;
2549 std::vector<CounterExpression> Expressions;
2550 std::vector<CounterMappingRegion> Regions;
2551 FilenameStrs.resize(FileEntries.size() + 1);
2552 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2553 for (
const auto &Entry : FileEntries) {
2554 auto I = Entry.second;
2555 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2558 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
2559 Expressions, Regions);
2562 dump(llvm::outs(), NameValue, Expressions, Regions);
2567 if (FunctionRecords.empty())
2569 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
2570 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
2574 FilenameStrs.resize(FileEntries.size() + 1);
2576 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2577 for (
const auto &Entry : FileEntries) {
2578 auto I = Entry.second;
2579 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2582 std::string Filenames;
2584 llvm::raw_string_ostream OS(Filenames);
2585 CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
2587 auto *FilenamesVal =
2588 llvm::ConstantDataArray::getString(Ctx, Filenames,
false);
2589 const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
2592 for (
const FunctionInfo &Info : FunctionRecords)
2593 emitFunctionMappingRecord(Info, FilenamesRef);
2595 const unsigned NRecords = 0;
2596 const size_t FilenamesSize = Filenames.size();
2597 const unsigned CoverageMappingSize = 0;
2598 llvm::Type *CovDataHeaderTypes[] = {
2599#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
2600#include "llvm/ProfileData/InstrProfData.inc"
2602 auto CovDataHeaderTy =
2603 llvm::StructType::get(Ctx,
ArrayRef(CovDataHeaderTypes));
2604 llvm::Constant *CovDataHeaderVals[] = {
2605#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
2606#include "llvm/ProfileData/InstrProfData.inc"
2608 auto CovDataHeaderVal =
2609 llvm::ConstantStruct::get(CovDataHeaderTy,
ArrayRef(CovDataHeaderVals));
2612 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
2613 auto CovDataTy = llvm::StructType::get(Ctx,
ArrayRef(CovDataTypes));
2614 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
2615 auto CovDataVal = llvm::ConstantStruct::get(CovDataTy,
ArrayRef(TUDataVals));
2616 auto CovData =
new llvm::GlobalVariable(
2617 CGM.getModule(), CovDataTy,
true, llvm::GlobalValue::PrivateLinkage,
2618 CovDataVal, llvm::getCoverageMappingVarName());
2621 CovData->setAlignment(llvm::Align(8));
2624 CGM.addUsedGlobal(CovData);
2626 if (!FunctionNames.empty()) {
2627 auto AddrSpace = FunctionNames.front()->getType()->getPointerAddressSpace();
2628 auto NamesArrTy = llvm::ArrayType::get(
2629 llvm::PointerType::get(Ctx, AddrSpace), FunctionNames.size());
2630 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
2633 new llvm::GlobalVariable(CGM.getModule(), NamesArrTy,
true,
2634 llvm::GlobalValue::InternalLinkage, NamesArrVal,
2635 llvm::getCoverageUnusedNamesVarName());
2640 return FileEntries.try_emplace(
File, FileEntries.size() + 1).first->second;
2644 llvm::raw_ostream &OS) {
2645 assert(CounterMap && MCDCState);
2646 CounterCoverageMappingBuilder Walker(CVM, *CounterMap, *MCDCState, SM,
2648 Walker.VisitDecl(D);
2653 llvm::raw_ostream &OS) {
2654 EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
2655 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.
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)
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
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
llvm::DenseMap< const Stmt *, Branch > BranchByStmt
llvm::DenseMap< const Stmt *, Decision > DecisionByStmt