19#include "llvm/ADT/DenseSet.h"
20#include "llvm/ADT/SmallSet.h"
21#include "llvm/ADT/StringExtras.h"
22#include "llvm/ProfileData/Coverage/CoverageMapping.h"
23#include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
24#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
25#include "llvm/Support/FileSystem.h"
26#include "llvm/Support/Path.h"
37 llvm::cl::desc(
"Enable single byte coverage"),
38 llvm::cl::Hidden, llvm::cl::init(
false));
42 "emptyline-comment-coverage",
43 llvm::cl::desc(
"Emit emptylines and comment lines as skipped regions (only "
44 "disable it on test)"),
45 llvm::cl::init(
true), llvm::cl::Hidden);
49 "system-headers-coverage",
50 cl::desc(
"Enable collecting coverage from system headers"), cl::init(
false),
70 if (
Tok.getKind() != clang::tok::eod)
80 PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
81 SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
83 SkippedRanges.back().Range.setEnd(Range.getEnd());
85 SkippedRanges.push_back({Range, RangeKind,
PrevTokLoc});
102 if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
103 SkippedRanges.back().NextTokLoc = Loc;
108class SourceMappingRegion {
113 std::optional<Counter> FalseCount;
116 mcdc::Parameters MCDCParams;
119 std::optional<SourceLocation> LocStart;
122 std::optional<SourceLocation> LocEnd;
133 SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart,
134 std::optional<SourceLocation> LocEnd,
135 bool GapRegion =
false)
136 : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
137 SkippedRegion(
false) {}
139 SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount,
140 mcdc::Parameters MCDCParams,
141 std::optional<SourceLocation> LocStart,
142 std::optional<SourceLocation> LocEnd,
143 bool GapRegion =
false)
144 : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams),
145 LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
146 SkippedRegion(
false) {}
148 SourceMappingRegion(mcdc::Parameters MCDCParams,
149 std::optional<SourceLocation> LocStart,
150 std::optional<SourceLocation> LocEnd)
151 : MCDCParams(MCDCParams), LocStart(LocStart), LocEnd(LocEnd),
154 const Counter &getCounter()
const {
return Count; }
156 const Counter &getFalseCounter()
const {
157 assert(FalseCount &&
"Region has no alternate counter");
161 void setCounter(Counter
C) { Count =
C; }
163 bool hasStartLoc()
const {
return LocStart.has_value(); }
165 void setStartLoc(SourceLocation Loc) { LocStart = Loc; }
167 SourceLocation getBeginLoc()
const {
168 assert(LocStart &&
"Region has no start location");
172 bool hasEndLoc()
const {
return LocEnd.has_value(); }
174 void setEndLoc(SourceLocation Loc) {
175 assert(Loc.
isValid() &&
"Setting an invalid end location");
179 SourceLocation getEndLoc()
const {
180 assert(LocEnd &&
"Region has no end location");
184 bool isGap()
const {
return GapRegion; }
186 void setGap(
bool Gap) { GapRegion = Gap; }
188 bool isSkipped()
const {
return SkippedRegion; }
190 void setSkipped(
bool Skipped) { SkippedRegion = Skipped; }
192 bool isBranch()
const {
return FalseCount.has_value(); }
194 bool isMCDCBranch()
const {
195 return std::holds_alternative<mcdc::BranchParameters>(MCDCParams);
198 const auto &getMCDCBranchParams()
const {
199 return mcdc::getParams<const mcdc::BranchParameters>(MCDCParams);
202 bool isMCDCDecision()
const {
203 return std::holds_alternative<mcdc::DecisionParameters>(MCDCParams);
206 const auto &getMCDCDecisionParams()
const {
207 return mcdc::getParams<const mcdc::DecisionParameters>(MCDCParams);
210 const mcdc::Parameters &getMCDCParams()
const {
return MCDCParams; }
212 void resetMCDCParams() { MCDCParams = mcdc::Parameters(); }
216struct SpellingRegion {
221 unsigned ColumnStart;
229 SpellingRegion(SourceManager &
SM, SourceLocation LocStart,
230 SourceLocation LocEnd) {
231 LineStart =
SM.getSpellingLineNumber(LocStart);
232 ColumnStart =
SM.getSpellingColumnNumber(LocStart);
233 LineEnd =
SM.getSpellingLineNumber(LocEnd);
234 ColumnEnd =
SM.getSpellingColumnNumber(LocEnd);
237 SpellingRegion(SourceManager &
SM, SourceMappingRegion &R)
238 : SpellingRegion(
SM, R.getBeginLoc(), R.getEndLoc()) {}
242 bool isInSourceOrder()
const {
243 return (LineStart < LineEnd) ||
244 (LineStart == LineEnd && ColumnStart <= ColumnEnd);
250class CoverageMappingBuilder {
252 CoverageMappingModuleGen &CVM;
254 const LangOptions &LangOpts;
258 llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
263 llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
265 std::vector<SourceMappingRegion> SourceRegions;
272 typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
275 CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &
SM,
276 const LangOptions &LangOpts)
277 : CVM(CVM),
SM(
SM), LangOpts(LangOpts) {}
280 SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
289 SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
292 return SM.getLocForStartOfFile(
SM.getFileID(Loc));
296 SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
299 SM.getFileOffset(Loc));
300 return SM.getLocForEndOfFile(
SM.getFileID(Loc));
310 std::pair<SourceLocation, std::optional<SourceLocation>>
311 getNonScratchExpansionLoc(SourceLocation Loc) {
312 std::optional<SourceLocation> EndLoc = std::nullopt;
314 SM.isWrittenInScratchSpace(
SM.getSpellingLoc(Loc))) {
315 auto ExpansionRange =
SM.getImmediateExpansionRange(Loc);
316 Loc = ExpansionRange.getBegin();
317 EndLoc = ExpansionRange.getEnd();
319 return std::make_pair(Loc, EndLoc);
325 SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc,
326 bool AcceptScratch =
true) {
328 return SM.getIncludeLoc(
SM.getFileID(Loc));
329 Loc =
SM.getImmediateExpansionRange(Loc).getBegin();
332 return getNonScratchExpansionLoc(Loc).first;
336 bool isInBuiltin(SourceLocation Loc) {
337 return SM.getBufferName(
SM.getSpellingLoc(Loc)) ==
"<built-in>";
341 bool isNestedIn(SourceLocation Loc, FileID Parent) {
343 Loc = getIncludeOrExpansionLoc(Loc);
346 }
while (!
SM.isInFileID(Loc, Parent));
351 SourceLocation getStart(
const Stmt *S) {
353 while (
SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
354 Loc =
SM.getImmediateExpansionRange(Loc).getBegin();
359 SourceLocation getEnd(
const Stmt *S) {
361 while (
SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
362 Loc =
SM.getImmediateExpansionRange(Loc).getBegin();
363 return getPreciseTokenLocEnd(Loc);
371 void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
372 FileIDMapping.clear();
374 llvm::SmallSet<FileID, 8> Visited;
375 SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
376 for (
auto &Region : SourceRegions) {
377 SourceLocation Loc = Region.getBeginLoc();
380 auto NonScratchExpansionLoc = getNonScratchExpansionLoc(Loc);
381 auto EndLoc = NonScratchExpansionLoc.second;
382 if (EndLoc.has_value()) {
383 Loc = NonScratchExpansionLoc.first;
384 Region.setStartLoc(Loc);
385 Region.setEndLoc(EndLoc.value());
390 auto BeginLoc =
SM.getSpellingLoc(Loc);
391 auto EndLoc =
SM.getSpellingLoc(Region.getEndLoc());
392 if (
SM.isWrittenInSameFile(BeginLoc, EndLoc)) {
393 Loc =
SM.getFileLoc(Loc);
394 Region.setStartLoc(Loc);
395 Region.setEndLoc(
SM.getFileLoc(Region.getEndLoc()));
399 FileID
File =
SM.getFileID(Loc);
400 if (!Visited.insert(
File).second)
404 !
SM.isInSystemHeader(
SM.getSpellingLoc(Loc)));
407 for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
408 Parent.
isValid(); Parent = getIncludeOrExpansionLoc(Parent))
410 FileLocs.push_back(std::make_pair(Loc, Depth));
412 llvm::stable_sort(FileLocs, llvm::less_second());
414 for (
const auto &FL : FileLocs) {
415 SourceLocation Loc = FL.first;
416 FileID SpellingFile =
SM.getDecomposedSpellingLoc(Loc).first;
417 auto Entry =
SM.getFileEntryRefForID(SpellingFile);
421 FileIDMapping[
SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
422 Mapping.push_back(CVM.
getFileID(*Entry));
429 std::optional<unsigned> getCoverageFileID(SourceLocation Loc) {
430 auto Mapping = FileIDMapping.find(
SM.getFileID(Loc));
431 if (Mapping != FileIDMapping.end())
432 return Mapping->second.first;
441 std::optional<SpellingRegion> adjustSkippedRange(SourceManager &
SM,
442 SourceLocation LocStart,
443 SourceLocation LocEnd,
444 SourceLocation PrevTokLoc,
445 SourceLocation NextTokLoc) {
446 SpellingRegion SR{
SM, LocStart, LocEnd};
448 if (PrevTokLoc.
isValid() &&
SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
449 SR.LineStart ==
SM.getSpellingLineNumber(PrevTokLoc))
451 if (NextTokLoc.
isValid() &&
SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
452 SR.LineEnd ==
SM.getSpellingLineNumber(NextTokLoc)) {
456 if (SR.isInSourceOrder())
463 void gatherSkippedRegions() {
466 llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
467 FileLineRanges.resize(
468 FileIDMapping.size(),
469 std::make_pair(std::numeric_limits<unsigned>::max(), 0));
470 for (
const auto &R : MappingRegions) {
471 FileLineRanges[R.FileID].first =
472 std::min(FileLineRanges[R.FileID].first, R.LineStart);
473 FileLineRanges[R.FileID].second =
474 std::max(FileLineRanges[R.FileID].second, R.LineEnd);
478 for (
auto &I : SkippedRanges) {
479 SourceRange
Range = I.Range;
480 auto LocStart =
Range.getBegin();
481 auto LocEnd =
Range.getEnd();
482 assert(
SM.isWrittenInSameFile(LocStart, LocEnd) &&
483 "region spans multiple files");
485 auto CovFileID = getCoverageFileID(LocStart);
488 std::optional<SpellingRegion> SR;
490 SR = adjustSkippedRange(
SM, LocStart, LocEnd, I.PrevTokLoc,
492 else if (I.isPPIfElse() || I.isEmptyLine())
493 SR = {
SM, LocStart, LocEnd};
497 auto Region = CounterMappingRegion::makeSkipped(
498 *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
502 if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
503 Region.LineEnd <= FileLineRanges[*CovFileID].second)
504 MappingRegions.push_back(Region);
510 void emitSourceRegions(
const SourceRegionFilter &Filter) {
511 for (
const auto &Region : SourceRegions) {
512 assert(Region.hasEndLoc() &&
"incomplete region");
514 SourceLocation LocStart = Region.getBeginLoc();
515 assert(
SM.getFileID(LocStart).isValid() &&
"region in invalid file");
520 SM.isInSystemHeader(
SM.getSpellingLoc(LocStart))) {
521 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
522 "Don't suppress the condition in system headers");
526 auto CovFileID = getCoverageFileID(LocStart);
529 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
530 "Don't suppress the condition in non-file regions");
534 SourceLocation LocEnd = Region.getEndLoc();
535 assert(
SM.isWrittenInSameFile(LocStart, LocEnd) &&
536 "region spans multiple files");
542 if (
Filter.count(std::make_pair(LocStart, LocEnd))) {
543 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
544 "Don't suppress the condition");
549 SpellingRegion SR{
SM, LocStart, LocEnd};
550 assert(SR.isInSourceOrder() &&
"region start and end out of order");
552 if (Region.isGap()) {
553 MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
554 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
555 SR.LineEnd, SR.ColumnEnd));
556 }
else if (Region.isSkipped()) {
557 MappingRegions.push_back(CounterMappingRegion::makeSkipped(
558 *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd,
560 }
else if (Region.isBranch()) {
561 MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
562 Region.getCounter(), Region.getFalseCounter(), *CovFileID,
563 SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd,
564 Region.getMCDCParams()));
565 }
else if (Region.isMCDCDecision()) {
566 MappingRegions.push_back(CounterMappingRegion::makeDecisionRegion(
567 Region.getMCDCDecisionParams(), *CovFileID, SR.LineStart,
568 SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
570 MappingRegions.push_back(CounterMappingRegion::makeRegion(
571 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
572 SR.LineEnd, SR.ColumnEnd));
578 SourceRegionFilter emitExpansionRegions() {
579 SourceRegionFilter
Filter;
580 for (
const auto &FM : FileIDMapping) {
581 SourceLocation ExpandedLoc = FM.second.second;
582 SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc,
false);
586 auto ParentFileID = getCoverageFileID(ParentLoc);
589 auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
590 assert(ExpandedFileID &&
"expansion in uncovered file");
592 SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
593 assert(
SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
594 "region spans multiple files");
595 Filter.insert(std::make_pair(ParentLoc, LocEnd));
597 SpellingRegion SR{
SM, ParentLoc, LocEnd};
598 assert(SR.isInSourceOrder() &&
"region start and end out of order");
599 MappingRegions.push_back(CounterMappingRegion::makeExpansion(
600 *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
601 SR.LineEnd, SR.ColumnEnd));
609struct EmptyCoverageMappingBuilder :
public CoverageMappingBuilder {
610 EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &
SM,
611 const LangOptions &LangOpts)
612 : CoverageMappingBuilder(CVM,
SM, LangOpts) {}
614 void VisitDecl(
const Decl *D) {
618 SourceLocation Start = getStart(Body);
619 SourceLocation End = getEnd(Body);
620 if (!
SM.isWrittenInSameFile(Start, End)) {
623 FileID StartFileID =
SM.getFileID(Start);
624 FileID EndFileID =
SM.getFileID(End);
625 while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
626 Start = getIncludeOrExpansionLoc(Start);
628 "Declaration start location not nested within a known region");
629 StartFileID =
SM.getFileID(Start);
631 while (StartFileID != EndFileID) {
632 End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
634 "Declaration end location not nested within a known region");
635 EndFileID =
SM.getFileID(End);
638 SourceRegions.emplace_back(Counter(), Start, End);
642 void write(llvm::raw_ostream &OS) {
643 SmallVector<unsigned, 16> FileIDMapping;
644 gatherFileIDs(FileIDMapping);
645 emitSourceRegions(SourceRegionFilter());
647 if (MappingRegions.empty())
650 CoverageMappingWriter Writer(FileIDMapping, {}, MappingRegions);
663struct MCDCCoverageBuilder {
755 llvm::SmallVector<mcdc::ConditionIDs> DecisionStack;
756 MCDC::State &MCDCState;
757 const Stmt *DecisionStmt =
nullptr;
758 mcdc::ConditionID NextID = 0;
759 bool NotMapped =
false;
763 static constexpr mcdc::ConditionIDs DecisionStackSentinel{-1, -1};
766 bool isLAnd(
const BinaryOperator *E)
const {
771 MCDCCoverageBuilder(CodeGenModule &CGM, MCDC::State &MCDCState)
772 : CGM(CGM), DecisionStack(1, DecisionStackSentinel),
773 MCDCState(MCDCState) {}
778 bool isIdle()
const {
return (NextID == 0 && !NotMapped); }
783 bool isBuilding()
const {
return (NextID > 0); }
786 void setCondID(
const Expr *
Cond, mcdc::ConditionID ID) {
792 mcdc::ConditionID getCondID(
const Expr *
Cond)
const {
801 const mcdc::ConditionIDs &back()
const {
return DecisionStack.back(); }
806 void pushAndAssignIDs(
const BinaryOperator *E) {
824 const mcdc::ConditionIDs &ParentDecision = DecisionStack.back();
830 setCondID(E->
getLHS(), getCondID(E));
832 setCondID(E->
getLHS(), NextID++);
835 mcdc::ConditionID RHSid = NextID++;
836 setCondID(E->
getRHS(), RHSid);
840 DecisionStack.push_back({ParentDecision[
false], RHSid});
842 DecisionStack.push_back({RHSid, ParentDecision[
true]});
846 mcdc::ConditionIDs pop() {
848 return DecisionStackSentinel;
850 assert(DecisionStack.size() > 1);
851 return DecisionStack.pop_back_val();
856 unsigned getTotalConditionsAndReset(
const BinaryOperator *E) {
861 assert(DecisionStack.size() == 1);
871 unsigned TotalConds = NextID;
882struct CounterCoverageMappingBuilder
883 :
public CoverageMappingBuilder,
884 public ConstStmtVisitor<CounterCoverageMappingBuilder> {
886 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;
888 MCDC::State &MCDCState;
891 llvm::SmallVector<SourceMappingRegion> RegionStack;
895 llvm::DenseSet<const Stmt *> LeafExprSet;
898 MCDCCoverageBuilder MCDCBuilder;
900 CounterExpressionBuilder Builder;
906 SourceLocation MostRecentLocation;
909 bool HasTerminateStmt =
false;
912 Counter GapRegionCounter;
915 Counter subtractCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
917 "cannot add counters when single byte coverage mode is enabled");
918 return Builder.subtract(LHS, RHS, Simplify);
922 Counter addCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
923 return Builder.add(LHS, RHS, Simplify);
926 Counter addCounters(Counter C1, Counter C2, Counter C3,
927 bool Simplify =
true) {
928 return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
934 Counter getRegionCounter(
const Stmt *S) {
935 return Counter::getCounter(CounterMap[S].Executed);
938 struct BranchCounterPair {
960 getBranchCounterPair(
const Stmt *S, Counter ParentCnt,
961 std::optional<Counter> SkipCntForOld = std::nullopt) {
962 Counter ExecCnt = getRegionCounter(S);
967 assert(SkipCntForOld &&
968 "SingleByte must provide SkipCntForOld as a fake Skipped count.");
969 return {ExecCnt, *SkipCntForOld};
972 return {ExecCnt, Builder.subtract(ParentCnt, ExecCnt)};
975 bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
976 if (OutCount == ParentCount)
986 size_t pushRegion(Counter Count,
987 std::optional<SourceLocation> StartLoc = std::nullopt,
988 std::optional<SourceLocation> EndLoc = std::nullopt,
989 std::optional<Counter> FalseCount = std::nullopt,
990 const mcdc::Parameters &BranchParams = std::monostate()) {
992 if (StartLoc && !FalseCount) {
993 MostRecentLocation = *StartLoc;
998 assert((!StartLoc || StartLoc->isValid()) &&
"Start location is not valid");
999 assert((!EndLoc || EndLoc->isValid()) &&
"End location is not valid");
1005 if (StartLoc && StartLoc->isInvalid())
1006 StartLoc = std::nullopt;
1007 if (EndLoc && EndLoc->isInvalid())
1008 EndLoc = std::nullopt;
1009 RegionStack.emplace_back(Count, FalseCount, BranchParams, StartLoc, EndLoc);
1011 return RegionStack.size() - 1;
1014 size_t pushRegion(
const mcdc::DecisionParameters &DecisionParams,
1015 std::optional<SourceLocation> StartLoc = std::nullopt,
1016 std::optional<SourceLocation> EndLoc = std::nullopt) {
1018 RegionStack.emplace_back(DecisionParams, StartLoc, EndLoc);
1020 return RegionStack.size() - 1;
1023 size_t locationDepth(SourceLocation Loc) {
1026 Loc = getIncludeOrExpansionLoc(Loc);
1036 void popRegions(
size_t ParentIndex) {
1037 assert(RegionStack.size() >= ParentIndex &&
"parent not in stack");
1038 while (RegionStack.size() > ParentIndex) {
1039 SourceMappingRegion &Region = RegionStack.back();
1040 if (Region.hasStartLoc() &&
1041 (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) {
1042 SourceLocation StartLoc = Region.getBeginLoc();
1043 SourceLocation EndLoc = Region.hasEndLoc()
1044 ? Region.getEndLoc()
1045 : RegionStack[ParentIndex].getEndLoc();
1046 bool isBranch = Region.isBranch();
1047 size_t StartDepth = locationDepth(StartLoc);
1048 size_t EndDepth = locationDepth(EndLoc);
1049 while (!
SM.isWrittenInSameFile(StartLoc, EndLoc)) {
1050 bool UnnestStart = StartDepth >= EndDepth;
1051 bool UnnestEnd = EndDepth >= StartDepth;
1059 SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
1060 assert(
SM.isWrittenInSameFile(NestedLoc, EndLoc));
1062 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
1063 SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
1066 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
1068 llvm::report_fatal_error(
1069 "File exit not handled before popRegions");
1079 SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
1080 assert(
SM.isWrittenInSameFile(StartLoc, NestedLoc));
1082 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
1083 SourceRegions.emplace_back(Region.getCounter(), StartLoc,
1086 StartLoc = getIncludeOrExpansionLoc(StartLoc);
1088 llvm::report_fatal_error(
1089 "File exit not handled before popRegions");
1093 Region.setStartLoc(StartLoc);
1094 Region.setEndLoc(EndLoc);
1097 MostRecentLocation = EndLoc;
1100 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
1101 EndLoc == getEndOfFileOrMacro(EndLoc))
1102 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
1105 assert(
SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
1106 assert(SpellingRegion(
SM, Region).isInSourceOrder());
1107 SourceRegions.push_back(Region);
1109 RegionStack.pop_back();
1115 assert(!RegionStack.empty() &&
"statement has no region");
1116 return RegionStack.back();
1121 Counter propagateCounts(Counter TopCount,
const Stmt *S,
1122 bool VisitChildren =
true) {
1123 SourceLocation StartLoc = getStart(S);
1124 SourceLocation EndLoc = getEnd(S);
1125 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
1128 Counter ExitCount =
getRegion().getCounter();
1133 if (
SM.isBeforeInTranslationUnit(StartLoc, S->
getBeginLoc()))
1134 MostRecentLocation = EndLoc;
1143 void createBranchRegion(
const Expr *
C, Counter TrueCnt, Counter FalseCnt,
1144 const mcdc::ConditionIDs &Conds = {}) {
1157 mcdc::Parameters BranchParams;
1158 mcdc::ConditionID
ID = MCDCBuilder.getCondID(
C);
1160 BranchParams = mcdc::BranchParameters{
ID, Conds};
1170 if (
Result.Val.getInt().getBoolValue())
1171 FalseCnt = Counter::getZero();
1173 TrueCnt = Counter::getZero();
1176 pushRegion(TrueCnt, getStart(
C), getEnd(
C), FalseCnt, BranchParams));
1183 void createDecisionRegion(
const Expr *
C,
1184 const mcdc::DecisionParameters &DecisionParams) {
1185 popRegions(pushRegion(DecisionParams, getStart(
C), getEnd(
C)));
1191 Counter createSwitchCaseRegion(
const SwitchCase *SC, Counter ParentCount) {
1195 Counter TrueCnt = getRegionCounter(SC);
1196 popRegions(pushRegion(TrueCnt, getStart(SC), SC->
getColonLoc(),
1197 subtractCounters(ParentCount, TrueCnt)));
1203 bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
1204 bool isBranch =
false) {
1205 return llvm::any_of(
1206 llvm::reverse(SourceRegions), [&](
const SourceMappingRegion &Region) {
1207 return Region.getBeginLoc() == StartLoc &&
1208 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
1215 void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
1216 MostRecentLocation = EndLoc;
1223 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
1224 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
1225 MostRecentLocation,
getRegion().isBranch()))
1226 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
1234 void handleFileExit(SourceLocation NewLoc) {
1236 SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
1241 SourceLocation LCA = NewLoc;
1242 FileID ParentFile =
SM.getFileID(LCA);
1243 while (!isNestedIn(MostRecentLocation, ParentFile)) {
1244 LCA = getIncludeOrExpansionLoc(LCA);
1245 if (LCA.
isInvalid() ||
SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
1248 MostRecentLocation = NewLoc;
1251 ParentFile =
SM.getFileID(LCA);
1254 llvm::SmallSet<SourceLocation, 8> StartLocs;
1255 std::optional<Counter> ParentCounter;
1256 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
1257 if (!I.hasStartLoc())
1259 SourceLocation Loc = I.getBeginLoc();
1260 if (!isNestedIn(Loc, ParentFile)) {
1261 ParentCounter = I.getCounter();
1265 while (!
SM.isInFileID(Loc, ParentFile)) {
1269 if (StartLocs.insert(Loc).second) {
1271 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(),
1272 I.getMCDCParams(), Loc,
1273 getEndOfFileOrMacro(Loc), I.isBranch());
1275 SourceRegions.emplace_back(I.getCounter(), Loc,
1276 getEndOfFileOrMacro(Loc));
1278 Loc = getIncludeOrExpansionLoc(Loc);
1280 I.setStartLoc(getPreciseTokenLocEnd(Loc));
1283 if (ParentCounter) {
1287 SourceLocation Loc = MostRecentLocation;
1288 while (isNestedIn(Loc, ParentFile)) {
1289 SourceLocation FileStart = getStartOfFileOrMacro(Loc);
1290 if (StartLocs.insert(FileStart).second) {
1291 SourceRegions.emplace_back(*ParentCounter, FileStart,
1292 getEndOfFileOrMacro(Loc));
1293 assert(SpellingRegion(
SM, SourceRegions.back()).isInSourceOrder());
1295 Loc = getIncludeOrExpansionLoc(Loc);
1299 MostRecentLocation = NewLoc;
1303 void extendRegion(
const Stmt *S) {
1304 SourceMappingRegion &Region =
getRegion();
1305 SourceLocation StartLoc = getStart(S);
1307 handleFileExit(StartLoc);
1308 if (!Region.hasStartLoc())
1309 Region.setStartLoc(StartLoc);
1313 void terminateRegion(
const Stmt *S) {
1315 SourceMappingRegion &Region =
getRegion();
1316 SourceLocation EndLoc = getEnd(S);
1317 if (!Region.hasEndLoc())
1318 Region.setEndLoc(EndLoc);
1319 pushRegion(Counter::getZero());
1320 HasTerminateStmt =
true;
1324 std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
1325 SourceLocation BeforeLoc) {
1330 return std::nullopt;
1335 FileID FID =
SM.getFileID(AfterLoc);
1336 const SrcMgr::ExpansionInfo *EI = &
SM.getSLocEntry(FID).getExpansion();
1341 size_t StartDepth = locationDepth(AfterLoc);
1342 size_t EndDepth = locationDepth(BeforeLoc);
1343 while (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
1344 bool UnnestStart = StartDepth >= EndDepth;
1345 bool UnnestEnd = EndDepth >= StartDepth;
1347 assert(
SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1350 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1355 assert(
SM.isWrittenInSameFile(AfterLoc,
1356 getEndOfFileOrMacro(AfterLoc)));
1358 AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
1360 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1365 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1369 return std::nullopt;
1370 if (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
1371 !SpellingRegion(
SM, AfterLoc, BeforeLoc).isInSourceOrder())
1372 return std::nullopt;
1373 return {{AfterLoc, BeforeLoc}};
1377 void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
1379 if (StartLoc == EndLoc)
1381 assert(SpellingRegion(
SM, StartLoc, EndLoc).isInSourceOrder());
1382 handleFileExit(StartLoc);
1383 size_t Index = pushRegion(Count, StartLoc, EndLoc);
1385 handleFileExit(EndLoc);
1391 std::optional<SourceRange> findAreaStartingFromTo(SourceLocation StartingLoc,
1392 SourceLocation BeforeLoc) {
1395 FileID FID =
SM.getFileID(StartingLoc);
1396 const SrcMgr::ExpansionInfo *EI = &
SM.getSLocEntry(FID).getExpansion();
1401 size_t StartDepth = locationDepth(StartingLoc);
1402 size_t EndDepth = locationDepth(BeforeLoc);
1403 while (!
SM.isWrittenInSameFile(StartingLoc, BeforeLoc)) {
1404 bool UnnestStart = StartDepth >= EndDepth;
1405 bool UnnestEnd = EndDepth >= StartDepth;
1407 assert(
SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1410 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1415 assert(
SM.isWrittenInSameFile(StartingLoc,
1416 getStartOfFileOrMacro(StartingLoc)));
1418 StartingLoc = getIncludeOrExpansionLoc(StartingLoc);
1419 assert(StartingLoc.
isValid());
1426 return std::nullopt;
1427 if (!
SM.isWrittenInSameFile(StartingLoc, BeforeLoc) ||
1428 !SpellingRegion(
SM, StartingLoc, BeforeLoc).isInSourceOrder())
1429 return std::nullopt;
1430 return {{StartingLoc, BeforeLoc}};
1433 void markSkipped(SourceLocation StartLoc, SourceLocation BeforeLoc) {
1434 const auto Skipped = findAreaStartingFromTo(StartLoc, BeforeLoc);
1439 const auto NewStartLoc = Skipped->getBegin();
1440 const auto EndLoc = Skipped->getEnd();
1442 if (NewStartLoc == EndLoc)
1444 assert(SpellingRegion(
SM, NewStartLoc, EndLoc).isInSourceOrder());
1445 handleFileExit(NewStartLoc);
1446 size_t Index = pushRegion(Counter{}, NewStartLoc, EndLoc);
1448 handleFileExit(EndLoc);
1453 struct BreakContinue {
1455 Counter ContinueCount;
1457 SmallVector<BreakContinue, 8> BreakContinueStack;
1459 CounterCoverageMappingBuilder(
1460 CoverageMappingModuleGen &CVM,
1461 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,
1462 MCDC::State &MCDCState, SourceManager &
SM,
const LangOptions &LangOpts)
1463 : CoverageMappingBuilder(CVM,
SM, LangOpts), CounterMap(CounterMap),
1464 MCDCState(MCDCState), MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {}
1467 void write(llvm::raw_ostream &OS) {
1468 llvm::SmallVector<unsigned, 8> VirtualFileMapping;
1469 gatherFileIDs(VirtualFileMapping);
1470 SourceRegionFilter
Filter = emitExpansionRegions();
1471 emitSourceRegions(Filter);
1472 gatherSkippedRegions();
1474 if (MappingRegions.empty())
1477 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
1482 void VisitStmt(
const Stmt *S) {
1485 const Stmt *LastStmt =
nullptr;
1486 bool SaveTerminateStmt = HasTerminateStmt;
1487 HasTerminateStmt =
false;
1488 GapRegionCounter = Counter::getZero();
1489 for (
const Stmt *Child : S->
children())
1493 if (LastStmt && HasTerminateStmt) {
1494 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
1496 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
1498 SaveTerminateStmt =
true;
1499 HasTerminateStmt =
false;
1504 if (SaveTerminateStmt)
1505 HasTerminateStmt =
true;
1506 handleFileExit(getEnd(S));
1509 void VisitStmtExpr(
const StmtExpr *E) {
1514 HasTerminateStmt =
false;
1517 void VisitDecl(
const Decl *D) {
1523 SM.isInSystemHeader(
SM.getSpellingLoc(getStart(Body))))
1530 Counter BodyCounter = getRegionCounter(Body);
1532 if (
auto *
Method = dyn_cast<CXXMethodDecl>(D))
1534 if (
auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
1538 if (getStart(
Init).isValid() && getEnd(
Init).isValid())
1539 propagateCounts(BodyCounter,
Init);
1544 propagateCounts(BodyCounter, Body,
1546 assert(RegionStack.empty() &&
"Regions entered but never exited");
1549 void VisitReturnStmt(
const ReturnStmt *S) {
1556 void VisitCoroutineBodyStmt(
const CoroutineBodyStmt *S) {
1561 void VisitCoreturnStmt(
const CoreturnStmt *S) {
1568 void VisitCoroutineSuspendExpr(
const CoroutineSuspendExpr *E) {
1572 void VisitCXXThrowExpr(
const CXXThrowExpr *E) {
1579 void VisitGotoStmt(
const GotoStmt *S) { terminateRegion(S); }
1581 void VisitLabelStmt(
const LabelStmt *S) {
1582 Counter LabelCount = getRegionCounter(S);
1583 SourceLocation Start = getStart(S);
1585 handleFileExit(Start);
1586 pushRegion(LabelCount, Start);
1590 void VisitBreakStmt(
const BreakStmt *S) {
1591 assert(!BreakContinueStack.empty() &&
"break not in a loop or switch!");
1593 BreakContinueStack.back().BreakCount = addCounters(
1594 BreakContinueStack.back().BreakCount,
getRegion().getCounter());
1600 void VisitContinueStmt(
const ContinueStmt *S) {
1601 assert(!BreakContinueStack.empty() &&
"continue stmt not in a loop!");
1603 BreakContinueStack.back().ContinueCount = addCounters(
1604 BreakContinueStack.back().ContinueCount,
getRegion().getCounter());
1608 void VisitCallExpr(
const CallExpr *E) {
1618 void VisitWhileStmt(
const WhileStmt *S) {
1621 Counter ParentCount =
getRegion().getCounter();
1623 ? getRegionCounter(S->
getBody())
1624 : getRegionCounter(S);
1627 BreakContinueStack.push_back(BreakContinue());
1629 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1630 BreakContinue BC = BreakContinueStack.pop_back_val();
1632 bool BodyHasTerminateStmt = HasTerminateStmt;
1633 HasTerminateStmt =
false;
1638 ? getRegionCounter(S->
getCond())
1639 : addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1640 auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
1641 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1644 propagateCounts(CondCount, S->
getCond());
1645 adjustForOutOfOrderTraversal(getEnd(S));
1650 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1654 (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
1655 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1656 if (!IsCounterEqual(OutCount, ParentCount)) {
1657 pushRegion(OutCount);
1658 GapRegionCounter = OutCount;
1659 if (BodyHasTerminateStmt)
1660 HasTerminateStmt =
true;
1665 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1668 void VisitDoStmt(
const DoStmt *S) {
1671 Counter ParentCount =
getRegion().getCounter();
1673 ? getRegionCounter(S->
getBody())
1674 : getRegionCounter(S);
1676 BreakContinueStack.push_back(BreakContinue());
1679 Counter BackedgeCount;
1681 propagateCounts(BodyCount, S->
getBody());
1684 propagateCounts(addCounters(ParentCount, BodyCount), S->
getBody());
1686 BreakContinue BC = BreakContinueStack.pop_back_val();
1688 bool BodyHasTerminateStmt = HasTerminateStmt;
1689 HasTerminateStmt =
false;
1692 ? getRegionCounter(S->
getCond())
1693 : addCounters(BackedgeCount, BC.ContinueCount);
1694 auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
1695 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1698 propagateCounts(CondCount, S->
getCond());
1702 (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
1703 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1704 if (!IsCounterEqual(OutCount, ParentCount)) {
1705 pushRegion(OutCount);
1706 GapRegionCounter = OutCount;
1707 if (BodyHasTerminateStmt)
1708 HasTerminateStmt =
true;
1713 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1716 void VisitForStmt(
const ForStmt *S) {
1721 Counter ParentCount =
getRegion().getCounter();
1723 ? getRegionCounter(S->
getBody())
1724 : getRegionCounter(S);
1728 BreakContinueStack.emplace_back();
1731 BreakContinueStack.emplace_back();
1733 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1734 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1736 bool BodyHasTerminateStmt = HasTerminateStmt;
1737 HasTerminateStmt =
false;
1741 BreakContinue IncrementBC;
1742 if (
const Stmt *Inc = S->
getInc()) {
1744 if (llvm::EnableSingleByteCoverage)
1745 IncCount = getRegionCounter(S->getInc());
1747 IncCount = addCounters(BackedgeCount, BodyBC.ContinueCount);
1748 propagateCounts(IncCount, Inc);
1749 IncrementBC = BreakContinueStack.pop_back_val();
1755 ? getRegionCounter(S->
getCond())
1757 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1758 IncrementBC.ContinueCount);
1759 auto BranchCount = getBranchCounterPair(S, CondCount, getRegionCounter(S));
1760 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1764 propagateCounts(CondCount,
Cond);
1765 adjustForOutOfOrderTraversal(getEnd(S));
1771 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1774 (BodyBC.BreakCount.isZero() && IncrementBC.BreakCount.isZero()));
1775 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1776 BranchCount.Skipped);
1777 if (!IsCounterEqual(OutCount, ParentCount)) {
1778 pushRegion(OutCount);
1779 GapRegionCounter = OutCount;
1780 if (BodyHasTerminateStmt)
1781 HasTerminateStmt =
true;
1786 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1789 void VisitCXXForRangeStmt(
const CXXForRangeStmt *S) {
1796 Counter ParentCount =
getRegion().getCounter();
1798 ? getRegionCounter(S->
getBody())
1799 : getRegionCounter(S);
1801 BreakContinueStack.push_back(BreakContinue());
1803 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1804 BreakContinue BC = BreakContinueStack.pop_back_val();
1806 bool BodyHasTerminateStmt = HasTerminateStmt;
1807 HasTerminateStmt =
false;
1812 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1815 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1816 auto BranchCount = getBranchCounterPair(S, LoopCount, getRegionCounter(S));
1817 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount ||
1821 (BC.BreakCount.isZero() && BranchCount.Skipped == getRegionCounter(S)));
1823 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1824 if (!IsCounterEqual(OutCount, ParentCount)) {
1825 pushRegion(OutCount);
1826 GapRegionCounter = OutCount;
1827 if (BodyHasTerminateStmt)
1828 HasTerminateStmt =
true;
1833 createBranchRegion(S->
getCond(), BodyCount, BranchCount.Skipped);
1836 void VisitObjCForCollectionStmt(
const ObjCForCollectionStmt *S) {
1840 Counter ParentCount =
getRegion().getCounter();
1841 Counter BodyCount = getRegionCounter(S);
1843 BreakContinueStack.push_back(BreakContinue());
1845 Counter BackedgeCount = propagateCounts(BodyCount, S->
getBody());
1846 BreakContinue BC = BreakContinueStack.pop_back_val();
1851 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1854 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1855 auto BranchCount = getBranchCounterPair(S, LoopCount);
1856 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1857 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1858 if (!IsCounterEqual(OutCount, ParentCount)) {
1859 pushRegion(OutCount);
1860 GapRegionCounter = OutCount;
1864 void VisitSwitchStmt(
const SwitchStmt *S) {
1870 BreakContinueStack.push_back(BreakContinue());
1872 const Stmt *Body = S->
getBody();
1874 if (
const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1875 if (!CS->body_empty()) {
1879 size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1884 for (
size_t i = RegionStack.size(); i != Index; --i) {
1885 if (!RegionStack[i - 1].hasEndLoc())
1886 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1892 propagateCounts(Counter::getZero(), Body);
1893 BreakContinue BC = BreakContinueStack.pop_back_val();
1896 BreakContinueStack.back().ContinueCount = addCounters(
1897 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1899 Counter ParentCount =
getRegion().getCounter();
1900 Counter ExitCount = getRegionCounter(S);
1901 SourceLocation ExitLoc = getEnd(S);
1902 pushRegion(ExitCount);
1903 GapRegionCounter = ExitCount;
1907 MostRecentLocation = getStart(S);
1908 handleFileExit(ExitLoc);
1917 Counter CaseCountSum;
1918 bool HasDefaultCase =
false;
1922 auto CaseCount = createSwitchCaseRegion(Case, ParentCount);
1923 CaseCountSum = addCounters(CaseCountSum, CaseCount,
false);
1928 if (!HasDefaultCase) {
1933 addCounters(CaseCountSum, Counter::getZero(),
true);
1936 Counter SwitchFalse = subtractCounters(ParentCount, CaseCountSum);
1937 createBranchRegion(S->
getCond(), CaseCountSum, SwitchFalse);
1941 void VisitSwitchCase(
const SwitchCase *S) {
1944 SourceMappingRegion &Parent =
getRegion();
1946 ? getRegionCounter(S)
1947 : addCounters(Parent.getCounter(), getRegionCounter(S));
1951 if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
1952 Parent.setCounter(Count);
1954 pushRegion(Count, getStart(S));
1956 GapRegionCounter = Count;
1958 if (
const auto *CS = dyn_cast<CaseStmt>(S)) {
1959 Visit(CS->getLHS());
1960 if (
const Expr *RHS = CS->getRHS())
1966 void coverIfConsteval(
const IfStmt *S) {
1969 const auto *Then = S->
getThen();
1970 const auto *Else = S->
getElse();
1975 const Counter ParentCount =
getRegion().getCounter();
1981 markSkipped(S->
getIfLoc(), getStart(Then));
1982 propagateCounts(ParentCount, Then);
1986 markSkipped(getEnd(Then), getEnd(Else));
1991 markSkipped(S->
getIfLoc(), Else ? getStart(Else) : getEnd(Then));
1994 propagateCounts(ParentCount, Else);
1998 void coverIfConstexpr(
const IfStmt *S) {
2011 const Counter ParentCount =
getRegion().getCounter();
2014 SourceLocation startOfSkipped = S->
getIfLoc();
2017 const auto start = getStart(
Init);
2018 const auto end = getEnd(
Init);
2022 if (start.isValid() && end.isValid()) {
2023 markSkipped(startOfSkipped, start);
2024 propagateCounts(ParentCount,
Init);
2025 startOfSkipped = getEnd(
Init);
2029 const auto *Then = S->
getThen();
2030 const auto *Else = S->
getElse();
2034 markSkipped(startOfSkipped, getStart(Then));
2035 propagateCounts(ParentCount, Then);
2039 markSkipped(getEnd(Then), getEnd(Else));
2042 markSkipped(startOfSkipped, Else ? getStart(Else) : getEnd(Then));
2045 propagateCounts(ParentCount, Else);
2049 void VisitIfStmt(
const IfStmt *S) {
2053 return coverIfConsteval(S);
2055 return coverIfConstexpr(S);
2065 Counter ParentCount =
getRegion().getCounter();
2066 auto [ThenCount, ElseCount] =
2068 ? BranchCounterPair{getRegionCounter(S->
getThen()),
2070 : Counter::getZero())}
2071 : getBranchCounterPair(S, ParentCount));
2075 propagateCounts(ParentCount, S->
getCond());
2078 std::optional<SourceRange> Gap =
2081 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
2084 Counter OutCount = propagateCounts(ThenCount, S->
getThen());
2086 if (
const Stmt *Else = S->
getElse()) {
2087 bool ThenHasTerminateStmt = HasTerminateStmt;
2088 HasTerminateStmt =
false;
2090 std::optional<SourceRange> Gap =
2091 findGapAreaBetween(getEnd(S->
getThen()), getStart(Else));
2093 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
2096 Counter ElseOutCount = propagateCounts(ElseCount, Else);
2098 OutCount = addCounters(OutCount, ElseOutCount);
2100 if (ThenHasTerminateStmt)
2101 HasTerminateStmt =
true;
2103 OutCount = addCounters(OutCount, ElseCount);
2106 OutCount = getRegionCounter(S);
2108 if (!IsCounterEqual(OutCount, ParentCount)) {
2109 pushRegion(OutCount);
2110 GapRegionCounter = OutCount;
2115 createBranchRegion(S->
getCond(), ThenCount, ElseCount);
2118 void VisitCXXTryStmt(
const CXXTryStmt *S) {
2123 Counter ParentCount =
getRegion().getCounter();
2129 Counter ExitCount = getRegionCounter(S);
2130 pushRegion(ExitCount);
2133 void VisitCXXCatchStmt(
const CXXCatchStmt *S) {
2137 void VisitAbstractConditionalOperator(
const AbstractConditionalOperator *E) {
2140 Counter ParentCount =
getRegion().getCounter();
2141 auto [TrueCount, FalseCount] =
2143 ? BranchCounterPair{getRegionCounter(E->
getTrueExpr()),
2145 : getBranchCounterPair(E, ParentCount));
2148 if (
const auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) {
2149 propagateCounts(ParentCount, BCO->getCommon());
2150 OutCount = TrueCount;
2152 propagateCounts(ParentCount, E->
getCond());
2157 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
2160 OutCount = propagateCounts(TrueCount, E->
getTrueExpr());
2164 Counter FalseOutCount = propagateCounts(FalseCount, E->
getFalseExpr());
2166 OutCount = getRegionCounter(E);
2168 OutCount = addCounters(OutCount, FalseOutCount);
2170 if (!IsCounterEqual(OutCount, ParentCount)) {
2171 pushRegion(OutCount);
2172 GapRegionCounter = OutCount;
2177 createBranchRegion(E->
getCond(), TrueCount, FalseCount);
2180 void createOrCancelDecision(
const BinaryOperator *E,
unsigned Since) {
2181 unsigned NumConds = MCDCBuilder.getTotalConditionsAndReset(E);
2186 llvm::SmallVector<mcdc::ConditionIDs> CondIDs(NumConds);
2187 for (
const auto &SR : ArrayRef(SourceRegions).slice(Since)) {
2188 if (SR.isMCDCBranch()) {
2189 auto [
ID, Conds] = SR.getMCDCBranchParams();
2190 CondIDs[
ID] = Conds;
2195 mcdc::TVIdxBuilder Builder(CondIDs);
2196 unsigned NumTVs = Builder.NumTestVectors;
2198 assert(MaxTVs < mcdc::TVIdxBuilder::HardMaxTVs);
2200 if (NumTVs > MaxTVs) {
2202 cancelDecision(E, Since, NumTVs, MaxTVs);
2210 std::move(Builder.Indices),
2213 auto DecisionParams = mcdc::DecisionParameters{
2219 createDecisionRegion(E, DecisionParams);
2223 void cancelDecision(
const BinaryOperator *E,
unsigned Since,
int NumTVs,
2228 "unsupported MC/DC boolean expression; "
2229 "number of test vectors (%0) exceeds max (%1). "
2230 "Expression will not be covered");
2234 for (
auto &SR : MutableArrayRef(SourceRegions).slice(Since)) {
2235 assert(!SR.isMCDCDecision() &&
"Decision shouldn't be seen here");
2236 if (SR.isMCDCBranch())
2237 SR.resetMCDCParams();
2245 bool isExprInSystemHeader(
const BinaryOperator *E)
const {
2252 void VisitBinLAnd(
const BinaryOperator *E) {
2253 if (isExprInSystemHeader(E)) {
2254 LeafExprSet.insert(E);
2258 bool IsRootNode = MCDCBuilder.isIdle();
2260 unsigned SourceRegionsSince = SourceRegions.size();
2263 MCDCBuilder.pushAndAssignIDs(E);
2265 extendRegion(E->
getLHS());
2267 handleFileExit(getEnd(E->
getLHS()));
2270 const auto DecisionLHS = MCDCBuilder.pop();
2273 findGapAreaBetween(getEnd(E->
getLHS()), getStart(E->
getRHS()))) {
2274 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));
2278 extendRegion(E->
getRHS());
2279 propagateCounts(getRegionCounter(E), E->
getRHS());
2285 const auto DecisionRHS = MCDCBuilder.back();
2288 Counter ParentCnt =
getRegion().getCounter();
2291 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2294 auto [RHSTrueCnt, RHSExitCnt] =
2295 getBranchCounterPair(E->
getRHS(), RHSExecCnt);
2298 createBranchRegion(E->
getLHS(), RHSExecCnt, LHSExitCnt, DecisionLHS);
2301 createBranchRegion(E->
getRHS(), RHSTrueCnt, RHSExitCnt, DecisionRHS);
2305 createOrCancelDecision(E, SourceRegionsSince);
2309 bool shouldVisitRHS(
const Expr *LHS) {
2310 bool LHSIsTrue =
false;
2311 bool LHSIsConst =
false;
2315 return !LHSIsConst || (LHSIsConst && !LHSIsTrue);
2318 void VisitBinLOr(
const BinaryOperator *E) {
2319 if (isExprInSystemHeader(E)) {
2320 LeafExprSet.insert(E);
2324 bool IsRootNode = MCDCBuilder.isIdle();
2326 unsigned SourceRegionsSince = SourceRegions.size();
2329 MCDCBuilder.pushAndAssignIDs(E);
2331 extendRegion(E->
getLHS());
2332 Counter OutCount = propagateCounts(
getRegion().getCounter(), E->
getLHS());
2333 handleFileExit(getEnd(E->
getLHS()));
2336 const auto DecisionLHS = MCDCBuilder.pop();
2339 findGapAreaBetween(getEnd(E->
getLHS()), getStart(E->
getRHS()))) {
2340 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));
2344 extendRegion(E->
getRHS());
2345 propagateCounts(getRegionCounter(E), E->
getRHS());
2351 const auto DecisionRHS = MCDCBuilder.back();
2354 Counter ParentCnt =
getRegion().getCounter();
2357 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2360 auto [RHSFalseCnt, RHSExitCnt] =
2361 getBranchCounterPair(E->
getRHS(), RHSExecCnt);
2363 if (!shouldVisitRHS(E->
getLHS())) {
2364 GapRegionCounter = OutCount;
2368 createBranchRegion(E->
getLHS(), LHSExitCnt, RHSExecCnt, DecisionLHS);
2371 createBranchRegion(E->
getRHS(), RHSExitCnt, RHSFalseCnt, DecisionRHS);
2375 createOrCancelDecision(E, SourceRegionsSince);
2383 void VisitArrayInitLoopExpr(
const ArrayInitLoopExpr *AILE) {
2387 void VisitPseudoObjectExpr(
const PseudoObjectExpr *POE) {
2392 void VisitOpaqueValueExpr(
const OpaqueValueExpr* OVE) {
2400static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
2403 OS << FunctionName <<
":\n";
2404 CounterMappingContext Ctx(Expressions);
2405 for (
const auto &R : Regions) {
2408 case CounterMappingRegion::CodeRegion:
2410 case CounterMappingRegion::ExpansionRegion:
2413 case CounterMappingRegion::SkippedRegion:
2416 case CounterMappingRegion::GapRegion:
2419 case CounterMappingRegion::BranchRegion:
2420 case CounterMappingRegion::MCDCBranchRegion:
2423 case CounterMappingRegion::MCDCDecisionRegion:
2428 OS <<
"File " << R.FileID <<
", " << R.LineStart <<
":" << R.ColumnStart
2429 <<
" -> " << R.LineEnd <<
":" << R.ColumnEnd <<
" = ";
2431 if (
const auto *DecisionParams =
2432 std::get_if<mcdc::DecisionParameters>(&R.MCDCParams)) {
2433 OS <<
"M:" << DecisionParams->BitmapIdx;
2434 OS <<
", C:" << DecisionParams->NumConditions;
2436 Ctx.dump(R.Count, OS);
2440 Ctx.dump(R.FalseCount, OS);
2444 if (
const auto *BranchParams =
2445 std::get_if<mcdc::BranchParameters>(&R.MCDCParams)) {
2446 OS <<
" [" << BranchParams->ID + 1 <<
","
2447 << BranchParams->Conds[
true] + 1;
2448 OS <<
"," << BranchParams->Conds[
false] + 1 <<
"] ";
2451 if (R.Kind == CounterMappingRegion::ExpansionRegion)
2452 OS <<
" (Expanded file = " << R.ExpandedFileID <<
")";
2459 : CGM(CGM), SourceInfo(SourceInfo) {}
2461std::string CoverageMappingModuleGen::getCurrentDirname() {
2465std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
2467 llvm::sys::path::remove_dots(Path,
true);
2472 for (
const auto &[From, To] :
2474 if (llvm::sys::path::replace_path_prefix(Path, From, To))
2477 return Path.str().str();
2481 llvm::InstrProfSectKind SK) {
2482 return llvm::getInstrProfSectionName(
2486void CoverageMappingModuleGen::emitFunctionMappingRecord(
2487 const FunctionInfo &Info, uint64_t FilenamesRef) {
2488 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
2491 std::string FuncRecordName =
"__covrec_" + llvm::utohexstr(Info.NameHash);
2498 FuncRecordName +=
"u";
2501 const uint64_t NameHash = Info.NameHash;
2502 const uint64_t FuncHash = Info.FuncHash;
2503 const std::string &CoverageMapping = Info.CoverageMapping;
2504#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
2505 llvm::Type *FunctionRecordTypes[] = {
2506#include "llvm/ProfileData/InstrProfData.inc"
2508 auto *FunctionRecordTy =
2509 llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes),
2513#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
2514 llvm::Constant *FunctionRecordVals[] = {
2515 #include "llvm/ProfileData/InstrProfData.inc"
2517 auto *FuncRecordConstant =
2518 llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals));
2521 auto *FuncRecord =
new llvm::GlobalVariable(
2522 CGM.getModule(), FunctionRecordTy,
true,
2523 llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
2525 FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
2527 FuncRecord->setAlignment(llvm::Align(8));
2528 if (CGM.supportsCOMDAT())
2529 FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
2532 CGM.addUsedGlobal(FuncRecord);
2536 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
2537 const std::string &CoverageMapping,
bool IsUsed) {
2538 const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
2539 FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
2542 FunctionNames.push_back(NamePtr);
2544 if (CGM.getCodeGenOpts().DumpCoverageMapping) {
2551 std::vector<StringRef> Filenames;
2552 std::vector<CounterExpression> Expressions;
2553 std::vector<CounterMappingRegion> Regions;
2554 FilenameStrs.resize(FileEntries.size() + 1);
2555 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2556 for (
const auto &Entry : FileEntries) {
2557 auto I = Entry.second;
2558 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2561 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
2562 Expressions, Regions);
2565 dump(llvm::outs(), NameValue, Expressions, Regions);
2570 if (FunctionRecords.empty())
2572 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
2573 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
2577 FilenameStrs.resize(FileEntries.size() + 1);
2579 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2580 for (
const auto &Entry : FileEntries) {
2581 auto I = Entry.second;
2582 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2585 std::string Filenames;
2587 llvm::raw_string_ostream OS(Filenames);
2588 CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
2590 auto *FilenamesVal =
2591 llvm::ConstantDataArray::getString(Ctx, Filenames,
false);
2592 const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
2595 for (
const FunctionInfo &Info : FunctionRecords)
2596 emitFunctionMappingRecord(Info, FilenamesRef);
2598 const unsigned NRecords = 0;
2599 const size_t FilenamesSize = Filenames.size();
2600 const unsigned CoverageMappingSize = 0;
2601 llvm::Type *CovDataHeaderTypes[] = {
2602#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
2603#include "llvm/ProfileData/InstrProfData.inc"
2605 auto CovDataHeaderTy =
2606 llvm::StructType::get(Ctx,
ArrayRef(CovDataHeaderTypes));
2607 llvm::Constant *CovDataHeaderVals[] = {
2608#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
2609#include "llvm/ProfileData/InstrProfData.inc"
2611 auto CovDataHeaderVal =
2612 llvm::ConstantStruct::get(CovDataHeaderTy,
ArrayRef(CovDataHeaderVals));
2615 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
2616 auto CovDataTy = llvm::StructType::get(Ctx,
ArrayRef(CovDataTypes));
2617 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
2618 auto CovDataVal = llvm::ConstantStruct::get(CovDataTy,
ArrayRef(TUDataVals));
2619 auto CovData =
new llvm::GlobalVariable(
2620 CGM.getModule(), CovDataTy,
true, llvm::GlobalValue::PrivateLinkage,
2621 CovDataVal, llvm::getCoverageMappingVarName());
2624 CovData->setAlignment(llvm::Align(8));
2627 CGM.addUsedGlobal(CovData);
2629 if (!FunctionNames.empty()) {
2630 auto AddrSpace = FunctionNames.front()->getType()->getPointerAddressSpace();
2631 auto NamesArrTy = llvm::ArrayType::get(
2632 llvm::PointerType::get(Ctx, AddrSpace), FunctionNames.size());
2633 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
2636 new llvm::GlobalVariable(CGM.getModule(), NamesArrTy,
true,
2637 llvm::GlobalValue::InternalLinkage, NamesArrVal,
2638 llvm::getCoverageUnusedNamesVarName());
2643 return FileEntries.try_emplace(
File, FileEntries.size() + 1).first->second;
2647 llvm::raw_ostream &OS) {
2648 assert(CounterMap && MCDCState);
2649 CounterCoverageMappingBuilder Walker(CVM, *CounterMap, *MCDCState, SM,
2651 Walker.VisitDecl(D);
2656 llvm::raw_ostream &OS) {
2657 EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
2658 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, SmallVectorImpl< PartialDiagnosticAt > *Diag=nullptr) 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