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/ProfileData/InstrProfReader.h"
26#include "llvm/Support/FileSystem.h"
27#include "llvm/Support/Path.h"
35 "emptyline-comment-coverage",
36 llvm::cl::desc(
"Emit emptylines and comment lines as skipped regions (only "
37 "disable it on test)"),
38 llvm::cl::init(
true), llvm::cl::Hidden);
41 "system-headers-coverage",
42 llvm::cl::desc(
"Enable collecting coverage from system headers"),
43 llvm::cl::init(
false), llvm::cl::Hidden);
46using namespace CodeGen;
47using namespace llvm::coverage;
61 if (Tok.
getKind() != clang::tok::eod)
71 PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
72 SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
74 SkippedRanges.back().Range.setEnd(Range.getEnd());
76 SkippedRanges.push_back({Range, RangeKind, PrevTokLoc});
93 if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
94 SkippedRanges.back().NextTokLoc = Loc;
100class SourceMappingRegion {
105 std::optional<Counter> FalseCount;
108 std::optional<SourceLocation> LocStart;
111 std::optional<SourceLocation> LocEnd;
118 SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart,
119 std::optional<SourceLocation> LocEnd,
120 bool GapRegion =
false)
121 : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) {
124 SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount,
125 std::optional<SourceLocation> LocStart,
126 std::optional<SourceLocation> LocEnd,
127 bool GapRegion =
false)
128 : Count(Count), FalseCount(FalseCount), LocStart(LocStart),
129 LocEnd(LocEnd), GapRegion(GapRegion) {}
131 const Counter &getCounter()
const {
return Count; }
133 const Counter &getFalseCounter()
const {
134 assert(FalseCount &&
"Region has no alternate counter");
138 void setCounter(Counter
C) { Count =
C; }
140 bool hasStartLoc()
const {
return LocStart.has_value(); }
145 assert(LocStart &&
"Region has no start location");
149 bool hasEndLoc()
const {
return LocEnd.has_value(); }
152 assert(Loc.
isValid() &&
"Setting an invalid end location");
157 assert(LocEnd &&
"Region has no end location");
161 bool isGap()
const {
return GapRegion; }
163 void setGap(
bool Gap) { GapRegion = Gap; }
165 bool isBranch()
const {
return FalseCount.has_value(); }
169struct SpellingRegion {
174 unsigned ColumnStart;
184 LineStart =
SM.getSpellingLineNumber(LocStart);
185 ColumnStart =
SM.getSpellingColumnNumber(LocStart);
186 LineEnd =
SM.getSpellingLineNumber(LocEnd);
187 ColumnEnd =
SM.getSpellingColumnNumber(LocEnd);
191 : SpellingRegion(
SM, R.getBeginLoc(), R.getEndLoc()) {}
195 bool isInSourceOrder()
const {
196 return (LineStart < LineEnd) ||
197 (LineStart == LineEnd && ColumnStart <= ColumnEnd);
203class CoverageMappingBuilder {
211 llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
218 std::vector<SourceMappingRegion> SourceRegions;
225 typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
230 : CVM(CVM),
SM(
SM), LangOpts(LangOpts) {}
245 return SM.getLocForStartOfFile(
SM.getFileID(Loc));
252 SM.getFileOffset(Loc));
253 return SM.getLocForEndOfFile(
SM.getFileID(Loc));
258 return Loc.
isMacroID() ?
SM.getImmediateExpansionRange(Loc).getBegin()
259 :
SM.getIncludeLoc(
SM.getFileID(Loc));
264 return SM.getBufferName(
SM.getSpellingLoc(Loc)) ==
"<built-in>";
270 Loc = getIncludeOrExpansionLoc(Loc);
273 }
while (!
SM.isInFileID(Loc,
Parent));
280 while (
SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
281 Loc =
SM.getImmediateExpansionRange(Loc).getBegin();
288 while (
SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
289 Loc =
SM.getImmediateExpansionRange(Loc).getBegin();
290 return getPreciseTokenLocEnd(Loc);
299 FileIDMapping.clear();
301 llvm::SmallSet<FileID, 8>
Visited;
303 for (
const auto &Region : SourceRegions) {
318 FileLocs.push_back(std::make_pair(Loc, Depth));
320 llvm::stable_sort(FileLocs, llvm::less_second());
322 for (
const auto &FL : FileLocs) {
324 FileID SpellingFile =
SM.getDecomposedSpellingLoc(Loc).first;
325 auto Entry =
SM.getFileEntryRefForID(SpellingFile);
329 FileIDMapping[
SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
330 Mapping.push_back(CVM.
getFileID(*Entry));
338 auto Mapping = FileIDMapping.find(
SM.getFileID(Loc));
339 if (Mapping != FileIDMapping.end())
340 return Mapping->second.first;
354 SpellingRegion SR{
SM, LocStart, LocEnd};
356 if (PrevTokLoc.
isValid() &&
SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
357 SR.LineStart ==
SM.getSpellingLineNumber(PrevTokLoc))
359 if (NextTokLoc.
isValid() &&
SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
360 SR.LineEnd ==
SM.getSpellingLineNumber(NextTokLoc)) {
364 if (SR.isInSourceOrder())
371 void gatherSkippedRegions() {
375 FileLineRanges.resize(
376 FileIDMapping.size(),
377 std::make_pair(std::numeric_limits<unsigned>::max(), 0));
378 for (
const auto &R : MappingRegions) {
379 FileLineRanges[R.FileID].first =
380 std::min(FileLineRanges[R.FileID].first, R.LineStart);
381 FileLineRanges[R.FileID].second =
382 std::max(FileLineRanges[R.FileID].second, R.LineEnd);
386 for (
auto &I : SkippedRanges) {
388 auto LocStart =
Range.getBegin();
389 auto LocEnd =
Range.getEnd();
390 assert(
SM.isWrittenInSameFile(LocStart, LocEnd) &&
391 "region spans multiple files");
393 auto CovFileID = getCoverageFileID(LocStart);
396 std::optional<SpellingRegion> SR;
398 SR = adjustSkippedRange(
SM, LocStart, LocEnd, I.PrevTokLoc,
400 else if (I.isPPIfElse() || I.isEmptyLine())
401 SR = {
SM, LocStart, LocEnd};
405 auto Region = CounterMappingRegion::makeSkipped(
406 *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
410 if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
411 Region.LineEnd <= FileLineRanges[*CovFileID].second)
412 MappingRegions.push_back(Region);
418 void emitSourceRegions(
const SourceRegionFilter &Filter) {
419 for (
const auto &Region : SourceRegions) {
420 assert(Region.hasEndLoc() &&
"incomplete region");
423 assert(
SM.getFileID(LocStart).isValid() &&
"region in invalid file");
428 SM.isInSystemHeader(
SM.getSpellingLoc(LocStart)))
431 auto CovFileID = getCoverageFileID(LocStart);
437 assert(
SM.isWrittenInSameFile(LocStart, LocEnd) &&
438 "region spans multiple files");
444 if (
Filter.count(std::make_pair(LocStart, LocEnd)))
448 SpellingRegion SR{
SM, LocStart, LocEnd};
449 assert(SR.isInSourceOrder() &&
"region start and end out of order");
451 if (Region.isGap()) {
452 MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
453 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
454 SR.LineEnd, SR.ColumnEnd));
455 }
else if (Region.isBranch()) {
456 MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
457 Region.getCounter(), Region.getFalseCounter(), *CovFileID,
458 SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
460 MappingRegions.push_back(CounterMappingRegion::makeRegion(
461 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
462 SR.LineEnd, SR.ColumnEnd));
468 SourceRegionFilter emitExpansionRegions() {
469 SourceRegionFilter
Filter;
470 for (
const auto &FM : FileIDMapping) {
476 auto ParentFileID = getCoverageFileID(ParentLoc);
479 auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
480 assert(ExpandedFileID &&
"expansion in uncovered file");
483 assert(
SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
484 "region spans multiple files");
485 Filter.insert(std::make_pair(ParentLoc, LocEnd));
487 SpellingRegion SR{
SM, ParentLoc, LocEnd};
488 assert(SR.isInSourceOrder() &&
"region start and end out of order");
489 MappingRegions.push_back(CounterMappingRegion::makeExpansion(
490 *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
491 SR.LineEnd, SR.ColumnEnd));
499struct EmptyCoverageMappingBuilder :
public CoverageMappingBuilder {
502 : CoverageMappingBuilder(CVM,
SM, LangOpts) {}
504 void VisitDecl(
const Decl *D) {
510 if (!
SM.isWrittenInSameFile(Start, End)) {
513 FileID StartFileID =
SM.getFileID(Start);
514 FileID EndFileID =
SM.getFileID(End);
515 while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
516 Start = getIncludeOrExpansionLoc(Start);
518 "Declaration start location not nested within a known region");
519 StartFileID =
SM.getFileID(Start);
521 while (StartFileID != EndFileID) {
522 End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
523 assert(End.isValid() &&
524 "Declaration end location not nested within a known region");
525 EndFileID =
SM.getFileID(End);
528 SourceRegions.emplace_back(Counter(), Start, End);
532 void write(llvm::raw_ostream &OS) {
534 gatherFileIDs(FileIDMapping);
535 emitSourceRegions(SourceRegionFilter());
537 if (MappingRegions.empty())
540 CoverageMappingWriter Writer(FileIDMapping, std::nullopt, MappingRegions);
547struct CounterCoverageMappingBuilder
548 :
public CoverageMappingBuilder,
551 llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
554 std::vector<SourceMappingRegion> RegionStack;
556 CounterExpressionBuilder Builder;
565 bool HasTerminateStmt =
false;
568 Counter GapRegionCounter;
571 Counter subtractCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
572 return Builder.subtract(LHS, RHS, Simplify);
576 Counter addCounters(Counter LHS, Counter RHS,
bool Simplify =
true) {
577 return Builder.add(LHS, RHS, Simplify);
580 Counter addCounters(Counter C1, Counter C2, Counter C3,
581 bool Simplify =
true) {
582 return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
588 Counter getRegionCounter(
const Stmt *S) {
589 return Counter::getCounter(CounterMap[S]);
596 size_t pushRegion(Counter Count,
597 std::optional<SourceLocation> StartLoc = std::nullopt,
598 std::optional<SourceLocation> EndLoc = std::nullopt,
599 std::optional<Counter> FalseCount = std::nullopt) {
601 if (StartLoc && !FalseCount) {
602 MostRecentLocation = *StartLoc;
607 assert((!StartLoc || StartLoc->isValid()) &&
"Start location is not valid");
608 assert((!EndLoc || EndLoc->isValid()) &&
"End location is not valid");
614 if (StartLoc && StartLoc->isInvalid())
615 StartLoc = std::nullopt;
616 if (EndLoc && EndLoc->isInvalid())
617 EndLoc = std::nullopt;
618 RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc);
620 return RegionStack.size() - 1;
626 Loc = getIncludeOrExpansionLoc(Loc);
636 void popRegions(
size_t ParentIndex) {
637 assert(RegionStack.size() >= ParentIndex &&
"parent not in stack");
638 while (RegionStack.size() > ParentIndex) {
639 SourceMappingRegion &Region = RegionStack.back();
640 if (Region.hasStartLoc() &&
641 (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) {
645 : RegionStack[ParentIndex].getEndLoc();
646 bool isBranch = Region.isBranch();
647 size_t StartDepth = locationDepth(StartLoc);
648 size_t EndDepth = locationDepth(EndLoc);
649 while (!
SM.isWrittenInSameFile(StartLoc, EndLoc)) {
650 bool UnnestStart = StartDepth >= EndDepth;
651 bool UnnestEnd = EndDepth >= StartDepth;
660 assert(
SM.isWrittenInSameFile(NestedLoc, EndLoc));
662 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
663 SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
666 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
668 llvm::report_fatal_error(
669 "File exit not handled before popRegions");
680 assert(
SM.isWrittenInSameFile(StartLoc, NestedLoc));
682 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
683 SourceRegions.emplace_back(Region.getCounter(), StartLoc,
686 StartLoc = getIncludeOrExpansionLoc(StartLoc);
688 llvm::report_fatal_error(
689 "File exit not handled before popRegions");
693 Region.setStartLoc(StartLoc);
694 Region.setEndLoc(EndLoc);
697 MostRecentLocation = EndLoc;
700 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
701 EndLoc == getEndOfFileOrMacro(EndLoc))
702 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
705 assert(
SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
706 assert(SpellingRegion(
SM, Region).isInSourceOrder());
707 SourceRegions.push_back(Region);
709 RegionStack.pop_back();
714 SourceMappingRegion &getRegion() {
715 assert(!RegionStack.empty() &&
"statement has no region");
716 return RegionStack.back();
721 Counter propagateCounts(Counter TopCount,
const Stmt *S,
722 bool VisitChildren =
true) {
725 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
728 Counter ExitCount = getRegion().getCounter();
733 if (
SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
734 MostRecentLocation = EndLoc;
740 bool ConditionFoldsToBool(
const Expr *Cond) {
749 void createBranchRegion(
const Expr *
C, Counter TrueCnt, Counter FalseCnt) {
758 if (CodeGenFunction::isInstrumentedCondition(
C)) {
765 if (ConditionFoldsToBool(
C))
766 popRegions(pushRegion(Counter::getZero(), getStart(
C), getEnd(
C),
767 Counter::getZero()));
770 popRegions(pushRegion(TrueCnt, getStart(
C), getEnd(
C), FalseCnt));
776 void createSwitchCaseRegion(
const SwitchCase *SC, Counter TrueCnt,
781 popRegions(pushRegion(TrueCnt, getStart(SC), SC->
getColonLoc(), FalseCnt));
787 bool isBranch =
false) {
789 llvm::reverse(SourceRegions), [&](
const SourceMappingRegion &Region) {
790 return Region.getBeginLoc() == StartLoc &&
791 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
799 MostRecentLocation = EndLoc;
805 if (getRegion().hasEndLoc() &&
806 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
807 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
808 MostRecentLocation, getRegion().isBranch()))
809 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
819 SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
825 FileID ParentFile =
SM.getFileID(LCA);
826 while (!isNestedIn(MostRecentLocation, ParentFile)) {
827 LCA = getIncludeOrExpansionLoc(LCA);
828 if (LCA.
isInvalid() ||
SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
831 MostRecentLocation = NewLoc;
834 ParentFile =
SM.getFileID(LCA);
837 llvm::SmallSet<SourceLocation, 8> StartLocs;
838 std::optional<Counter> ParentCounter;
839 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
840 if (!I.hasStartLoc())
843 if (!isNestedIn(Loc, ParentFile)) {
844 ParentCounter = I.getCounter();
848 while (!
SM.isInFileID(Loc, ParentFile)) {
852 if (StartLocs.insert(Loc).second) {
854 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), Loc,
855 getEndOfFileOrMacro(Loc), I.isBranch());
857 SourceRegions.emplace_back(I.getCounter(), Loc,
858 getEndOfFileOrMacro(Loc));
860 Loc = getIncludeOrExpansionLoc(Loc);
862 I.setStartLoc(getPreciseTokenLocEnd(Loc));
870 while (isNestedIn(Loc, ParentFile)) {
872 if (StartLocs.insert(FileStart).second) {
873 SourceRegions.emplace_back(*ParentCounter, FileStart,
874 getEndOfFileOrMacro(Loc));
875 assert(SpellingRegion(
SM, SourceRegions.back()).isInSourceOrder());
877 Loc = getIncludeOrExpansionLoc(Loc);
881 MostRecentLocation = NewLoc;
885 void extendRegion(
const Stmt *S) {
886 SourceMappingRegion &Region = getRegion();
889 handleFileExit(StartLoc);
890 if (!Region.hasStartLoc())
891 Region.setStartLoc(StartLoc);
895 void terminateRegion(
const Stmt *S) {
897 SourceMappingRegion &Region = getRegion();
899 if (!Region.hasEndLoc())
900 Region.setEndLoc(EndLoc);
901 pushRegion(Counter::getZero());
902 HasTerminateStmt =
true;
906 std::optional<SourceRange> findGapAreaBetween(
SourceLocation AfterLoc,
911 FileID FID =
SM.getFileID(AfterLoc);
917 size_t StartDepth = locationDepth(AfterLoc);
918 size_t EndDepth = locationDepth(BeforeLoc);
919 while (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
920 bool UnnestStart = StartDepth >= EndDepth;
921 bool UnnestEnd = EndDepth >= StartDepth;
923 assert(
SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
926 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
931 assert(
SM.isWrittenInSameFile(AfterLoc,
932 getEndOfFileOrMacro(AfterLoc)));
934 AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
936 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
941 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
946 if (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
947 !SpellingRegion(
SM, AfterLoc, BeforeLoc).isInSourceOrder())
949 return {{AfterLoc, BeforeLoc}};
955 if (StartLoc == EndLoc)
957 assert(SpellingRegion(
SM, StartLoc, EndLoc).isInSourceOrder());
958 handleFileExit(StartLoc);
959 size_t Index = pushRegion(Count, StartLoc, EndLoc);
960 getRegion().setGap(
true);
961 handleFileExit(EndLoc);
966 struct BreakContinue {
968 Counter ContinueCount;
972 CounterCoverageMappingBuilder(
976 : CoverageMappingBuilder(CVM,
SM, LangOpts), CounterMap(CounterMap) {}
979 void write(llvm::raw_ostream &OS) {
981 gatherFileIDs(VirtualFileMapping);
982 SourceRegionFilter
Filter = emitExpansionRegions();
983 emitSourceRegions(Filter);
984 gatherSkippedRegions();
986 if (MappingRegions.empty())
989 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
994 void VisitStmt(
const Stmt *S) {
995 if (S->getBeginLoc().isValid())
997 const Stmt *LastStmt =
nullptr;
998 bool SaveTerminateStmt = HasTerminateStmt;
999 HasTerminateStmt =
false;
1000 GapRegionCounter = Counter::getZero();
1001 for (
const Stmt *Child : S->children())
1006 if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) {
1007 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
1009 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
1011 SaveTerminateStmt =
true;
1012 HasTerminateStmt =
false;
1017 if (SaveTerminateStmt)
1018 HasTerminateStmt =
true;
1019 handleFileExit(getEnd(S));
1022 void VisitDecl(
const Decl *D) {
1028 SM.isInSystemHeader(
SM.getSpellingLoc(getStart(Body))))
1035 Counter BodyCounter = getRegionCounter(Body);
1037 if (
auto *Method = dyn_cast<CXXMethodDecl>(D))
1039 if (
auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
1043 if (getStart(
Init).isValid() && getEnd(
Init).isValid())
1044 propagateCounts(BodyCounter,
Init);
1049 propagateCounts(BodyCounter, Body,
1051 assert(RegionStack.empty() &&
"Regions entered but never exited");
1056 if (S->getRetValue())
1057 Visit(S->getRetValue());
1063 Visit(S->getBody());
1068 if (S->getOperand())
1069 Visit(S->getOperand());
1080 void VisitGotoStmt(
const GotoStmt *S) { terminateRegion(S); }
1082 void VisitLabelStmt(
const LabelStmt *S) {
1083 Counter LabelCount = getRegionCounter(S);
1086 handleFileExit(Start);
1087 pushRegion(LabelCount, Start);
1088 Visit(S->getSubStmt());
1091 void VisitBreakStmt(
const BreakStmt *S) {
1092 assert(!BreakContinueStack.empty() &&
"break not in a loop or switch!");
1093 BreakContinueStack.back().BreakCount = addCounters(
1094 BreakContinueStack.back().BreakCount, getRegion().getCounter());
1101 assert(!BreakContinueStack.empty() &&
"continue stmt not in a loop!");
1102 BreakContinueStack.back().ContinueCount = addCounters(
1103 BreakContinueStack.back().ContinueCount, getRegion().getCounter());
1107 void VisitCallExpr(
const CallExpr *E) {
1117 void VisitWhileStmt(
const WhileStmt *S) {
1120 Counter ParentCount = getRegion().getCounter();
1121 Counter BodyCount = getRegionCounter(S);
1124 BreakContinueStack.push_back(BreakContinue());
1125 extendRegion(S->getBody());
1126 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1127 BreakContinue BC = BreakContinueStack.pop_back_val();
1129 bool BodyHasTerminateStmt = HasTerminateStmt;
1130 HasTerminateStmt =
false;
1134 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1135 propagateCounts(CondCount, S->getCond());
1136 adjustForOutOfOrderTraversal(getEnd(S));
1139 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1141 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1144 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1145 if (OutCount != ParentCount) {
1146 pushRegion(OutCount);
1147 GapRegionCounter = OutCount;
1148 if (BodyHasTerminateStmt)
1149 HasTerminateStmt =
true;
1153 createBranchRegion(S->getCond(), BodyCount,
1154 subtractCounters(CondCount, BodyCount));
1157 void VisitDoStmt(
const DoStmt *S) {
1160 Counter ParentCount = getRegion().getCounter();
1161 Counter BodyCount = getRegionCounter(S);
1163 BreakContinueStack.push_back(BreakContinue());
1164 extendRegion(S->getBody());
1165 Counter BackedgeCount =
1166 propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
1167 BreakContinue BC = BreakContinueStack.pop_back_val();
1169 bool BodyHasTerminateStmt = HasTerminateStmt;
1170 HasTerminateStmt =
false;
1172 Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
1173 propagateCounts(CondCount, S->getCond());
1176 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1177 if (OutCount != ParentCount) {
1178 pushRegion(OutCount);
1179 GapRegionCounter = OutCount;
1183 createBranchRegion(S->getCond(), BodyCount,
1184 subtractCounters(CondCount, BodyCount));
1186 if (BodyHasTerminateStmt)
1187 HasTerminateStmt =
true;
1190 void VisitForStmt(
const ForStmt *S) {
1193 Visit(S->getInit());
1195 Counter ParentCount = getRegion().getCounter();
1196 Counter BodyCount = getRegionCounter(S);
1200 BreakContinueStack.emplace_back();
1203 BreakContinueStack.emplace_back();
1204 extendRegion(S->getBody());
1205 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1206 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1208 bool BodyHasTerminateStmt = HasTerminateStmt;
1209 HasTerminateStmt =
false;
1213 BreakContinue IncrementBC;
1214 if (
const Stmt *Inc = S->getInc()) {
1215 propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
1216 IncrementBC = BreakContinueStack.pop_back_val();
1220 Counter CondCount = addCounters(
1221 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1222 IncrementBC.ContinueCount);
1223 if (
const Expr *Cond = S->getCond()) {
1224 propagateCounts(CondCount, Cond);
1225 adjustForOutOfOrderTraversal(getEnd(S));
1229 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1231 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1233 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1234 subtractCounters(CondCount, BodyCount));
1235 if (OutCount != ParentCount) {
1236 pushRegion(OutCount);
1237 GapRegionCounter = OutCount;
1238 if (BodyHasTerminateStmt)
1239 HasTerminateStmt =
true;
1243 createBranchRegion(S->getCond(), BodyCount,
1244 subtractCounters(CondCount, BodyCount));
1250 Visit(S->getInit());
1251 Visit(S->getLoopVarStmt());
1252 Visit(S->getRangeStmt());
1254 Counter ParentCount = getRegion().getCounter();
1255 Counter BodyCount = getRegionCounter(S);
1257 BreakContinueStack.push_back(BreakContinue());
1258 extendRegion(S->getBody());
1259 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1260 BreakContinue BC = BreakContinueStack.pop_back_val();
1262 bool BodyHasTerminateStmt = HasTerminateStmt;
1263 HasTerminateStmt =
false;
1266 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1268 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1271 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1273 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1274 if (OutCount != ParentCount) {
1275 pushRegion(OutCount);
1276 GapRegionCounter = OutCount;
1277 if (BodyHasTerminateStmt)
1278 HasTerminateStmt =
true;
1282 createBranchRegion(S->getCond(), BodyCount,
1283 subtractCounters(LoopCount, BodyCount));
1288 Visit(S->getElement());
1290 Counter ParentCount = getRegion().getCounter();
1291 Counter BodyCount = getRegionCounter(S);
1293 BreakContinueStack.push_back(BreakContinue());
1294 extendRegion(S->getBody());
1295 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1296 BreakContinue BC = BreakContinueStack.pop_back_val();
1299 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1301 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1304 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1306 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1307 if (OutCount != ParentCount) {
1308 pushRegion(OutCount);
1309 GapRegionCounter = OutCount;
1316 Visit(S->getInit());
1317 Visit(S->getCond());
1319 BreakContinueStack.push_back(BreakContinue());
1321 const Stmt *Body = S->getBody();
1323 if (
const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1324 if (!CS->body_empty()) {
1328 size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1329 getRegion().setGap(
true);
1333 for (
size_t i = RegionStack.size(); i != Index; --i) {
1334 if (!RegionStack[i - 1].hasEndLoc())
1335 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1341 propagateCounts(Counter::getZero(), Body);
1342 BreakContinue BC = BreakContinueStack.pop_back_val();
1344 if (!BreakContinueStack.empty())
1345 BreakContinueStack.back().ContinueCount = addCounters(
1346 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1348 Counter ParentCount = getRegion().getCounter();
1349 Counter ExitCount = getRegionCounter(S);
1351 pushRegion(ExitCount);
1352 GapRegionCounter = ExitCount;
1356 MostRecentLocation = getStart(S);
1357 handleFileExit(ExitLoc);
1361 Counter CaseCountSum;
1362 bool HasDefaultCase =
false;
1363 const SwitchCase *Case = S->getSwitchCaseList();
1365 HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case);
1367 addCounters(CaseCountSum, getRegionCounter(Case),
false);
1368 createSwitchCaseRegion(
1369 Case, getRegionCounter(Case),
1370 subtractCounters(ParentCount, getRegionCounter(Case)));
1375 CaseCountSum = addCounters(CaseCountSum, Counter::getZero());
1380 if (!HasDefaultCase) {
1381 Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum);
1382 Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue);
1383 createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse);
1390 SourceMappingRegion &
Parent = getRegion();
1392 Counter Count = addCounters(
Parent.getCounter(), getRegionCounter(S));
1395 if (
Parent.hasStartLoc() &&
Parent.getBeginLoc() == getStart(S))
1396 Parent.setCounter(Count);
1398 pushRegion(Count, getStart(S));
1400 GapRegionCounter = Count;
1402 if (
const auto *CS = dyn_cast<CaseStmt>(S)) {
1403 Visit(CS->getLHS());
1404 if (
const Expr *RHS = CS->getRHS())
1407 Visit(S->getSubStmt());
1410 void VisitIfStmt(
const IfStmt *S) {
1413 Visit(S->getInit());
1417 if (!S->isConsteval())
1418 extendRegion(S->getCond());
1420 Counter ParentCount = getRegion().getCounter();
1421 Counter ThenCount = getRegionCounter(S);
1423 if (!S->isConsteval()) {
1426 propagateCounts(ParentCount, S->getCond());
1429 std::optional<SourceRange> Gap =
1430 findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
1432 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
1435 extendRegion(S->getThen());
1436 Counter OutCount = propagateCounts(ThenCount, S->getThen());
1438 Counter ElseCount = subtractCounters(ParentCount, ThenCount);
1439 if (
const Stmt *Else = S->getElse()) {
1440 bool ThenHasTerminateStmt = HasTerminateStmt;
1441 HasTerminateStmt =
false;
1443 std::optional<SourceRange> Gap =
1444 findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
1446 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
1448 OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
1450 if (ThenHasTerminateStmt)
1451 HasTerminateStmt =
true;
1453 OutCount = addCounters(OutCount, ElseCount);
1455 if (OutCount != ParentCount) {
1456 pushRegion(OutCount);
1457 GapRegionCounter = OutCount;
1460 if (!S->isConsteval()) {
1462 createBranchRegion(S->getCond(), ThenCount,
1463 subtractCounters(ParentCount, ThenCount));
1470 extendRegion(S->getTryBlock());
1472 Counter ParentCount = getRegion().getCounter();
1473 propagateCounts(ParentCount, S->getTryBlock());
1475 for (
unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
1476 Visit(S->getHandler(I));
1478 Counter ExitCount = getRegionCounter(S);
1479 pushRegion(ExitCount);
1483 propagateCounts(getRegionCounter(S), S->getHandlerBlock());
1489 Counter ParentCount = getRegion().getCounter();
1490 Counter TrueCount = getRegionCounter(E);
1492 propagateCounts(ParentCount, E->
getCond());
1495 if (!isa<BinaryConditionalOperator>(E)) {
1500 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
1503 OutCount = propagateCounts(TrueCount, E->
getTrueExpr());
1507 OutCount = addCounters(
1508 OutCount, propagateCounts(subtractCounters(ParentCount, TrueCount),
1511 if (OutCount != ParentCount) {
1512 pushRegion(OutCount);
1513 GapRegionCounter = OutCount;
1517 createBranchRegion(E->
getCond(), TrueCount,
1518 subtractCounters(ParentCount, TrueCount));
1522 extendRegion(E->
getLHS());
1523 propagateCounts(getRegion().getCounter(), E->
getLHS());
1524 handleFileExit(getEnd(E->
getLHS()));
1527 extendRegion(E->
getRHS());
1528 propagateCounts(getRegionCounter(E), E->
getRHS());
1531 Counter RHSExecCnt = getRegionCounter(E);
1534 Counter RHSTrueCnt = getRegionCounter(E->
getRHS());
1537 Counter ParentCnt = getRegion().getCounter();
1540 createBranchRegion(E->
getLHS(), RHSExecCnt,
1541 subtractCounters(ParentCnt, RHSExecCnt));
1544 createBranchRegion(E->
getRHS(), RHSTrueCnt,
1545 subtractCounters(RHSExecCnt, RHSTrueCnt));
1549 bool shouldVisitRHS(
const Expr *LHS) {
1550 bool LHSIsTrue =
false;
1551 bool LHSIsConst =
false;
1555 return !LHSIsConst || (LHSIsConst && !LHSIsTrue);
1559 extendRegion(E->
getLHS());
1560 Counter OutCount = propagateCounts(getRegion().getCounter(), E->
getLHS());
1561 handleFileExit(getEnd(E->
getLHS()));
1564 extendRegion(E->
getRHS());
1565 propagateCounts(getRegionCounter(E), E->
getRHS());
1568 Counter RHSExecCnt = getRegionCounter(E);
1571 Counter RHSFalseCnt = getRegionCounter(E->
getRHS());
1573 if (!shouldVisitRHS(E->
getLHS())) {
1574 GapRegionCounter = OutCount;
1578 Counter ParentCnt = getRegion().getCounter();
1581 createBranchRegion(E->
getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
1585 createBranchRegion(E->
getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
1606static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
1609 OS << FunctionName <<
":\n";
1610 CounterMappingContext Ctx(Expressions);
1611 for (
const auto &R : Regions) {
1614 case CounterMappingRegion::CodeRegion:
1616 case CounterMappingRegion::ExpansionRegion:
1619 case CounterMappingRegion::SkippedRegion:
1622 case CounterMappingRegion::GapRegion:
1625 case CounterMappingRegion::BranchRegion:
1630 OS <<
"File " << R.FileID <<
", " << R.LineStart <<
":" << R.ColumnStart
1631 <<
" -> " << R.LineEnd <<
":" << R.ColumnEnd <<
" = ";
1632 Ctx.dump(R.Count, OS);
1634 if (R.Kind == CounterMappingRegion::BranchRegion) {
1636 Ctx.dump(R.FalseCount, OS);
1639 if (R.Kind == CounterMappingRegion::ExpansionRegion)
1640 OS <<
" (Expanded file = " << R.ExpandedFileID <<
")";
1647 : CGM(CGM), SourceInfo(SourceInfo) {}
1649std::string CoverageMappingModuleGen::getCurrentDirname() {
1654 llvm::sys::fs::current_path(CWD);
1655 return CWD.str().str();
1658std::string CoverageMappingModuleGen::normalizeFilename(StringRef
Filename) {
1660 llvm::sys::path::remove_dots(Path,
true);
1665 for (
const auto &[From, To] :
1667 if (llvm::sys::path::replace_path_prefix(Path, From, To))
1670 return Path.str().str();
1674 llvm::InstrProfSectKind SK) {
1675 return llvm::getInstrProfSectionName(
1679void CoverageMappingModuleGen::emitFunctionMappingRecord(
1680 const FunctionInfo &Info, uint64_t FilenamesRef) {
1684 std::string FuncRecordName =
"__covrec_" + llvm::utohexstr(Info.NameHash);
1691 FuncRecordName +=
"u";
1694 const uint64_t NameHash = Info.NameHash;
1695 const uint64_t FuncHash = Info.FuncHash;
1696 const std::string &CoverageMapping = Info.CoverageMapping;
1697#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
1698 llvm::Type *FunctionRecordTypes[] = {
1699#include "llvm/ProfileData/InstrProfData.inc"
1701 auto *FunctionRecordTy =
1702 llvm::StructType::get(Ctx,
ArrayRef(FunctionRecordTypes),
1706#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
1707 llvm::Constant *FunctionRecordVals[] = {
1708 #include "llvm/ProfileData/InstrProfData.inc"
1710 auto *FuncRecordConstant =
1711 llvm::ConstantStruct::get(FunctionRecordTy,
ArrayRef(FunctionRecordVals));
1714 auto *FuncRecord =
new llvm::GlobalVariable(
1715 CGM.
getModule(), FunctionRecordTy,
true,
1716 llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
1718 FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
1720 FuncRecord->setAlignment(llvm::Align(8));
1722 FuncRecord->setComdat(CGM.
getModule().getOrInsertComdat(FuncRecordName));
1729 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
1730 const std::string &CoverageMapping,
bool IsUsed) {
1731 const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
1732 FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
1735 FunctionNames.push_back(NamePtr);
1744 std::vector<StringRef> Filenames;
1745 std::vector<CounterExpression> Expressions;
1746 std::vector<CounterMappingRegion> Regions;
1747 FilenameStrs.resize(FileEntries.size() + 1);
1748 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
1749 for (
const auto &Entry : FileEntries) {
1750 auto I = Entry.second;
1751 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
1754 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
1755 Expressions, Regions);
1758 dump(llvm::outs(), NameValue, Expressions, Regions);
1763 if (FunctionRecords.empty())
1766 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
1770 FilenameStrs.resize(FileEntries.size() + 1);
1772 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
1773 for (
const auto &Entry : FileEntries) {
1774 auto I = Entry.second;
1775 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
1778 std::string Filenames;
1780 llvm::raw_string_ostream OS(Filenames);
1781 CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
1783 auto *FilenamesVal =
1784 llvm::ConstantDataArray::getString(Ctx, Filenames,
false);
1785 const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
1788 for (
const FunctionInfo &Info : FunctionRecords)
1789 emitFunctionMappingRecord(Info, FilenamesRef);
1791 const unsigned NRecords = 0;
1792 const size_t FilenamesSize = Filenames.size();
1793 const unsigned CoverageMappingSize = 0;
1794 llvm::Type *CovDataHeaderTypes[] = {
1795#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
1796#include "llvm/ProfileData/InstrProfData.inc"
1798 auto CovDataHeaderTy =
1799 llvm::StructType::get(Ctx,
ArrayRef(CovDataHeaderTypes));
1800 llvm::Constant *CovDataHeaderVals[] = {
1801#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
1802#include "llvm/ProfileData/InstrProfData.inc"
1804 auto CovDataHeaderVal =
1805 llvm::ConstantStruct::get(CovDataHeaderTy,
ArrayRef(CovDataHeaderVals));
1808 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
1809 auto CovDataTy = llvm::StructType::get(Ctx,
ArrayRef(CovDataTypes));
1810 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
1811 auto CovDataVal = llvm::ConstantStruct::get(CovDataTy,
ArrayRef(TUDataVals));
1812 auto CovData =
new llvm::GlobalVariable(
1813 CGM.
getModule(), CovDataTy,
true, llvm::GlobalValue::PrivateLinkage,
1814 CovDataVal, llvm::getCoverageMappingVarName());
1817 CovData->setAlignment(llvm::Align(8));
1822 if (!FunctionNames.empty()) {
1823 auto NamesArrTy = llvm::ArrayType::get(llvm::PointerType::getUnqual(Ctx),
1824 FunctionNames.size());
1825 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
1828 new llvm::GlobalVariable(CGM.
getModule(), NamesArrTy,
true,
1829 llvm::GlobalValue::InternalLinkage, NamesArrVal,
1830 llvm::getCoverageUnusedNamesVarName());
1835 auto It = FileEntries.find(
File);
1836 if (It != FileEntries.end())
1838 unsigned FileID = FileEntries.size() + 1;
1839 FileEntries.insert(std::make_pair(
File,
FileID));
1844 llvm::raw_ostream &OS) {
1846 CounterCoverageMappingBuilder Walker(CVM, *CounterMap,
SM, LangOpts);
1847 Walker.VisitDecl(D);
1852 llvm::raw_ostream &OS) {
1853 EmptyCoverageMappingBuilder Walker(CVM,
SM, LangOpts);
1854 Walker.VisitDecl(D);
Defines the Diagnostic-related interfaces.
static std::string getInstrProfSection(const CodeGenModule &CGM, llvm::InstrProfSectKind SK)
static llvm::cl::opt< bool > SystemHeadersCoverage("system-headers-coverage", llvm::cl::desc("Enable collecting coverage from system headers"), llvm::cl::init(false), llvm::cl::Hidden)
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)
Defines the clang::FileManager interface and associated types.
llvm::DenseSet< const void * > Visited
const TargetInfo & getTargetInfo() const
AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...
Expr * getCond() const
getCond - Return the expression representing the condition for the ?: operator.
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...
A builtin binary operation expression such as "x + y" or "x <= y".
BreakStmt - This represents a break.
CXXCatchStmt - This represents a C++ catch block.
CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for statement, represented as 'for (ra...
A C++ throw-expression (C++ [except.throw]).
const Expr * getSubExpr() const
CXXTryStmt - A C++ try block, including all handlers.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
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.
This class organizes the cross-function state that is used while generating LLVM code.
llvm::Module & getModule() const
void addUsedGlobal(llvm::GlobalValue *GV)
Add a global to a list to be added to the llvm.used metadata.
ASTContext & getContext() const
bool supportsCOMDAT() const
const CodeGenOptions & getCodeGenOpts() const
llvm::LLVMContext & getLLVMContext()
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...
Organizes the cross-function state that is used while generating code coverage mapping data.
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.
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
ContinueStmt - This represents a continue.
Represents a 'co_return' statement in the C++ Coroutines TS.
Represents the body of a coroutine.
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
Decl - This represents one declaration (or definition), e.g.
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...
DoStmt - This represents a 'do/while' stmt.
This represents one expression.
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer,...
bool isValueDependent() const
Determines whether the value of this expression depends on.
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...
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
ForStmt - This represents a 'for (init;cond;inc)' stmt.
GotoStmt - This represents a direct goto.
IfStmt - This represents an if/then/else.
LabelStmt - Represents a label, which has a substatement.
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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 ...
Represents Objective-C's collection statement.
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
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.
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
Expr * getSyntacticForm()
Return the syntactic form of this expression, i.e.
A (possibly-)qualified type.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
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.
This class handles loading and caching of source files into memory.
A trivial tuple used to represent a source range.
Each ExpansionInfo encodes the expansion location - where the token was ultimately expanded,...
bool isFunctionMacroExpansion() const
SourceLocation getExpansionLocEnd() const
Stmt - This represents one statement.
SourceLocation getColonLoc() const
const SwitchCase * getNextSwitchCase() const
SwitchStmt - This represents a 'switch' stmt.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Token - This structure provides full information about a lexed token.
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
tok::TokenKind getKind() const
WhileStmt - This represents a 'while' stmt.
FunctionType::ExtInfo getFunctionExtInfo(const Type &t)
EvalResult is a struct with detailed info about an evaluated expression.