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) {
306 if (!Visited.insert(
File).second)
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.getFileEntryForID(SpellingFile);
329 FileIDMapping[
SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
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;
605 RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc);
607 return RegionStack.size() - 1;
613 Loc = getIncludeOrExpansionLoc(Loc);
623 void popRegions(
size_t ParentIndex) {
624 assert(RegionStack.size() >= ParentIndex &&
"parent not in stack");
625 while (RegionStack.size() > ParentIndex) {
626 SourceMappingRegion &Region = RegionStack.back();
627 if (Region.hasStartLoc()) {
631 : RegionStack[ParentIndex].getEndLoc();
632 bool isBranch = Region.isBranch();
633 size_t StartDepth = locationDepth(StartLoc);
634 size_t EndDepth = locationDepth(EndLoc);
635 while (!
SM.isWrittenInSameFile(StartLoc, EndLoc)) {
636 bool UnnestStart = StartDepth >= EndDepth;
637 bool UnnestEnd = EndDepth >= StartDepth;
646 assert(
SM.isWrittenInSameFile(NestedLoc, EndLoc));
648 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
649 SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
652 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
654 llvm::report_fatal_error(
655 "File exit not handled before popRegions");
666 assert(
SM.isWrittenInSameFile(StartLoc, NestedLoc));
668 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
669 SourceRegions.emplace_back(Region.getCounter(), StartLoc,
672 StartLoc = getIncludeOrExpansionLoc(StartLoc);
674 llvm::report_fatal_error(
675 "File exit not handled before popRegions");
679 Region.setStartLoc(StartLoc);
680 Region.setEndLoc(EndLoc);
683 MostRecentLocation = EndLoc;
686 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
687 EndLoc == getEndOfFileOrMacro(EndLoc))
688 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
691 assert(
SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
692 assert(SpellingRegion(
SM, Region).isInSourceOrder());
693 SourceRegions.push_back(Region);
695 RegionStack.pop_back();
700 SourceMappingRegion &getRegion() {
701 assert(!RegionStack.empty() &&
"statement has no region");
702 return RegionStack.back();
707 Counter propagateCounts(Counter TopCount,
const Stmt *S,
708 bool VisitChildren =
true) {
711 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
714 Counter ExitCount = getRegion().getCounter();
719 if (
SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
720 MostRecentLocation = EndLoc;
726 bool ConditionFoldsToBool(
const Expr *Cond) {
735 void createBranchRegion(
const Expr *
C, Counter TrueCnt, Counter FalseCnt) {
744 if (CodeGenFunction::isInstrumentedCondition(
C)) {
751 if (ConditionFoldsToBool(
C))
752 popRegions(pushRegion(Counter::getZero(), getStart(
C), getEnd(
C),
753 Counter::getZero()));
756 popRegions(pushRegion(TrueCnt, getStart(
C), getEnd(
C), FalseCnt));
762 void createSwitchCaseRegion(
const SwitchCase *SC, Counter TrueCnt,
767 popRegions(pushRegion(TrueCnt, getStart(SC), SC->
getColonLoc(), FalseCnt));
773 bool isBranch =
false) {
775 llvm::reverse(SourceRegions), [&](
const SourceMappingRegion &Region) {
776 return Region.getBeginLoc() == StartLoc &&
777 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
785 MostRecentLocation = EndLoc;
791 if (getRegion().hasEndLoc() &&
792 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
793 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
794 MostRecentLocation, getRegion().isBranch()))
795 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
805 SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
811 FileID ParentFile =
SM.getFileID(LCA);
812 while (!isNestedIn(MostRecentLocation, ParentFile)) {
813 LCA = getIncludeOrExpansionLoc(LCA);
814 if (LCA.
isInvalid() ||
SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
817 MostRecentLocation = NewLoc;
820 ParentFile =
SM.getFileID(LCA);
823 llvm::SmallSet<SourceLocation, 8> StartLocs;
824 std::optional<Counter> ParentCounter;
825 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
826 if (!I.hasStartLoc())
829 if (!isNestedIn(Loc, ParentFile)) {
830 ParentCounter = I.getCounter();
834 while (!
SM.isInFileID(Loc, ParentFile)) {
838 if (StartLocs.insert(Loc).second) {
840 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), Loc,
841 getEndOfFileOrMacro(Loc), I.isBranch());
843 SourceRegions.emplace_back(I.getCounter(), Loc,
844 getEndOfFileOrMacro(Loc));
846 Loc = getIncludeOrExpansionLoc(Loc);
848 I.setStartLoc(getPreciseTokenLocEnd(Loc));
856 while (isNestedIn(Loc, ParentFile)) {
858 if (StartLocs.insert(FileStart).second) {
859 SourceRegions.emplace_back(*ParentCounter, FileStart,
860 getEndOfFileOrMacro(Loc));
861 assert(SpellingRegion(
SM, SourceRegions.back()).isInSourceOrder());
863 Loc = getIncludeOrExpansionLoc(Loc);
867 MostRecentLocation = NewLoc;
871 void extendRegion(
const Stmt *S) {
872 SourceMappingRegion &Region = getRegion();
875 handleFileExit(StartLoc);
876 if (!Region.hasStartLoc())
877 Region.setStartLoc(StartLoc);
881 void terminateRegion(
const Stmt *S) {
883 SourceMappingRegion &Region = getRegion();
885 if (!Region.hasEndLoc())
886 Region.setEndLoc(EndLoc);
887 pushRegion(Counter::getZero());
888 HasTerminateStmt =
true;
892 std::optional<SourceRange> findGapAreaBetween(
SourceLocation AfterLoc,
897 FileID FID =
SM.getFileID(AfterLoc);
903 size_t StartDepth = locationDepth(AfterLoc);
904 size_t EndDepth = locationDepth(BeforeLoc);
905 while (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
906 bool UnnestStart = StartDepth >= EndDepth;
907 bool UnnestEnd = EndDepth >= StartDepth;
909 assert(
SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
912 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
917 assert(
SM.isWrittenInSameFile(AfterLoc,
918 getEndOfFileOrMacro(AfterLoc)));
920 AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
922 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
927 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
932 if (!
SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
933 !SpellingRegion(
SM, AfterLoc, BeforeLoc).isInSourceOrder())
935 return {{AfterLoc, BeforeLoc}};
941 if (StartLoc == EndLoc)
943 assert(SpellingRegion(
SM, StartLoc, EndLoc).isInSourceOrder());
944 handleFileExit(StartLoc);
945 size_t Index = pushRegion(Count, StartLoc, EndLoc);
946 getRegion().setGap(
true);
947 handleFileExit(EndLoc);
952 struct BreakContinue {
954 Counter ContinueCount;
958 CounterCoverageMappingBuilder(
962 : CoverageMappingBuilder(CVM,
SM, LangOpts), CounterMap(CounterMap) {}
965 void write(llvm::raw_ostream &
OS) {
967 gatherFileIDs(VirtualFileMapping);
968 SourceRegionFilter
Filter = emitExpansionRegions();
969 emitSourceRegions(Filter);
970 gatherSkippedRegions();
972 if (MappingRegions.empty())
975 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
980 void VisitStmt(
const Stmt *S) {
981 if (S->getBeginLoc().isValid())
983 const Stmt *LastStmt =
nullptr;
984 bool SaveTerminateStmt = HasTerminateStmt;
985 HasTerminateStmt =
false;
986 GapRegionCounter = Counter::getZero();
987 for (
const Stmt *Child : S->children())
992 if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) {
993 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
995 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
997 SaveTerminateStmt =
true;
998 HasTerminateStmt =
false;
1003 if (SaveTerminateStmt)
1004 HasTerminateStmt =
true;
1005 handleFileExit(getEnd(S));
1008 void VisitDecl(
const Decl *D) {
1014 SM.isInSystemHeader(
SM.getSpellingLoc(getStart(Body))))
1022 if (
auto *Method = dyn_cast<CXXMethodDecl>(D))
1025 propagateCounts(getRegionCounter(Body), Body,
1027 assert(RegionStack.empty() &&
"Regions entered but never exited");
1032 if (S->getRetValue())
1033 Visit(S->getRetValue());
1039 Visit(S->getBody());
1044 if (S->getOperand())
1045 Visit(S->getOperand());
1056 void VisitGotoStmt(
const GotoStmt *S) { terminateRegion(S); }
1058 void VisitLabelStmt(
const LabelStmt *S) {
1059 Counter LabelCount = getRegionCounter(S);
1062 handleFileExit(Start);
1063 pushRegion(LabelCount, Start);
1064 Visit(S->getSubStmt());
1067 void VisitBreakStmt(
const BreakStmt *S) {
1068 assert(!BreakContinueStack.empty() &&
"break not in a loop or switch!");
1069 BreakContinueStack.back().BreakCount = addCounters(
1070 BreakContinueStack.back().BreakCount, getRegion().getCounter());
1077 assert(!BreakContinueStack.empty() &&
"continue stmt not in a loop!");
1078 BreakContinueStack.back().ContinueCount = addCounters(
1079 BreakContinueStack.back().ContinueCount, getRegion().getCounter());
1083 void VisitCallExpr(
const CallExpr *E) {
1093 void VisitWhileStmt(
const WhileStmt *S) {
1096 Counter ParentCount = getRegion().getCounter();
1097 Counter BodyCount = getRegionCounter(S);
1100 BreakContinueStack.push_back(BreakContinue());
1101 extendRegion(S->getBody());
1102 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1103 BreakContinue BC = BreakContinueStack.pop_back_val();
1105 bool BodyHasTerminateStmt = HasTerminateStmt;
1106 HasTerminateStmt =
false;
1110 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1111 propagateCounts(CondCount, S->getCond());
1112 adjustForOutOfOrderTraversal(getEnd(S));
1115 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1117 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1120 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1121 if (OutCount != ParentCount) {
1122 pushRegion(OutCount);
1123 GapRegionCounter = OutCount;
1124 if (BodyHasTerminateStmt)
1125 HasTerminateStmt =
true;
1129 createBranchRegion(S->getCond(), BodyCount,
1130 subtractCounters(CondCount, BodyCount));
1133 void VisitDoStmt(
const DoStmt *S) {
1136 Counter ParentCount = getRegion().getCounter();
1137 Counter BodyCount = getRegionCounter(S);
1139 BreakContinueStack.push_back(BreakContinue());
1140 extendRegion(S->getBody());
1141 Counter BackedgeCount =
1142 propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
1143 BreakContinue BC = BreakContinueStack.pop_back_val();
1145 bool BodyHasTerminateStmt = HasTerminateStmt;
1146 HasTerminateStmt =
false;
1148 Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
1149 propagateCounts(CondCount, S->getCond());
1152 addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1153 if (OutCount != ParentCount) {
1154 pushRegion(OutCount);
1155 GapRegionCounter = OutCount;
1159 createBranchRegion(S->getCond(), BodyCount,
1160 subtractCounters(CondCount, BodyCount));
1162 if (BodyHasTerminateStmt)
1163 HasTerminateStmt =
true;
1166 void VisitForStmt(
const ForStmt *S) {
1169 Visit(S->getInit());
1171 Counter ParentCount = getRegion().getCounter();
1172 Counter BodyCount = getRegionCounter(S);
1176 BreakContinueStack.emplace_back();
1179 BreakContinueStack.emplace_back();
1180 extendRegion(S->getBody());
1181 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1182 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1184 bool BodyHasTerminateStmt = HasTerminateStmt;
1185 HasTerminateStmt =
false;
1189 BreakContinue IncrementBC;
1190 if (
const Stmt *Inc = S->getInc()) {
1191 propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
1192 IncrementBC = BreakContinueStack.pop_back_val();
1196 Counter CondCount = addCounters(
1197 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1198 IncrementBC.ContinueCount);
1199 if (
const Expr *Cond = S->getCond()) {
1200 propagateCounts(CondCount, Cond);
1201 adjustForOutOfOrderTraversal(getEnd(S));
1205 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1207 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1209 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1210 subtractCounters(CondCount, BodyCount));
1211 if (OutCount != ParentCount) {
1212 pushRegion(OutCount);
1213 GapRegionCounter = OutCount;
1214 if (BodyHasTerminateStmt)
1215 HasTerminateStmt =
true;
1219 createBranchRegion(S->getCond(), BodyCount,
1220 subtractCounters(CondCount, BodyCount));
1226 Visit(S->getInit());
1227 Visit(S->getLoopVarStmt());
1228 Visit(S->getRangeStmt());
1230 Counter ParentCount = getRegion().getCounter();
1231 Counter BodyCount = getRegionCounter(S);
1233 BreakContinueStack.push_back(BreakContinue());
1234 extendRegion(S->getBody());
1235 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1236 BreakContinue BC = BreakContinueStack.pop_back_val();
1238 bool BodyHasTerminateStmt = HasTerminateStmt;
1239 HasTerminateStmt =
false;
1242 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1244 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1247 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1249 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1250 if (OutCount != ParentCount) {
1251 pushRegion(OutCount);
1252 GapRegionCounter = OutCount;
1253 if (BodyHasTerminateStmt)
1254 HasTerminateStmt =
true;
1258 createBranchRegion(S->getCond(), BodyCount,
1259 subtractCounters(LoopCount, BodyCount));
1264 Visit(S->getElement());
1266 Counter ParentCount = getRegion().getCounter();
1267 Counter BodyCount = getRegionCounter(S);
1269 BreakContinueStack.push_back(BreakContinue());
1270 extendRegion(S->getBody());
1271 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1272 BreakContinue BC = BreakContinueStack.pop_back_val();
1275 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1277 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1280 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1282 addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1283 if (OutCount != ParentCount) {
1284 pushRegion(OutCount);
1285 GapRegionCounter = OutCount;
1292 Visit(S->getInit());
1293 Visit(S->getCond());
1295 BreakContinueStack.push_back(BreakContinue());
1297 const Stmt *Body = S->getBody();
1299 if (
const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1300 if (!CS->body_empty()) {
1304 size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1305 getRegion().setGap(
true);
1309 for (
size_t i = RegionStack.size(); i != Index; --i) {
1310 if (!RegionStack[i - 1].hasEndLoc())
1311 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1317 propagateCounts(Counter::getZero(), Body);
1318 BreakContinue BC = BreakContinueStack.pop_back_val();
1320 if (!BreakContinueStack.empty())
1321 BreakContinueStack.back().ContinueCount = addCounters(
1322 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1324 Counter ParentCount = getRegion().getCounter();
1325 Counter ExitCount = getRegionCounter(S);
1327 pushRegion(ExitCount);
1328 GapRegionCounter = ExitCount;
1332 MostRecentLocation = getStart(S);
1333 handleFileExit(ExitLoc);
1337 Counter CaseCountSum;
1338 bool HasDefaultCase =
false;
1339 const SwitchCase *Case = S->getSwitchCaseList();
1341 HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case);
1343 addCounters(CaseCountSum, getRegionCounter(Case),
false);
1344 createSwitchCaseRegion(
1345 Case, getRegionCounter(Case),
1346 subtractCounters(ParentCount, getRegionCounter(Case)));
1351 CaseCountSum = addCounters(CaseCountSum, Counter::getZero());
1356 if (!HasDefaultCase) {
1357 Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum);
1358 Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue);
1359 createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse);
1366 SourceMappingRegion &
Parent = getRegion();
1368 Counter Count = addCounters(
Parent.getCounter(), getRegionCounter(S));
1371 if (
Parent.hasStartLoc() &&
Parent.getBeginLoc() == getStart(S))
1372 Parent.setCounter(Count);
1374 pushRegion(Count, getStart(S));
1376 GapRegionCounter = Count;
1378 if (
const auto *CS = dyn_cast<CaseStmt>(S)) {
1379 Visit(CS->getLHS());
1380 if (
const Expr *RHS = CS->getRHS())
1383 Visit(S->getSubStmt());
1386 void VisitIfStmt(
const IfStmt *S) {
1389 Visit(S->getInit());
1393 if (!S->isConsteval())
1394 extendRegion(S->getCond());
1396 Counter ParentCount = getRegion().getCounter();
1397 Counter ThenCount = getRegionCounter(S);
1399 if (!S->isConsteval()) {
1402 propagateCounts(ParentCount, S->getCond());
1405 std::optional<SourceRange> Gap =
1406 findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
1408 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
1411 extendRegion(S->getThen());
1412 Counter OutCount = propagateCounts(ThenCount, S->getThen());
1414 Counter ElseCount = subtractCounters(ParentCount, ThenCount);
1415 if (
const Stmt *Else = S->getElse()) {
1416 bool ThenHasTerminateStmt = HasTerminateStmt;
1417 HasTerminateStmt =
false;
1419 std::optional<SourceRange> Gap =
1420 findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
1422 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
1424 OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
1426 if (ThenHasTerminateStmt)
1427 HasTerminateStmt =
true;
1429 OutCount = addCounters(OutCount, ElseCount);
1431 if (OutCount != ParentCount) {
1432 pushRegion(OutCount);
1433 GapRegionCounter = OutCount;
1436 if (!S->isConsteval()) {
1438 createBranchRegion(S->getCond(), ThenCount,
1439 subtractCounters(ParentCount, ThenCount));
1446 extendRegion(S->getTryBlock());
1448 Counter ParentCount = getRegion().getCounter();
1449 propagateCounts(ParentCount, S->getTryBlock());
1451 for (
unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
1452 Visit(S->getHandler(I));
1454 Counter ExitCount = getRegionCounter(S);
1455 pushRegion(ExitCount);
1459 propagateCounts(getRegionCounter(S), S->getHandlerBlock());
1465 Counter ParentCount = getRegion().getCounter();
1466 Counter TrueCount = getRegionCounter(E);
1468 propagateCounts(ParentCount, E->
getCond());
1471 if (!isa<BinaryConditionalOperator>(E)) {
1476 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
1479 OutCount = propagateCounts(TrueCount, E->
getTrueExpr());
1483 OutCount = addCounters(
1484 OutCount, propagateCounts(subtractCounters(ParentCount, TrueCount),
1487 if (OutCount != ParentCount) {
1488 pushRegion(OutCount);
1489 GapRegionCounter = OutCount;
1493 createBranchRegion(E->
getCond(), TrueCount,
1494 subtractCounters(ParentCount, TrueCount));
1498 extendRegion(E->
getLHS());
1499 propagateCounts(getRegion().getCounter(), E->
getLHS());
1500 handleFileExit(getEnd(E->
getLHS()));
1503 extendRegion(E->
getRHS());
1504 propagateCounts(getRegionCounter(E), E->
getRHS());
1507 Counter RHSExecCnt = getRegionCounter(E);
1510 Counter RHSTrueCnt = getRegionCounter(E->
getRHS());
1513 Counter ParentCnt = getRegion().getCounter();
1516 createBranchRegion(E->
getLHS(), RHSExecCnt,
1517 subtractCounters(ParentCnt, RHSExecCnt));
1520 createBranchRegion(E->
getRHS(), RHSTrueCnt,
1521 subtractCounters(RHSExecCnt, RHSTrueCnt));
1525 bool shouldVisitRHS(
const Expr *LHS) {
1526 bool LHSIsTrue =
false;
1527 bool LHSIsConst =
false;
1531 return !LHSIsConst || (LHSIsConst && !LHSIsTrue);
1535 extendRegion(E->
getLHS());
1536 Counter OutCount = propagateCounts(getRegion().getCounter(), E->
getLHS());
1537 handleFileExit(getEnd(E->
getLHS()));
1540 extendRegion(E->
getRHS());
1541 propagateCounts(getRegionCounter(E), E->
getRHS());
1544 Counter RHSExecCnt = getRegionCounter(E);
1547 Counter RHSFalseCnt = getRegionCounter(E->
getRHS());
1549 if (!shouldVisitRHS(E->
getLHS())) {
1550 GapRegionCounter = OutCount;
1554 Counter ParentCnt = getRegion().getCounter();
1557 createBranchRegion(E->
getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
1561 createBranchRegion(E->
getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
1573static void dump(llvm::raw_ostream &
OS, StringRef FunctionName,
1576 OS << FunctionName <<
":\n";
1577 CounterMappingContext Ctx(Expressions);
1578 for (
const auto &R : Regions) {
1581 case CounterMappingRegion::CodeRegion:
1583 case CounterMappingRegion::ExpansionRegion:
1586 case CounterMappingRegion::SkippedRegion:
1589 case CounterMappingRegion::GapRegion:
1592 case CounterMappingRegion::BranchRegion:
1597 OS <<
"File " << R.FileID <<
", " << R.LineStart <<
":" << R.ColumnStart
1598 <<
" -> " << R.LineEnd <<
":" << R.ColumnEnd <<
" = ";
1599 Ctx.dump(R.Count,
OS);
1601 if (R.Kind == CounterMappingRegion::BranchRegion) {
1603 Ctx.dump(R.FalseCount,
OS);
1606 if (R.Kind == CounterMappingRegion::ExpansionRegion)
1607 OS <<
" (Expanded file = " << R.ExpandedFileID <<
")";
1614 : CGM(CGM), SourceInfo(SourceInfo) {
1618std::string CoverageMappingModuleGen::getCurrentDirname() {
1623 llvm::sys::fs::current_path(CWD);
1624 return CWD.str().str();
1627std::string CoverageMappingModuleGen::normalizeFilename(StringRef
Filename) {
1629 llvm::sys::path::remove_dots(Path,
true);
1630 for (
const auto &Entry : CoveragePrefixMap) {
1631 if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
1634 return Path.str().str();
1638 llvm::InstrProfSectKind SK) {
1639 return llvm::getInstrProfSectionName(
1643void CoverageMappingModuleGen::emitFunctionMappingRecord(
1644 const FunctionInfo &Info, uint64_t FilenamesRef) {
1648 std::string FuncRecordName =
"__covrec_" + llvm::utohexstr(Info.NameHash);
1655 FuncRecordName +=
"u";
1658 const uint64_t NameHash = Info.NameHash;
1659 const uint64_t FuncHash = Info.FuncHash;
1660 const std::string &CoverageMapping = Info.CoverageMapping;
1661#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
1662 llvm::Type *FunctionRecordTypes[] = {
1663#include "llvm/ProfileData/InstrProfData.inc"
1665 auto *FunctionRecordTy =
1666 llvm::StructType::get(Ctx,
ArrayRef(FunctionRecordTypes),
1670#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
1671 llvm::Constant *FunctionRecordVals[] = {
1672 #include "llvm/ProfileData/InstrProfData.inc"
1674 auto *FuncRecordConstant =
1675 llvm::ConstantStruct::get(FunctionRecordTy,
ArrayRef(FunctionRecordVals));
1678 auto *FuncRecord =
new llvm::GlobalVariable(
1679 CGM.
getModule(), FunctionRecordTy,
true,
1680 llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
1682 FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
1684 FuncRecord->setAlignment(llvm::Align(8));
1686 FuncRecord->setComdat(CGM.
getModule().getOrInsertComdat(FuncRecordName));
1693 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
1694 const std::string &CoverageMapping,
bool IsUsed) {
1696 const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
1697 FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
1700 FunctionNames.push_back(
1701 llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)));
1710 std::vector<StringRef> Filenames;
1711 std::vector<CounterExpression> Expressions;
1712 std::vector<CounterMappingRegion> Regions;
1713 FilenameStrs.resize(FileEntries.size() + 1);
1714 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
1715 for (
const auto &Entry : FileEntries) {
1716 auto I = Entry.second;
1717 FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1720 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
1721 Expressions, Regions);
1724 dump(llvm::outs(), NameValue, Expressions, Regions);
1729 if (FunctionRecords.empty())
1732 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
1736 FilenameStrs.resize(FileEntries.size() + 1);
1738 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
1739 for (
const auto &Entry : FileEntries) {
1740 auto I = Entry.second;
1741 FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1744 std::string Filenames;
1746 llvm::raw_string_ostream
OS(Filenames);
1747 CoverageFilenamesSectionWriter(FilenameStrs).write(
OS);
1749 auto *FilenamesVal =
1750 llvm::ConstantDataArray::getString(Ctx, Filenames,
false);
1751 const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
1754 for (
const FunctionInfo &Info : FunctionRecords)
1755 emitFunctionMappingRecord(Info, FilenamesRef);
1757 const unsigned NRecords = 0;
1758 const size_t FilenamesSize = Filenames.size();
1759 const unsigned CoverageMappingSize = 0;
1760 llvm::Type *CovDataHeaderTypes[] = {
1761#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
1762#include "llvm/ProfileData/InstrProfData.inc"
1764 auto CovDataHeaderTy =
1765 llvm::StructType::get(Ctx,
ArrayRef(CovDataHeaderTypes));
1766 llvm::Constant *CovDataHeaderVals[] = {
1767#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
1768#include "llvm/ProfileData/InstrProfData.inc"
1770 auto CovDataHeaderVal =
1771 llvm::ConstantStruct::get(CovDataHeaderTy,
ArrayRef(CovDataHeaderVals));
1774 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
1775 auto CovDataTy = llvm::StructType::get(Ctx,
ArrayRef(CovDataTypes));
1776 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
1777 auto CovDataVal = llvm::ConstantStruct::get(CovDataTy,
ArrayRef(TUDataVals));
1778 auto CovData =
new llvm::GlobalVariable(
1779 CGM.
getModule(), CovDataTy,
true, llvm::GlobalValue::PrivateLinkage,
1780 CovDataVal, llvm::getCoverageMappingVarName());
1783 CovData->setAlignment(llvm::Align(8));
1788 if (!FunctionNames.empty()) {
1789 auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx),
1790 FunctionNames.size());
1791 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
1794 new llvm::GlobalVariable(CGM.
getModule(), NamesArrTy,
true,
1795 llvm::GlobalValue::InternalLinkage, NamesArrVal,
1796 llvm::getCoverageUnusedNamesVarName());
1801 auto It = FileEntries.find(
File);
1802 if (It != FileEntries.end())
1804 unsigned FileID = FileEntries.size() + 1;
1805 FileEntries.insert(std::make_pair(
File,
FileID));
1810 llvm::raw_ostream &
OS) {
1812 CounterCoverageMappingBuilder Walker(CVM, *CounterMap,
SM, LangOpts);
1813 Walker.VisitDecl(D);
1818 llvm::raw_ostream &
OS) {
1819 EmptyCoverageMappingBuilder Walker(CVM,
SM, LangOpts);
1820 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.
const TargetInfo & getTargetInfo() const
AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...
Expr * getTrueExpr() const
SourceLocation getQuestionLoc() const
Expr * getFalseExpr() const
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]).
std::string CoverageCompilationDir
The string to embed in coverage mapping as the current working directory.
std::map< std::string, std::string > CoveragePrefixMap
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(const FileEntry *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...
Cached information about one file (either on disk or in the virtual file system).
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.
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.
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)
@ C
Languages that the frontend can parse and compile.
EvalResult is a struct with detailed info about an evaluated expression.