clang 24.0.0git
CoverageMappingGen.cpp
Go to the documentation of this file.
1//===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Instrumentation-based code coverage mapping generator
10//
11//===----------------------------------------------------------------------===//
12
13#include "CoverageMappingGen.h"
14#include "CodeGenFunction.h"
15#include "CodeGenPGO.h"
19#include "clang/Lex/Lexer.h"
20#include "llvm/ADT/DenseSet.h"
21#include "llvm/ADT/SmallSet.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/ProfileData/Coverage/CoverageMapping.h"
24#include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
25#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
26#include "llvm/Support/FileSystem.h"
27#include "llvm/Support/Path.h"
28#include <optional>
29
30// This selects the coverage mapping format defined when `InstrProfData.inc`
31// is textually included.
32#define COVMAP_V3
33
34namespace llvm {
35cl::opt<bool>
36 EnableSingleByteCoverage("enable-single-byte-coverage",
37 llvm::cl::ZeroOrMore,
38 llvm::cl::desc("Enable single byte coverage"),
39 llvm::cl::Hidden, llvm::cl::init(false));
40} // namespace llvm
41
42static llvm::cl::opt<bool> EmptyLineCommentCoverage(
43 "emptyline-comment-coverage",
44 llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only "
45 "disable it on test)"),
46 llvm::cl::init(true), llvm::cl::Hidden);
47
48namespace llvm::coverage {
50 "system-headers-coverage",
51 cl::desc("Enable collecting coverage from system headers"), cl::init(false),
52 cl::Hidden);
53}
54
55using namespace clang;
56using namespace CodeGen;
57using namespace llvm::coverage;
58
61 CoverageSourceInfo *CoverageInfo =
63 PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(CoverageInfo));
65 PP.addCommentHandler(CoverageInfo);
66 PP.setEmptylineHandler(CoverageInfo);
67 PP.setPreprocessToken(true);
68 PP.setTokenWatcher([CoverageInfo](clang::Token Tok) {
69 // Update previous token location.
70 CoverageInfo->PrevTokLoc = Tok.getLocation();
71 if (Tok.getKind() != clang::tok::eod)
72 CoverageInfo->updateNextTokLoc(Tok.getLocation());
73 });
74 }
75 return CoverageInfo;
76}
77
79 SkippedRange::Kind RangeKind) {
80 if (EmptyLineCommentCoverage && !SkippedRanges.empty() &&
81 PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
82 SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
83 Range.getBegin()))
84 SkippedRanges.back().Range.setEnd(Range.getEnd());
85 else
86 SkippedRanges.push_back({Range, RangeKind, PrevTokLoc});
87}
88
92
96
101
103 if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
104 SkippedRanges.back().NextTokLoc = Loc;
105}
106
107namespace {
108/// A region of source code that can be mapped to a counter.
109class SourceMappingRegion {
110 /// Primary Counter that is also used for Branch Regions for "True" branches.
111 Counter Count;
112
113 /// Secondary Counter used for Branch Regions for "False" branches.
114 std::optional<Counter> FalseCount;
115
116 /// Parameters used for Modified Condition/Decision Coverage
117 mcdc::Parameters MCDCParams;
118
119 /// The region's starting location.
120 std::optional<SourceLocation> LocStart;
121
122 /// The region's ending location.
123 std::optional<SourceLocation> LocEnd;
124
125 /// Whether this region is a gap region. The count from a gap region is set
126 /// as the line execution count if there are no other regions on the line.
127 bool GapRegion;
128
129 /// Whetever this region is skipped ('if constexpr' or 'if consteval' untaken
130 /// branch, or anything skipped but not empty line / comments)
131 bool SkippedRegion;
132
133public:
134 SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart,
135 std::optional<SourceLocation> LocEnd,
136 bool GapRegion = false)
137 : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
138 SkippedRegion(false) {}
139
140 SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount,
141 mcdc::Parameters MCDCParams,
142 std::optional<SourceLocation> LocStart,
143 std::optional<SourceLocation> LocEnd,
144 bool GapRegion = false)
145 : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams),
146 LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
147 SkippedRegion(false) {}
148
149 SourceMappingRegion(mcdc::Parameters MCDCParams,
150 std::optional<SourceLocation> LocStart,
151 std::optional<SourceLocation> LocEnd)
152 : MCDCParams(MCDCParams), LocStart(LocStart), LocEnd(LocEnd),
153 GapRegion(false), SkippedRegion(false) {}
154
155 const Counter &getCounter() const { return Count; }
156
157 const Counter &getFalseCounter() const {
158 assert(FalseCount && "Region has no alternate counter");
159 return *FalseCount;
160 }
161
162 void setCounter(Counter C) { Count = C; }
163
164 bool hasStartLoc() const { return LocStart.has_value(); }
165
166 void setStartLoc(SourceLocation Loc) { LocStart = Loc; }
167
168 SourceLocation getBeginLoc() const {
169 assert(LocStart && "Region has no start location");
170 return *LocStart;
171 }
172
173 bool hasEndLoc() const { return LocEnd.has_value(); }
174
175 void setEndLoc(SourceLocation Loc) {
176 assert(Loc.isValid() && "Setting an invalid end location");
177 LocEnd = Loc;
178 }
179
180 SourceLocation getEndLoc() const {
181 assert(LocEnd && "Region has no end location");
182 return *LocEnd;
183 }
184
185 bool isGap() const { return GapRegion; }
186
187 void setGap(bool Gap) { GapRegion = Gap; }
188
189 bool isSkipped() const { return SkippedRegion; }
190
191 void setSkipped(bool Skipped) { SkippedRegion = Skipped; }
192
193 bool isBranch() const { return FalseCount.has_value(); }
194
195 bool isMCDCBranch() const {
196 return std::holds_alternative<mcdc::BranchParameters>(MCDCParams);
197 }
198
199 const auto &getMCDCBranchParams() const {
200 return mcdc::getParams<const mcdc::BranchParameters>(MCDCParams);
201 }
202
203 bool isMCDCDecision() const {
204 return std::holds_alternative<mcdc::DecisionParameters>(MCDCParams);
205 }
206
207 const auto &getMCDCDecisionParams() const {
208 return mcdc::getParams<const mcdc::DecisionParameters>(MCDCParams);
209 }
210
211 const mcdc::Parameters &getMCDCParams() const { return MCDCParams; }
212
213 void resetMCDCParams() { MCDCParams = mcdc::Parameters(); }
214};
215
216/// Spelling locations for the start and end of a source region.
217struct SpellingRegion {
218 /// The line where the region starts.
219 unsigned LineStart;
220
221 /// The column where the region starts.
222 unsigned ColumnStart;
223
224 /// The line where the region ends.
225 unsigned LineEnd;
226
227 /// The column where the region ends.
228 unsigned ColumnEnd;
229
230 SpellingRegion(SourceManager &SM, SourceLocation LocStart,
231 SourceLocation LocEnd) {
232 LineStart = SM.getSpellingLineNumber(LocStart);
233 ColumnStart = SM.getSpellingColumnNumber(LocStart);
234 LineEnd = SM.getSpellingLineNumber(LocEnd);
235 ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
236 }
237
238 SpellingRegion(SourceManager &SM, SourceMappingRegion &R)
239 : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {}
240
241 /// Check if the start and end locations appear in source order, i.e
242 /// top->bottom, left->right.
243 bool isInSourceOrder() const {
244 return (LineStart < LineEnd) ||
245 (LineStart == LineEnd && ColumnStart <= ColumnEnd);
246 }
247};
248
249/// Provides the common functionality for the different
250/// coverage mapping region builders.
251class CoverageMappingBuilder {
252public:
253 CoverageMappingModuleGen &CVM;
254 SourceManager &SM;
255 const LangOptions &LangOpts;
256
257private:
258 /// Map of clang's FileIDs to IDs used for coverage mapping.
259 llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
260 FileIDMapping;
261
262public:
263 /// The coverage mapping regions for this function
264 llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
265 /// The source mapping regions for this function.
266 std::vector<SourceMappingRegion> SourceRegions;
267
268 /// A set of regions which can be used as a filter.
269 ///
270 /// It is produced by emitExpansionRegions() and is used in
271 /// emitSourceRegions() to suppress producing code regions if
272 /// the same area is covered by expansion regions.
273 typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
274 SourceRegionFilter;
275
276 CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
277 const LangOptions &LangOpts)
278 : CVM(CVM), SM(SM), LangOpts(LangOpts) {}
279
280 /// Return the precise end location for the given token.
281 SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
282 // We avoid getLocForEndOfToken here, because it doesn't do what we want for
283 // macro locations, which we just treat as expanded files.
284 unsigned TokLen =
285 Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts);
286 return Loc.getLocWithOffset(TokLen);
287 }
288
289 /// Return the start location of an included file or expanded macro.
290 SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
291 if (Loc.isMacroID())
292 return Loc.getLocWithOffset(-SM.getFileOffset(Loc));
293 return SM.getLocForStartOfFile(SM.getFileID(Loc));
294 }
295
296 /// Return the end location of an included file or expanded macro.
297 SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
298 if (Loc.isMacroID())
299 return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) -
300 SM.getFileOffset(Loc));
301 return SM.getLocForEndOfFile(SM.getFileID(Loc));
302 }
303
304 /// Find out where a macro is expanded. If the immediate result is a
305 /// <scratch space>, keep looking until the result isn't. Return a pair of
306 /// \c SourceLocation. The first object is always the begin sloc of found
307 /// result. The second should be checked by the caller: if it has value, it's
308 /// the end sloc of the found result. Otherwise the while loop didn't get
309 /// executed, which means the location wasn't changed and the caller has to
310 /// learn the end sloc from somewhere else.
311 std::pair<SourceLocation, std::optional<SourceLocation>>
312 getNonScratchExpansionLoc(SourceLocation Loc) {
313 std::optional<SourceLocation> EndLoc = std::nullopt;
314 while (Loc.isMacroID() &&
316 auto ExpansionRange = SM.getImmediateExpansionRange(Loc);
317 Loc = ExpansionRange.getBegin();
318 EndLoc = ExpansionRange.getEnd();
319 }
320 return std::make_pair(Loc, EndLoc);
321 }
322
323 /// Find out where the current file is included or macro is expanded. If
324 /// \c AcceptScratch is set to false, keep looking for expansions until the
325 /// found sloc is not a <scratch space>.
326 SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc,
327 bool AcceptScratch = true) {
328 if (!Loc.isMacroID())
329 return SM.getIncludeLoc(SM.getFileID(Loc));
330 Loc = SM.getImmediateExpansionRange(Loc).getBegin();
331 if (AcceptScratch)
332 return Loc;
333 return getNonScratchExpansionLoc(Loc).first;
334 }
335
336 /// Return true if \c Loc is a location in a built-in macro.
337 bool isInBuiltin(SourceLocation Loc) {
338 return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>";
339 }
340
341 /// Check whether \c Loc is included or expanded from \c Parent.
342 bool isNestedIn(SourceLocation Loc, FileID Parent) {
343 do {
344 Loc = getIncludeOrExpansionLoc(Loc);
345 if (Loc.isInvalid())
346 return false;
347 } while (!SM.isInFileID(Loc, Parent));
348 return true;
349 }
350
351 /// Get the start of \c S ignoring macro arguments and builtin macros.
352 SourceLocation getStart(const Stmt *S) {
353 SourceLocation Loc = S->getBeginLoc();
354 while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
355 Loc = SM.getImmediateExpansionRange(Loc).getBegin();
356 return Loc;
357 }
358
359 /// Get the end of \c S ignoring macro arguments and builtin macros.
360 SourceLocation getEnd(const Stmt *S) {
361 SourceLocation Loc = S->getEndLoc();
362 while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
363 Loc = SM.getImmediateExpansionRange(Loc).getBegin();
364 return getPreciseTokenLocEnd(Loc);
365 }
366
367 /// Find the set of files we have regions for and assign IDs
368 ///
369 /// Fills \c Mapping with the virtual file mapping needed to write out
370 /// coverage and collects the necessary file information to emit source and
371 /// expansion regions.
372 void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
373 FileIDMapping.clear();
374
375 llvm::SmallSet<FileID, 8> Visited;
376 SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
377 for (auto &Region : SourceRegions) {
378 SourceLocation Loc = Region.getBeginLoc();
379
380 // Replace Region with its definition if it is in <scratch space>.
381 auto NonScratchExpansionLoc = getNonScratchExpansionLoc(Loc);
382 auto EndLoc = NonScratchExpansionLoc.second;
383 if (EndLoc.has_value()) {
384 Loc = NonScratchExpansionLoc.first;
385 Region.setStartLoc(Loc);
386 Region.setEndLoc(EndLoc.value());
387 }
388
389 // For regions whose spelling is in a system header, remap macro
390 // tokens to their user-code call site so coverage is attributed to
391 // the user expression. Drop anything still in a system header
392 // (e.g. a plain FileID into a -isystem .def file).
394 SM.isInSystemHeader(SM.getSpellingLoc(Loc))) {
395 if (Loc.isMacroID()) {
396 auto BeginLoc = SM.getSpellingLoc(Loc);
397 auto EndLoc = SM.getSpellingLoc(Region.getEndLoc());
398 if (SM.isWrittenInSameFile(BeginLoc, EndLoc)) {
399 Loc = SM.getFileLoc(Loc);
400 Region.setStartLoc(Loc);
401 Region.setEndLoc(SM.getFileLoc(Region.getEndLoc()));
402 }
403 }
404 if (SM.isInSystemHeader(SM.getSpellingLoc(Loc)))
405 continue;
406 }
407
408 FileID File = SM.getFileID(Loc);
409 if (!Visited.insert(File).second)
410 continue;
411
412 unsigned Depth = 0;
413 for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
414 Parent.isValid(); Parent = getIncludeOrExpansionLoc(Parent))
415 ++Depth;
416 FileLocs.push_back(std::make_pair(Loc, Depth));
417 }
418 llvm::stable_sort(FileLocs, llvm::less_second());
419
420 for (const auto &FL : FileLocs) {
421 SourceLocation Loc = FL.first;
422 FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first;
423 auto Entry = SM.getFileEntryRefForID(SpellingFile);
424 if (!Entry)
425 continue;
426
427 FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
428 Mapping.push_back(CVM.getFileID(*Entry));
429 }
430 }
431
432 /// Get the coverage mapping file ID for \c Loc.
433 ///
434 /// If such file id doesn't exist, return std::nullopt.
435 std::optional<unsigned> getCoverageFileID(SourceLocation Loc) {
436 auto Mapping = FileIDMapping.find(SM.getFileID(Loc));
437 if (Mapping != FileIDMapping.end())
438 return Mapping->second.first;
439 return std::nullopt;
440 }
441
442 /// This shrinks the skipped range if it spans a line that contains a
443 /// non-comment token. If shrinking the skipped range would make it empty,
444 /// this returns std::nullopt.
445 /// Note this function can potentially be expensive because
446 /// getSpellingLineNumber uses getLineNumber, which is expensive.
447 std::optional<SpellingRegion> adjustSkippedRange(SourceManager &SM,
448 SourceLocation LocStart,
449 SourceLocation LocEnd,
450 SourceLocation PrevTokLoc,
451 SourceLocation NextTokLoc) {
452 SpellingRegion SR{SM, LocStart, LocEnd};
453 SR.ColumnStart = 1;
454 if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
455 SR.LineStart == SM.getSpellingLineNumber(PrevTokLoc))
456 SR.LineStart++;
457 if (NextTokLoc.isValid() && SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
458 SR.LineEnd == SM.getSpellingLineNumber(NextTokLoc)) {
459 SR.LineEnd--;
460 SR.ColumnEnd++;
461 }
462 if (SR.isInSourceOrder())
463 return SR;
464 return std::nullopt;
465 }
466
467 /// Gather all the regions that were skipped by the preprocessor
468 /// using the constructs like #if or comments.
469 void gatherSkippedRegions() {
470 /// An array of the minimum lineStarts and the maximum lineEnds
471 /// for mapping regions from the appropriate source files.
472 llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
473 FileLineRanges.resize(
474 FileIDMapping.size(),
475 std::make_pair(std::numeric_limits<unsigned>::max(), 0));
476 for (const auto &R : MappingRegions) {
477 FileLineRanges[R.FileID].first =
478 std::min(FileLineRanges[R.FileID].first, R.LineStart);
479 FileLineRanges[R.FileID].second =
480 std::max(FileLineRanges[R.FileID].second, R.LineEnd);
481 }
482
483 auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges();
484 for (auto &I : SkippedRanges) {
485 SourceRange Range = I.Range;
486 auto LocStart = Range.getBegin();
487 auto LocEnd = Range.getEnd();
488 assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
489 "region spans multiple files");
490
491 auto CovFileID = getCoverageFileID(LocStart);
492 if (!CovFileID)
493 continue;
494 std::optional<SpellingRegion> SR;
495 if (I.isComment())
496 SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc,
497 I.NextTokLoc);
498 else if (I.isPPIfElse() || I.isEmptyLine())
499 SR = {SM, LocStart, LocEnd};
500
501 if (!SR)
502 continue;
503 auto Region = CounterMappingRegion::makeSkipped(
504 *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
505 SR->ColumnEnd);
506 // Make sure that we only collect the regions that are inside
507 // the source code of this function.
508 if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
509 Region.LineEnd <= FileLineRanges[*CovFileID].second)
510 MappingRegions.push_back(Region);
511 }
512 }
513
514 /// Generate the coverage counter mapping regions from collected
515 /// source regions.
516 void emitSourceRegions(const SourceRegionFilter &Filter) {
517 for (const auto &Region : SourceRegions) {
518 assert(Region.hasEndLoc() && "incomplete region");
519
520 SourceLocation LocStart = Region.getBeginLoc();
521 assert(SM.getFileID(LocStart).isValid() && "region in invalid file");
522
523 // Ignore regions from system headers unless collecting coverage from
524 // system headers is explicitly enabled.
526 SM.isInSystemHeader(SM.getSpellingLoc(LocStart))) {
527 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
528 "Don't suppress the condition in system headers");
529 continue;
530 }
531
532 auto CovFileID = getCoverageFileID(LocStart);
533 // Ignore regions that don't have a file, such as builtin macros.
534 if (!CovFileID) {
535 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
536 "Don't suppress the condition in non-file regions");
537 continue;
538 }
539
540 SourceLocation LocEnd = Region.getEndLoc();
541 assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
542 "region spans multiple files");
543
544 // Don't add code regions for the area covered by expansion regions.
545 // This not only suppresses redundant regions, but sometimes prevents
546 // creating regions with wrong counters if, for example, a statement's
547 // body ends at the end of a nested macro.
548 if (Filter.count(std::make_pair(LocStart, LocEnd))) {
549 assert(!Region.isMCDCBranch() && !Region.isMCDCDecision() &&
550 "Don't suppress the condition");
551 continue;
552 }
553
554 // Find the spelling locations for the mapping region.
555 SpellingRegion SR{SM, LocStart, LocEnd};
556 assert(SR.isInSourceOrder() && "region start and end out of order");
557
558 if (Region.isGap()) {
559 MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
560 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
561 SR.LineEnd, SR.ColumnEnd));
562 } else if (Region.isSkipped()) {
563 MappingRegions.push_back(CounterMappingRegion::makeSkipped(
564 *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd,
565 SR.ColumnEnd));
566 } else if (Region.isBranch()) {
567 MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
568 Region.getCounter(), Region.getFalseCounter(), *CovFileID,
569 SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd,
570 Region.getMCDCParams()));
571 } else if (Region.isMCDCDecision()) {
572 MappingRegions.push_back(CounterMappingRegion::makeDecisionRegion(
573 Region.getMCDCDecisionParams(), *CovFileID, SR.LineStart,
574 SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
575 } else {
576 MappingRegions.push_back(CounterMappingRegion::makeRegion(
577 Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
578 SR.LineEnd, SR.ColumnEnd));
579 }
580 }
581 }
582
583 /// Generate expansion regions for each virtual file we've seen.
584 SourceRegionFilter emitExpansionRegions() {
585 SourceRegionFilter Filter;
586 for (const auto &FM : FileIDMapping) {
587 SourceLocation ExpandedLoc = FM.second.second;
588 SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc, false);
589 if (ParentLoc.isInvalid())
590 continue;
591
592 auto ParentFileID = getCoverageFileID(ParentLoc);
593 if (!ParentFileID)
594 continue;
595 auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
596 assert(ExpandedFileID && "expansion in uncovered file");
597
598 SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
599 assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
600 "region spans multiple files");
601 Filter.insert(std::make_pair(ParentLoc, LocEnd));
602
603 SpellingRegion SR{SM, ParentLoc, LocEnd};
604 assert(SR.isInSourceOrder() && "region start and end out of order");
605 MappingRegions.push_back(CounterMappingRegion::makeExpansion(
606 *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
607 SR.LineEnd, SR.ColumnEnd));
608 }
609 return Filter;
610 }
611};
612
613/// Creates unreachable coverage regions for the functions that
614/// are not emitted.
615struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
616 EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
617 const LangOptions &LangOpts)
618 : CoverageMappingBuilder(CVM, SM, LangOpts) {}
619
620 void VisitDecl(const Decl *D) {
621 if (!D->hasBody())
622 return;
623 auto Body = D->getBody();
624 SourceLocation Start = getStart(Body);
625 SourceLocation End = getEnd(Body);
626 if (!SM.isWrittenInSameFile(Start, End)) {
627 // Walk up to find the common ancestor.
628 // Correct the locations accordingly.
629 FileID StartFileID = SM.getFileID(Start);
630 FileID EndFileID = SM.getFileID(End);
631 while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
632 Start = getIncludeOrExpansionLoc(Start);
633 assert(Start.isValid() &&
634 "Declaration start location not nested within a known region");
635 StartFileID = SM.getFileID(Start);
636 }
637 while (StartFileID != EndFileID) {
638 End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
639 assert(End.isValid() &&
640 "Declaration end location not nested within a known region");
641 EndFileID = SM.getFileID(End);
642 }
643 }
644 SourceRegions.emplace_back(Counter(), Start, End);
645 }
646
647 /// Write the mapping data to the output stream
648 void write(llvm::raw_ostream &OS) {
649 SmallVector<unsigned, 16> FileIDMapping;
650 gatherFileIDs(FileIDMapping);
651 emitSourceRegions(SourceRegionFilter());
652
653 if (MappingRegions.empty())
654 return;
655
656 CoverageMappingWriter Writer(FileIDMapping, {}, MappingRegions);
657 Writer.write(OS);
658 }
659};
660
661/// A wrapper object for maintaining stacks to track the resursive AST visitor
662/// walks for the purpose of assigning IDs to leaf-level conditions measured by
663/// MC/DC. The object is created with a reference to the MCDCBitmapMap that was
664/// created during the initial AST walk. The presence of a bitmap associated
665/// with a boolean expression (top-level logical operator nest) indicates that
666/// the boolean expression qualified for MC/DC. The resulting condition IDs
667/// are preserved in a map reference that is also provided during object
668/// creation.
669struct MCDCCoverageBuilder {
670
671 /// The AST walk recursively visits nested logical-AND or logical-OR binary
672 /// operator nodes and then visits their LHS and RHS children nodes. As this
673 /// happens, the algorithm will assign IDs to each operator's LHS and RHS side
674 /// as the walk moves deeper into the nest. At each level of the recursive
675 /// nest, the LHS and RHS may actually correspond to larger subtrees (not
676 /// leaf-conditions). If this is the case, when that node is visited, the ID
677 /// assigned to the subtree is re-assigned to its LHS, and a new ID is given
678 /// to its RHS. At the end of the walk, all leaf-level conditions will have a
679 /// unique ID -- keep in mind that the final set of IDs may not be in
680 /// numerical order from left to right.
681 ///
682 /// Example: "x = (A && B) || (C && D) || (D && F)"
683 ///
684 /// Visit Depth1:
685 /// (A && B) || (C && D) || (D && F)
686 /// ^-------LHS--------^ ^-RHS--^
687 /// ID=1 ID=2
688 ///
689 /// Visit LHS-Depth2:
690 /// (A && B) || (C && D)
691 /// ^-LHS--^ ^-RHS--^
692 /// ID=1 ID=3
693 ///
694 /// Visit LHS-Depth3:
695 /// (A && B)
696 /// LHS RHS
697 /// ID=1 ID=4
698 ///
699 /// Visit RHS-Depth3:
700 /// (C && D)
701 /// LHS RHS
702 /// ID=3 ID=5
703 ///
704 /// Visit RHS-Depth2: (D && F)
705 /// LHS RHS
706 /// ID=2 ID=6
707 ///
708 /// Visit Depth1:
709 /// (A && B) || (C && D) || (D && F)
710 /// ID=1 ID=4 ID=3 ID=5 ID=2 ID=6
711 ///
712 /// A node ID of '0' always means MC/DC isn't being tracked.
713 ///
714 /// As the AST walk proceeds recursively, the algorithm will also use a stack
715 /// to track the IDs of logical-AND and logical-OR operations on the RHS so
716 /// that it can be determined which nodes are executed next, depending on how
717 /// a LHS or RHS of a logical-AND or logical-OR is evaluated. This
718 /// information relies on the assigned IDs and are embedded within the
719 /// coverage region IDs of each branch region associated with a leaf-level
720 /// condition. This information helps the visualization tool reconstruct all
721 /// possible test vectors for the purposes of MC/DC analysis. If a "next" node
722 /// ID is '0', it means it's the end of the test vector. The following rules
723 /// are used:
724 ///
725 /// For logical-AND ("LHS && RHS"):
726 /// - If LHS is TRUE, execution goes to the RHS node.
727 /// - If LHS is FALSE, execution goes to the LHS node of the next logical-OR.
728 /// If that does not exist, execution exits (ID == 0).
729 ///
730 /// - If RHS is TRUE, execution goes to LHS node of the next logical-AND.
731 /// If that does not exist, execution exits (ID == 0).
732 /// - If RHS is FALSE, execution goes to the LHS node of the next logical-OR.
733 /// If that does not exist, execution exits (ID == 0).
734 ///
735 /// For logical-OR ("LHS || RHS"):
736 /// - If LHS is TRUE, execution goes to the LHS node of the next logical-AND.
737 /// If that does not exist, execution exits (ID == 0).
738 /// - If LHS is FALSE, execution goes to the RHS node.
739 ///
740 /// - If RHS is TRUE, execution goes to LHS node of the next logical-AND.
741 /// If that does not exist, execution exits (ID == 0).
742 /// - If RHS is FALSE, execution goes to the LHS node of the next logical-OR.
743 /// If that does not exist, execution exits (ID == 0).
744 ///
745 /// Finally, the condition IDs are also used when instrumenting the code to
746 /// indicate a unique offset into a temporary bitmap that represents the true
747 /// or false evaluation of that particular condition.
748 ///
749 /// NOTE regarding the use of CodeGenFunction::stripCond(). Even though, for
750 /// simplicity, parentheses and unary logical-NOT operators are considered
751 /// part of their underlying condition for both MC/DC and branch coverage, the
752 /// condition IDs themselves are assigned and tracked using the underlying
753 /// condition itself. This is done solely for consistency since parentheses
754 /// and logical-NOTs are ignored when checking whether the condition is
755 /// actually an instrumentable condition. This can also make debugging a bit
756 /// easier.
757
758private:
759 CodeGenModule &CGM;
760 MCDC::State &MCDCState;
761
762 struct DecisionState {
763 /// The root Decision
764 const Expr *DecisionExpr = nullptr;
765
766 /// Pair of Destination conditions [false, true]
767 /// -1, the final decision at the initial state.
768 /// Modify before/after the traversal of BinOp LHS.
769 mcdc::ConditionIDs CurCondIDs = {-1, -1};
770
771 /// The ID to be assigned, and total number of conditions.
772 mcdc::ConditionID NextID = 0;
773
774 /// false if the Decision is recognized but should be ignored.
775 bool Active = false;
776
777 DecisionState() = default;
778 DecisionState(const Expr *DecisionExpr, bool Valid)
779 : DecisionExpr(DecisionExpr), Active(Valid) {}
780 };
781
782 /// The bottom [0] is the sentinel.
783 /// - DecisionExpr = nullptr, doesn't match to any Expr(s).
784 /// - Active = false
785 llvm::SmallVector<DecisionState, 2> DecisionStack;
786
787 /// <Index of Decision, Index of Since>, on SourceRegions.
788 /// Used for restoring MCDCBranch=>Branch.
789 llvm::DenseMap<unsigned, unsigned> DecisionEndToSince;
790
791public:
792 MCDCCoverageBuilder(CodeGenModule &CGM, MCDC::State &MCDCState)
793 : CGM(CGM), MCDCState(MCDCState), DecisionStack(1) {}
794
795 bool isActive() const { return DecisionStack.back().Active; }
796
797 /// Set the given condition's ID.
798 void setCondID(const Expr *Cond, mcdc::ConditionID ID) {
799 assert(isActive());
801 ID, DecisionStack.back().DecisionExpr};
802 }
803
804 /// Return the ID of a given condition.
805 mcdc::ConditionID getCondID(const Expr *Cond) const {
806 auto I = MCDCState.BranchByStmt.find(CodeGenFunction::stripCond(Cond));
807 if (I == MCDCState.BranchByStmt.end())
808 return -1;
809 else
810 return I->second.ID;
811 }
812
813 /// Return the LHS Decision ([0,0] if not set).
814 auto &getCurCondIDs() { return DecisionStack.back().CurCondIDs; }
815
816 void swapConds() {
817 if (!isActive())
818 return;
819
820 std::swap(getCurCondIDs()[false], getCurCondIDs()[true]);
821 }
822
823 void checkDecisionRootOrPush(const Expr *E) {
824 // Don't push the new entry unless MC/DC Coverage.
825 if (!CGM.getCodeGenOpts().MCDCCoverage) {
826 assert(!isActive() && "The setinel should tell 'not Active'");
827 return;
828 }
829
830 auto *SC = CodeGenFunction::stripCond(E);
831 if (getCondID(SC) >= 0)
832 return;
833
834 // Push the new entry at the Decision root.
835 if (auto DI = MCDCState.DecisionByStmt.find(SC);
836 DI != MCDCState.DecisionByStmt.end()) {
837 auto &StackTop = DecisionStack.emplace_back(SC, DI->second.isValid());
838
839 // The root expr (possibly BinOp) may have 1st ID.
840 // It will be propagated to the most Left hand.
841 if (isActive() && getCondID(SC) < 0)
842 setCondID(SC, StackTop.NextID++);
843 return;
844 }
845
846 assert((!isActive() || DecisionStack.back().NextID > 0) &&
847 "Should be Active and after assignments");
848 }
849
850 /// Push the binary operator statement to track the nest level and assign IDs
851 /// to the operator's LHS and RHS. The RHS may be a larger subtree that is
852 /// broken up on successive levels.
853 std::pair<mcdc::ConditionID, mcdc::ConditionID>
854 pushAndAssignIDs(const BinaryOperator *E) {
855 if (!CGM.getCodeGenOpts().MCDCCoverage)
856 return {-1, -1};
857
858 checkDecisionRootOrPush(E);
859 if (!isActive())
860 return {-1, -1};
861
862 auto &StackTop = DecisionStack.back();
863
864 // LHS inherits the ID from the parent.
865 mcdc::ConditionID LHSid = getCondID(E);
866 assert(LHSid >= 0);
867 setCondID(E->getLHS(), LHSid);
868
869 // Assign a ID+1 for the RHS.
870 mcdc::ConditionID RHSid = StackTop.NextID++;
871 setCondID(E->getRHS(), RHSid);
872
873 return {LHSid, RHSid};
874 }
875
876 /// Return the total number of conditions and rewind the state. The number of
877 /// conditions is zero if the expression isn't mapped.
878 unsigned getTotalConditionsAndPop(const Expr *E) {
879 auto &StackTop = DecisionStack.back();
880
881 // Root?
882 if (StackTop.DecisionExpr != E)
883 return 0;
884
885 assert(StackTop.CurCondIDs[false] == -1 &&
886 StackTop.CurCondIDs[true] == -1 &&
887 "The root shouldn't depend on others.");
888
889 // Set number of conditions and pop.
890 unsigned TotalConds = (StackTop.Active ? StackTop.NextID : 0);
891 DecisionStack.pop_back();
892 assert(!DecisionStack.empty() && "Sentiel?");
893 return TotalConds;
894 }
895
896 void addDecisionRegionRange(unsigned Since, unsigned End) {
897 DecisionEndToSince[End] = Since;
898 }
899
900 /// Returns "Since" index corresponding to the arg Idx.
901 unsigned skipSourceRegionIndexForDecisions(unsigned Idx) {
902 auto I = DecisionEndToSince.find(Idx);
903 assert(I != DecisionEndToSince.end());
904 assert(I->second <= Idx);
905 return I->second;
906 }
907};
908
909/// A StmtVisitor that creates coverage mapping regions which map
910/// from the source code locations to the PGO counters.
911struct CounterCoverageMappingBuilder
912 : public CoverageMappingBuilder,
913 public ConstStmtVisitor<CounterCoverageMappingBuilder> {
914 /// The map of statements to count values.
915 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap;
916
917 /// Used to expand an allocatd SkipCnt to Expression with known counters.
918 /// Key: SkipCnt
919 /// Val: Subtract Expression
920 CounterExpressionBuilder::SubstMap MapToExpand;
921
922 /// Index and number for additional counters for SkipCnt.
923 unsigned NextCounterNum;
924
925 MCDC::State &MCDCState;
926
927 /// A stack of currently live regions.
928 llvm::SmallVector<SourceMappingRegion> RegionStack;
929
930 /// Set if the Expr should be handled as a leaf even if it is kind of binary
931 /// logical ops (&&, ||).
932 llvm::DenseSet<const Stmt *> LeafExprSet;
933
934 /// An object to manage MCDC regions.
935 MCDCCoverageBuilder MCDCBuilder;
936
937 CounterExpressionBuilder Builder;
938
939 /// A location in the most recently visited file or macro.
940 ///
941 /// This is used to adjust the active source regions appropriately when
942 /// expressions cross file or macro boundaries.
943 SourceLocation MostRecentLocation;
944
945 /// Whether the visitor at a terminate statement.
946 bool HasTerminateStmt = false;
947
948 /// Gap region counter after terminate statement.
949 Counter GapRegionCounter;
950
951 /// Return a counter for the subtraction of \c RHS from \c LHS
952 Counter subtractCounters(Counter LHS, Counter RHS, bool Simplify = true) {
954 "cannot add counters when single byte coverage mode is enabled");
955 return Builder.subtract(LHS, RHS, Simplify);
956 }
957
958 /// Return a counter for the sum of \c LHS and \c RHS.
959 Counter addCounters(Counter LHS, Counter RHS, bool Simplify = true) {
960 return Builder.add(LHS, RHS, Simplify);
961 }
962
963 Counter addCounters(Counter C1, Counter C2, Counter C3,
964 bool Simplify = true) {
965 return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
966 }
967
968 /// Return the region counter for the given statement.
969 ///
970 /// This should only be called on statements that have a dedicated counter.
971 Counter getRegionCounter(const Stmt *S) {
972 return Counter::getCounter(CounterMap[S].Executed);
973 }
974
975 struct BranchCounterPair {
976 Counter Executed; ///< The Counter previously assigned.
977 Counter Skipped; ///< An expression (Parent-Executed), or equivalent to it.
978 };
979
980 /// Retrieve or assign the pair of Counter(s).
981 ///
982 /// This returns BranchCounterPair {Executed, Skipped}.
983 /// Executed is the Counter associated with S assigned by an earlier
984 /// CounterMapping pass.
985 /// Skipped may be an expression (Executed - ParentCnt) or newly
986 /// assigned Counter in EnableSingleByteCoverage, as subtract
987 /// expressions are not available in this mode.
988 ///
989 /// \param S Key to the CounterMap
990 /// \param ParentCnt The Counter representing how many times S is evaluated.
991 BranchCounterPair
992 getBranchCounterPair(const Stmt *S, Counter ParentCnt,
993 std::optional<Counter> SkipCntForOld = std::nullopt) {
994 auto &TheMap = CounterMap[S];
995 auto ExecCnt = Counter::getCounter(TheMap.Executed);
996
997 BranchCounterPair Counters = {ExecCnt,
998 Builder.subtract(ParentCnt, ExecCnt)};
999
1000 if (!llvm::EnableSingleByteCoverage || !Counters.Skipped.isExpression()) {
1001 assert(
1002 !TheMap.Skipped.hasValue() &&
1003 "SkipCnt shouldn't be allocated but refer to an existing counter.");
1004 return Counters;
1005 }
1006
1007 // Assign second if second is not assigned yet.
1008 if (!TheMap.Skipped.hasValue())
1009 TheMap.Skipped = NextCounterNum++;
1010
1011 // Replace an expression (ParentCnt - ExecCnt) with SkipCnt.
1012 Counter SkipCnt = Counter::getCounter(TheMap.Skipped);
1013 MapToExpand[SkipCnt] = Builder.subst(Counters.Skipped, MapToExpand);
1014 Counters.Skipped = SkipCnt;
1015 return Counters;
1016 }
1017
1018 /// Returns {TrueCnt,FalseCnt} for "implicit default".
1019 /// FalseCnt is considered as the False count on SwitchStmt.
1020 std::pair<Counter, Counter>
1021 getSwitchImplicitDefaultCounterPair(const Stmt *Cond, Counter ParentCount,
1022 Counter CaseCountSum) {
1024 // Allocate the new Counter since `subtract(Parent - Sum)` is unavailable.
1025 unsigned Idx = NextCounterNum++;
1026 CounterMap[Cond].Skipped = Idx;
1027 return {Counter::getZero(), // Folded
1028 Counter::getCounter(Idx)};
1029 }
1030
1031 // Simplify is skipped while building the counters above: it can get
1032 // really slow on top of switches with thousands of cases. Instead,
1033 // trigger simplification by adding zero to the last counter.
1034 CaseCountSum =
1035 addCounters(CaseCountSum, Counter::getZero(), /*Simplify=*/true);
1036
1037 return {CaseCountSum, Builder.subtract(ParentCount, CaseCountSum)};
1038 }
1039
1040 bool IsCounterEqual(Counter OutCount, Counter ParentCount) {
1041 if (OutCount == ParentCount)
1042 return true;
1043
1044 // Try comaparison with pre-replaced expressions.
1045 //
1046 // For example, getBranchCounterPair(#0) returns {#1, #0 - #1}.
1047 // The sum of the pair should be equivalent to the Parent, #0.
1048 // OTOH when (#0 - #1) is replaced with the new counter #2,
1049 // The sum is (#1 + #2). If the reverse substitution #2 => (#0 - #1)
1050 // can be applied, the sum can be transformed to (#1 + (#0 - #1)).
1051 // To apply substitutions to both hand expressions, transform (LHS - RHS)
1052 // and check isZero.
1053 if (Builder.subst(Builder.subtract(OutCount, ParentCount), MapToExpand)
1054 .isZero())
1055 return true;
1056
1057 return false;
1058 }
1059
1060 /// Push a region onto the stack.
1061 ///
1062 /// Returns the index on the stack where the region was pushed. This can be
1063 /// used with popRegions to exit a "scope", ending the region that was pushed.
1064 size_t pushRegion(Counter Count,
1065 std::optional<SourceLocation> StartLoc = std::nullopt,
1066 std::optional<SourceLocation> EndLoc = std::nullopt,
1067 std::optional<Counter> FalseCount = std::nullopt,
1068 const mcdc::Parameters &BranchParams = std::monostate()) {
1069
1070 if (StartLoc && !FalseCount) {
1071 MostRecentLocation = *StartLoc;
1072 }
1073
1074 // If either of these locations is invalid, something elsewhere in the
1075 // compiler has broken.
1076 assert((!StartLoc || StartLoc->isValid()) && "Start location is not valid");
1077 assert((!EndLoc || EndLoc->isValid()) && "End location is not valid");
1078
1079 // However, we can still recover without crashing.
1080 // If either location is invalid, set it to std::nullopt to avoid
1081 // letting users of RegionStack think that region has a valid start/end
1082 // location.
1083 if (StartLoc && StartLoc->isInvalid())
1084 StartLoc = std::nullopt;
1085 if (EndLoc && EndLoc->isInvalid())
1086 EndLoc = std::nullopt;
1087 RegionStack.emplace_back(Count, FalseCount, BranchParams, StartLoc, EndLoc);
1088
1089 return RegionStack.size() - 1;
1090 }
1091
1092 size_t pushRegion(const mcdc::DecisionParameters &DecisionParams,
1093 std::optional<SourceLocation> StartLoc = std::nullopt,
1094 std::optional<SourceLocation> EndLoc = std::nullopt) {
1095
1096 RegionStack.emplace_back(DecisionParams, StartLoc, EndLoc);
1097
1098 return RegionStack.size() - 1;
1099 }
1100
1101 size_t locationDepth(SourceLocation Loc) {
1102 size_t Depth = 0;
1103 while (Loc.isValid()) {
1104 Loc = getIncludeOrExpansionLoc(Loc);
1105 Depth++;
1106 }
1107 return Depth;
1108 }
1109
1110 /// Pop regions from the stack into the function's list of regions.
1111 ///
1112 /// Adds all regions from \c ParentIndex to the top of the stack to the
1113 /// function's \c SourceRegions.
1114 void popRegions(size_t ParentIndex) {
1115 assert(RegionStack.size() >= ParentIndex && "parent not in stack");
1116 while (RegionStack.size() > ParentIndex) {
1117 SourceMappingRegion &Region = RegionStack.back();
1118 if (Region.hasStartLoc() &&
1119 (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) {
1120 SourceLocation StartLoc = Region.getBeginLoc();
1121 SourceLocation EndLoc = Region.hasEndLoc()
1122 ? Region.getEndLoc()
1123 : RegionStack[ParentIndex].getEndLoc();
1124 bool isBranch = Region.isBranch();
1125 size_t StartDepth = locationDepth(StartLoc);
1126 size_t EndDepth = locationDepth(EndLoc);
1127 while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) {
1128 bool UnnestStart = StartDepth >= EndDepth;
1129 bool UnnestEnd = EndDepth >= StartDepth;
1130 if (UnnestEnd) {
1131 // The region ends in a nested file or macro expansion. If the
1132 // region is not a branch region, create a separate region for each
1133 // expansion, and for all regions, update the EndLoc. Branch
1134 // regions should not be split in order to keep a straightforward
1135 // correspondance between the region and its associated branch
1136 // condition, even if the condition spans multiple depths.
1137 SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
1138 assert(SM.isWrittenInSameFile(NestedLoc, EndLoc));
1139
1140 if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
1141 SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
1142 EndLoc);
1143
1144 EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
1145 if (EndLoc.isInvalid())
1146 llvm::report_fatal_error(
1147 "File exit not handled before popRegions");
1148 EndDepth--;
1149 }
1150 if (UnnestStart) {
1151 // The region ends in a nested file or macro expansion. If the
1152 // region is not a branch region, create a separate region for each
1153 // expansion, and for all regions, update the StartLoc. Branch
1154 // regions should not be split in order to keep a straightforward
1155 // correspondance between the region and its associated branch
1156 // condition, even if the condition spans multiple depths.
1157 SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
1158 assert(SM.isWrittenInSameFile(StartLoc, NestedLoc));
1159
1160 if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
1161 SourceRegions.emplace_back(Region.getCounter(), StartLoc,
1162 NestedLoc);
1163
1164 StartLoc = getIncludeOrExpansionLoc(StartLoc);
1165 if (StartLoc.isInvalid())
1166 llvm::report_fatal_error(
1167 "File exit not handled before popRegions");
1168 StartDepth--;
1169 }
1170 }
1171 Region.setStartLoc(StartLoc);
1172 Region.setEndLoc(EndLoc);
1173
1174 if (!isBranch) {
1175 MostRecentLocation = EndLoc;
1176 // If this region happens to span an entire expansion, we need to
1177 // make sure we don't overlap the parent region with it.
1178 if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
1179 EndLoc == getEndOfFileOrMacro(EndLoc))
1180 MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
1181 }
1182
1183 assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
1184 assert(SpellingRegion(SM, Region).isInSourceOrder());
1185 SourceRegions.push_back(Region);
1186 }
1187 RegionStack.pop_back();
1188 }
1189 }
1190
1191 /// Return the currently active region.
1192 SourceMappingRegion &getRegion() {
1193 assert(!RegionStack.empty() && "statement has no region");
1194 return RegionStack.back();
1195 }
1196
1197 /// Propagate counts through the children of \p S if \p VisitChildren is true.
1198 /// Otherwise, only emit a count for \p S itself.
1199 Counter propagateCounts(Counter TopCount, const Stmt *S,
1200 bool VisitChildren = true) {
1201 SourceLocation StartLoc = getStart(S);
1202 SourceLocation EndLoc = getEnd(S);
1203 size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
1204 if (VisitChildren)
1205 Visit(S);
1206 Counter ExitCount = getRegion().getCounter();
1207 popRegions(Index);
1208
1209 // The statement may be spanned by an expansion. Make sure we handle a file
1210 // exit out of this expansion before moving to the next statement.
1211 if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
1212 MostRecentLocation = EndLoc;
1213
1214 return ExitCount;
1215 }
1216
1217 /// Create a Branch Region around an instrumentable condition for coverage
1218 /// and add it to the function's SourceRegions. A branch region tracks a
1219 /// "True" counter and a "False" counter for boolean expressions that
1220 /// result in the generation of a branch.
1221 void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt,
1222 const mcdc::ConditionIDs &Conds = {}) {
1223 // Check for NULL conditions.
1224 if (!C)
1225 return;
1226
1227 // Ensure we are an instrumentable condition (i.e. no "&&" or "||"). Push
1228 // region onto RegionStack but immediately pop it (which adds it to the
1229 // function's SourceRegions) because it doesn't apply to any other source
1230 // code other than the Condition.
1231 // With !SystemHeadersCoverage, binary logical ops in system headers may be
1232 // treated as instrumentable conditions.
1234 LeafExprSet.count(CodeGenFunction::stripCond(C))) {
1235 mcdc::Parameters BranchParams;
1236 mcdc::ConditionID ID = MCDCBuilder.getCondID(C);
1237 if (ID >= 0)
1238 BranchParams = mcdc::BranchParameters{ID, Conds};
1239
1240 // If a condition can fold to true or false, the corresponding branch
1241 // will be removed. Create a region with both counters hard-coded to
1242 // zero. This allows us to visualize them in a special way.
1243 // Alternatively, we can prevent any optimization done via
1244 // constant-folding by ensuring that ConstantFoldsToSimpleInteger() in
1245 // CodeGenFunction.c always returns false, but that is very heavy-handed.
1246 Expr::EvalResult Result;
1247 if (C->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext())) {
1248 if (Result.Val.getInt().getBoolValue())
1249 FalseCnt = Counter::getZero();
1250 else
1251 TrueCnt = Counter::getZero();
1252 }
1253 popRegions(
1254 pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt, BranchParams));
1255 }
1256 }
1257
1258 /// Create a Decision Region with a BitmapIdx and number of Conditions. This
1259 /// type of region "contains" branch regions, one for each of the conditions.
1260 /// The visualization tool will group everything together.
1261 void createDecisionRegion(const Expr *C,
1262 const mcdc::DecisionParameters &DecisionParams) {
1263 popRegions(pushRegion(DecisionParams, getStart(C), getEnd(C)));
1264 }
1265
1266 /// Create a Branch Region around a SwitchCase for code coverage
1267 /// and add it to the function's SourceRegions.
1268 /// Returns Counter that corresponds to SC.
1269 Counter createSwitchCaseRegion(const SwitchCase *SC, Counter ParentCount) {
1270 Counter TrueCnt = getRegionCounter(SC);
1271 Counter FalseCnt = (llvm::EnableSingleByteCoverage
1272 ? Counter::getZero() // Folded
1273 : subtractCounters(ParentCount, TrueCnt));
1274 // Push region onto RegionStack but immediately pop it (which adds it to
1275 // the function's SourceRegions) because it doesn't apply to any other
1276 // source other than the SwitchCase.
1277 popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt));
1278 return TrueCnt;
1279 }
1280
1281 /// Check whether a region with bounds \c StartLoc and \c EndLoc
1282 /// is already added to \c SourceRegions.
1283 bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
1284 bool isBranch = false) {
1285 return llvm::any_of(
1286 llvm::reverse(SourceRegions), [&](const SourceMappingRegion &Region) {
1287 return Region.getBeginLoc() == StartLoc &&
1288 Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
1289 });
1290 }
1291
1292 /// Adjust the most recently visited location to \c EndLoc.
1293 ///
1294 /// This should be used after visiting any statements in non-source order.
1295 void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
1296 MostRecentLocation = EndLoc;
1297 // The code region for a whole macro is created in handleFileExit() when
1298 // it detects exiting of the virtual file of that macro. If we visited
1299 // statements in non-source order, we might already have such a region
1300 // added, for example, if a body of a loop is divided among multiple
1301 // macros. Avoid adding duplicate regions in such case.
1302 if (getRegion().hasEndLoc() &&
1303 MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
1304 isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
1305 MostRecentLocation, getRegion().isBranch()))
1306 MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
1307 }
1308
1309 /// Adjust regions and state when \c NewLoc exits a file.
1310 ///
1311 /// If moving from our most recently tracked location to \c NewLoc exits any
1312 /// files, this adjusts our current region stack and creates the file regions
1313 /// for the exited file.
1314 void handleFileExit(SourceLocation NewLoc) {
1315 if (NewLoc.isInvalid() ||
1316 SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
1317 return;
1318
1319 // If NewLoc is not in a file that contains MostRecentLocation, walk up to
1320 // find the common ancestor.
1321 SourceLocation LCA = NewLoc;
1322 FileID ParentFile = SM.getFileID(LCA);
1323 while (!isNestedIn(MostRecentLocation, ParentFile)) {
1324 LCA = getIncludeOrExpansionLoc(LCA);
1325 if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
1326 // Since there isn't a common ancestor, no file was exited. We just need
1327 // to adjust our location to the new file.
1328 MostRecentLocation = NewLoc;
1329 return;
1330 }
1331 ParentFile = SM.getFileID(LCA);
1332 }
1333
1334 llvm::SmallSet<SourceLocation, 8> StartLocs;
1335 std::optional<Counter> ParentCounter;
1336 for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
1337 if (!I.hasStartLoc())
1338 continue;
1339 SourceLocation Loc = I.getBeginLoc();
1340 if (!isNestedIn(Loc, ParentFile)) {
1341 ParentCounter = I.getCounter();
1342 break;
1343 }
1344
1345 while (!SM.isInFileID(Loc, ParentFile)) {
1346 // The most nested region for each start location is the one with the
1347 // correct count. We avoid creating redundant regions by stopping once
1348 // we've seen this region.
1349 if (StartLocs.insert(Loc).second) {
1350 if (I.isBranch())
1351 SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(),
1352 I.getMCDCParams(), Loc,
1353 getEndOfFileOrMacro(Loc), I.isBranch());
1354 else
1355 SourceRegions.emplace_back(I.getCounter(), Loc,
1356 getEndOfFileOrMacro(Loc));
1357 }
1358 Loc = getIncludeOrExpansionLoc(Loc);
1359 }
1360 I.setStartLoc(getPreciseTokenLocEnd(Loc));
1361 }
1362
1363 if (ParentCounter) {
1364 // If the file is contained completely by another region and doesn't
1365 // immediately start its own region, the whole file gets a region
1366 // corresponding to the parent.
1367 SourceLocation Loc = MostRecentLocation;
1368 while (isNestedIn(Loc, ParentFile)) {
1369 SourceLocation FileStart = getStartOfFileOrMacro(Loc);
1370 if (StartLocs.insert(FileStart).second) {
1371 SourceRegions.emplace_back(*ParentCounter, FileStart,
1372 getEndOfFileOrMacro(Loc));
1373 assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder());
1374 }
1375 Loc = getIncludeOrExpansionLoc(Loc);
1376 }
1377 }
1378
1379 MostRecentLocation = NewLoc;
1380 }
1381
1382 /// Ensure that \c S is included in the current region.
1383 void extendRegion(const Stmt *S) {
1384 SourceMappingRegion &Region = getRegion();
1385 SourceLocation StartLoc = getStart(S);
1386
1387 handleFileExit(StartLoc);
1388 if (!Region.hasStartLoc())
1389 Region.setStartLoc(StartLoc);
1390 }
1391
1392 /// Mark \c S as a terminator, starting a zero region.
1393 void terminateRegion(const Stmt *S) {
1394 extendRegion(S);
1395 SourceMappingRegion &Region = getRegion();
1396 SourceLocation EndLoc = getEnd(S);
1397 if (!Region.hasEndLoc())
1398 Region.setEndLoc(EndLoc);
1399 pushRegion(Counter::getZero());
1400 HasTerminateStmt = true;
1401 }
1402
1403 /// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
1404 std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
1405 SourceLocation BeforeLoc) {
1406 // Some statements (like AttributedStmt and ImplicitValueInitExpr) don't
1407 // have valid source locations. Do not emit a gap region if this is the case
1408 // in either AfterLoc end or BeforeLoc end.
1409 if (AfterLoc.isInvalid() || BeforeLoc.isInvalid())
1410 return std::nullopt;
1411
1412 // If AfterLoc is in function-like macro, use the right parenthesis
1413 // location.
1414 if (AfterLoc.isMacroID()) {
1415 FileID FID = SM.getFileID(AfterLoc);
1416 const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion();
1417 if (EI->isFunctionMacroExpansion())
1418 AfterLoc = EI->getExpansionLocEnd();
1419 }
1420
1421 size_t StartDepth = locationDepth(AfterLoc);
1422 size_t EndDepth = locationDepth(BeforeLoc);
1423 while (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
1424 bool UnnestStart = StartDepth >= EndDepth;
1425 bool UnnestEnd = EndDepth >= StartDepth;
1426 if (UnnestEnd) {
1427 assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1428 BeforeLoc));
1429
1430 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1431 assert(BeforeLoc.isValid());
1432 EndDepth--;
1433 }
1434 if (UnnestStart) {
1435 assert(SM.isWrittenInSameFile(AfterLoc,
1436 getEndOfFileOrMacro(AfterLoc)));
1437
1438 AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
1439 assert(AfterLoc.isValid());
1440 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1441 assert(AfterLoc.isValid());
1442 StartDepth--;
1443 }
1444 }
1445 AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1446 // If the start and end locations of the gap are both within the same macro
1447 // file, the range may not be in source order.
1448 if (AfterLoc.isMacroID() || BeforeLoc.isMacroID())
1449 return std::nullopt;
1450 if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
1451 !SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder())
1452 return std::nullopt;
1453 return {{AfterLoc, BeforeLoc}};
1454 }
1455
1456 /// Emit a gap region between \p StartLoc and \p EndLoc with the given count.
1457 void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
1458 Counter Count) {
1459 if (StartLoc == EndLoc)
1460 return;
1461 assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder());
1462 handleFileExit(StartLoc);
1463 size_t Index = pushRegion(Count, StartLoc, EndLoc);
1464 getRegion().setGap(true);
1465 handleFileExit(EndLoc);
1466 popRegions(Index);
1467 }
1468
1469 /// Find a valid range starting with \p StartingLoc and ending before \p
1470 /// BeforeLoc.
1471 std::optional<SourceRange> findAreaStartingFromTo(SourceLocation StartingLoc,
1472 SourceLocation BeforeLoc) {
1473 // If StartingLoc is in function-like macro, use its start location.
1474 if (StartingLoc.isMacroID()) {
1475 FileID FID = SM.getFileID(StartingLoc);
1476 const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion();
1477 if (EI->isFunctionMacroExpansion())
1478 StartingLoc = EI->getExpansionLocStart();
1479 }
1480
1481 size_t StartDepth = locationDepth(StartingLoc);
1482 size_t EndDepth = locationDepth(BeforeLoc);
1483 while (!SM.isWrittenInSameFile(StartingLoc, BeforeLoc)) {
1484 bool UnnestStart = StartDepth >= EndDepth;
1485 bool UnnestEnd = EndDepth >= StartDepth;
1486 if (UnnestEnd) {
1487 assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1488 BeforeLoc));
1489
1490 BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1491 assert(BeforeLoc.isValid());
1492 EndDepth--;
1493 }
1494 if (UnnestStart) {
1495 assert(SM.isWrittenInSameFile(StartingLoc,
1496 getStartOfFileOrMacro(StartingLoc)));
1497
1498 StartingLoc = getIncludeOrExpansionLoc(StartingLoc);
1499 assert(StartingLoc.isValid());
1500 StartDepth--;
1501 }
1502 }
1503 // If the start and end locations of the gap are both within the same macro
1504 // file, the range may not be in source order.
1505 if (StartingLoc.isMacroID() || BeforeLoc.isMacroID())
1506 return std::nullopt;
1507 if (!SM.isWrittenInSameFile(StartingLoc, BeforeLoc) ||
1508 !SpellingRegion(SM, StartingLoc, BeforeLoc).isInSourceOrder())
1509 return std::nullopt;
1510 return {{StartingLoc, BeforeLoc}};
1511 }
1512
1513 void markSkipped(SourceLocation StartLoc, SourceLocation BeforeLoc) {
1514 const auto Skipped = findAreaStartingFromTo(StartLoc, BeforeLoc);
1515
1516 if (!Skipped)
1517 return;
1518
1519 const auto NewStartLoc = Skipped->getBegin();
1520 const auto EndLoc = Skipped->getEnd();
1521
1522 if (NewStartLoc == EndLoc)
1523 return;
1524 assert(SpellingRegion(SM, NewStartLoc, EndLoc).isInSourceOrder());
1525 handleFileExit(NewStartLoc);
1526 size_t Index = pushRegion(Counter{}, NewStartLoc, EndLoc);
1527 getRegion().setSkipped(true);
1528 handleFileExit(EndLoc);
1529 popRegions(Index);
1530 }
1531
1532 /// Keep counts of breaks and continues inside loops.
1533 struct BreakContinue {
1534 Counter BreakCount;
1535 Counter ContinueCount;
1536 };
1537 SmallVector<BreakContinue, 8> BreakContinueStack;
1538
1539 CounterCoverageMappingBuilder(
1540 CoverageMappingModuleGen &CVM,
1541 llvm::DenseMap<const Stmt *, CounterPair> &CounterMap,
1542 MCDC::State &MCDCState, SourceManager &SM, const LangOptions &LangOpts)
1543 : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
1544 NextCounterNum(CounterMap.size()), MCDCState(MCDCState),
1545 MCDCBuilder(CVM.getCodeGenModule(), MCDCState) {}
1546
1547 /// Write the mapping data to the output stream
1548 void write(llvm::raw_ostream &OS) {
1549 llvm::SmallVector<unsigned, 8> VirtualFileMapping;
1550 gatherFileIDs(VirtualFileMapping);
1551 SourceRegionFilter Filter = emitExpansionRegions();
1552 emitSourceRegions(Filter);
1553 gatherSkippedRegions();
1554
1555 if (MappingRegions.empty())
1556 return;
1557
1558 CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
1559 MappingRegions);
1560 Writer.write(OS);
1561 }
1562
1563 void VisitStmt(const Stmt *S) {
1564 if (S->getBeginLoc().isValid())
1565 extendRegion(S);
1566 const Stmt *LastStmt = nullptr;
1567 bool SaveTerminateStmt = HasTerminateStmt;
1568 HasTerminateStmt = false;
1569 GapRegionCounter = Counter::getZero();
1570 for (const Stmt *Child : S->children())
1571 if (Child) {
1572 // If last statement contains terminate statements, add a gap area
1573 // between the two statements.
1574 if (LastStmt && HasTerminateStmt) {
1575 auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
1576 if (Gap)
1577 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
1578 GapRegionCounter);
1579 SaveTerminateStmt = true;
1580 HasTerminateStmt = false;
1581 }
1582 this->Visit(Child);
1583 LastStmt = Child;
1584 }
1585 if (SaveTerminateStmt)
1586 HasTerminateStmt = true;
1587 handleFileExit(getEnd(S));
1588 }
1589
1590 void VisitStmtExpr(const StmtExpr *E) {
1591 Visit(E->getSubStmt());
1592 // Any region termination (such as a noreturn CallExpr) within the statement
1593 // expression has been handled by visiting the sub-statement. The visitor
1594 // cannot be at a terminate statement leaving the statement expression.
1595 HasTerminateStmt = false;
1596 }
1597
1598 void VisitDecl(const Decl *D) {
1599 Stmt *Body = D->getBody();
1600
1601 // Do not propagate region counts into system headers unless collecting
1602 // coverage from system headers is explicitly enabled.
1603 if (!SystemHeadersCoverage && Body &&
1604 SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
1605 return;
1606
1607 // Do not visit the artificial children nodes of defaulted methods. The
1608 // lexer may not be able to report back precise token end locations for
1609 // these children nodes (llvm.org/PR39822), and moreover users will not be
1610 // able to see coverage for them.
1611 Counter BodyCounter = getRegionCounter(Body);
1612 bool Defaulted = false;
1613 if (auto *Method = dyn_cast<CXXMethodDecl>(D))
1614 Defaulted = Method->isDefaulted();
1615 if (auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
1616 for (auto *Initializer : Ctor->inits()) {
1617 if (Initializer->isWritten()) {
1618 auto *Init = Initializer->getInit();
1619 if (getStart(Init).isValid() && getEnd(Init).isValid())
1620 propagateCounts(BodyCounter, Init);
1621 }
1622 }
1623 }
1624
1625 propagateCounts(BodyCounter, Body,
1626 /*VisitChildren=*/!Defaulted);
1627 assert(RegionStack.empty() && "Regions entered but never exited");
1628 }
1629
1630 void VisitReturnStmt(const ReturnStmt *S) {
1631 extendRegion(S);
1632 if (S->getRetValue())
1633 Visit(S->getRetValue());
1634 terminateRegion(S);
1635 }
1636
1637 void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
1638 extendRegion(S);
1639 Visit(S->getBody());
1640 }
1641
1642 void VisitCoreturnStmt(const CoreturnStmt *S) {
1643 extendRegion(S);
1644 if (S->getOperand())
1645 Visit(S->getOperand());
1646 terminateRegion(S);
1647 }
1648
1649 void VisitCoroutineSuspendExpr(const CoroutineSuspendExpr *E) {
1650 Visit(E->getOperand());
1651 }
1652
1653 void VisitCXXThrowExpr(const CXXThrowExpr *E) {
1654 extendRegion(E);
1655 if (E->getSubExpr())
1656 Visit(E->getSubExpr());
1657 terminateRegion(E);
1658 }
1659
1660 void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); }
1661
1662 void VisitLabelStmt(const LabelStmt *S) {
1663 Counter LabelCount = getRegionCounter(S);
1664 SourceLocation Start = getStart(S);
1665 // We can't extendRegion here or we risk overlapping with our new region.
1666 handleFileExit(Start);
1667 pushRegion(LabelCount, Start);
1668 Visit(S->getSubStmt());
1669 }
1670
1671 void VisitBreakStmt(const BreakStmt *S) {
1672 assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
1673 BreakContinueStack.back().BreakCount = addCounters(
1674 BreakContinueStack.back().BreakCount, getRegion().getCounter());
1675 // FIXME: a break in a switch should terminate regions for all preceding
1676 // case statements, not just the most recent one.
1677 terminateRegion(S);
1678 }
1679
1680 void VisitContinueStmt(const ContinueStmt *S) {
1681 assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
1682 BreakContinueStack.back().ContinueCount = addCounters(
1683 BreakContinueStack.back().ContinueCount, getRegion().getCounter());
1684 terminateRegion(S);
1685 }
1686
1687 void VisitCallExpr(const CallExpr *E) {
1688 VisitStmt(E);
1689
1690 // Terminate the region when we hit a noreturn function.
1691 // (This is helpful dealing with switch statements.)
1692 QualType CalleeType = E->getCallee()->getType();
1693 if (getFunctionExtInfo(*CalleeType).getNoReturn())
1694 terminateRegion(E);
1695 }
1696
1697 void VisitWhileStmt(const WhileStmt *S) {
1698 extendRegion(S);
1699
1700 Counter ParentCount = getRegion().getCounter();
1701 Counter BodyCount = getRegionCounter(S);
1702
1703 // Handle the body first so that we can get the backedge count.
1704 BreakContinueStack.push_back(BreakContinue());
1705 extendRegion(S->getBody());
1706 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1707 BreakContinue BC = BreakContinueStack.pop_back_val();
1708
1709 bool BodyHasTerminateStmt = HasTerminateStmt;
1710 HasTerminateStmt = false;
1711
1712 // Go back to handle the condition.
1713 Counter CondCount =
1714 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1715 auto BranchCount = getBranchCounterPair(S, CondCount);
1716 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1717
1718 propagateCounts(CondCount, S->getCond());
1719 adjustForOutOfOrderTraversal(getEnd(S));
1720
1721 // The body count applies to the area immediately after the increment.
1722 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1723 if (Gap)
1724 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1725
1726 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1727 if (!IsCounterEqual(OutCount, ParentCount)) {
1728 pushRegion(OutCount);
1729 GapRegionCounter = OutCount;
1730 if (BodyHasTerminateStmt)
1731 HasTerminateStmt = true;
1732 }
1733
1734 // Create Branch Region around condition.
1735 createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
1736 }
1737
1738 void VisitDoStmt(const DoStmt *S) {
1739 extendRegion(S);
1740
1741 Counter ParentCount = getRegion().getCounter();
1742 Counter BodyCount = getRegionCounter(S);
1743
1744 BreakContinueStack.push_back(BreakContinue());
1745 extendRegion(S->getBody());
1746
1747 Counter BackedgeCount =
1748 propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
1749
1750 BreakContinue BC = BreakContinueStack.pop_back_val();
1751
1752 bool BodyHasTerminateStmt = HasTerminateStmt;
1753 HasTerminateStmt = false;
1754
1755 Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
1756 auto BranchCount = getBranchCounterPair(S, CondCount);
1757 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1758
1759 propagateCounts(CondCount, S->getCond());
1760
1761 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1762 if (!IsCounterEqual(OutCount, ParentCount)) {
1763 pushRegion(OutCount);
1764 GapRegionCounter = OutCount;
1765 if (BodyHasTerminateStmt)
1766 HasTerminateStmt = true;
1767 }
1768
1769 // Create Branch Region around condition.
1770 createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
1771 }
1772
1773 void VisitForStmt(const ForStmt *S) {
1774 extendRegion(S);
1775 if (S->getInit())
1776 Visit(S->getInit());
1777
1778 Counter ParentCount = getRegion().getCounter();
1779 Counter BodyCount = getRegionCounter(S);
1780
1781 // The loop increment may contain a break or continue.
1782 if (S->getInc())
1783 BreakContinueStack.emplace_back();
1784
1785 // Handle the body first so that we can get the backedge count.
1786 BreakContinueStack.emplace_back();
1787 extendRegion(S->getBody());
1788 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1789 BreakContinue BodyBC = BreakContinueStack.pop_back_val();
1790
1791 bool BodyHasTerminateStmt = HasTerminateStmt;
1792 HasTerminateStmt = false;
1793
1794 // The increment is essentially part of the body but it needs to include
1795 // the count for all the continue statements.
1796 BreakContinue IncrementBC;
1797 if (const Stmt *Inc = S->getInc()) {
1798 propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
1799 IncrementBC = BreakContinueStack.pop_back_val();
1800 }
1801
1802 // Go back to handle the condition.
1803 Counter CondCount = addCounters(
1804 addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
1805 IncrementBC.ContinueCount);
1806 auto BranchCount = getBranchCounterPair(S, CondCount);
1807 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1808
1809 if (const Expr *Cond = S->getCond()) {
1810 propagateCounts(CondCount, Cond);
1811 adjustForOutOfOrderTraversal(getEnd(S));
1812 }
1813
1814 // The body count applies to the area immediately after the increment.
1815 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1816 if (Gap)
1817 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1818
1819 Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
1820 BranchCount.Skipped);
1821 if (!IsCounterEqual(OutCount, ParentCount)) {
1822 pushRegion(OutCount);
1823 GapRegionCounter = OutCount;
1824 if (BodyHasTerminateStmt)
1825 HasTerminateStmt = true;
1826 }
1827
1828 // Create Branch Region around condition.
1829 createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
1830 }
1831
1832 void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
1833 extendRegion(S);
1834 if (S->getInit())
1835 Visit(S->getInit());
1836 Visit(S->getLoopVarStmt());
1837 Visit(S->getRangeStmt());
1838
1839 Counter ParentCount = getRegion().getCounter();
1840 Counter BodyCount = getRegionCounter(S);
1841
1842 BreakContinueStack.push_back(BreakContinue());
1843 extendRegion(S->getBody());
1844 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1845 BreakContinue BC = BreakContinueStack.pop_back_val();
1846
1847 bool BodyHasTerminateStmt = HasTerminateStmt;
1848 HasTerminateStmt = false;
1849
1850 // The body count applies to the area immediately after the range.
1851 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1852 if (Gap)
1853 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1854
1855 Counter LoopCount =
1856 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1857 auto BranchCount = getBranchCounterPair(S, LoopCount);
1858 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1859
1860 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1861 if (!IsCounterEqual(OutCount, ParentCount)) {
1862 pushRegion(OutCount);
1863 GapRegionCounter = OutCount;
1864 if (BodyHasTerminateStmt)
1865 HasTerminateStmt = true;
1866 }
1867
1868 // Create Branch Region around condition.
1869 createBranchRegion(S->getCond(), BodyCount, BranchCount.Skipped);
1870 }
1871
1872 void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
1873 extendRegion(S);
1874 Visit(S->getElement());
1875
1876 Counter ParentCount = getRegion().getCounter();
1877 Counter BodyCount = getRegionCounter(S);
1878
1879 BreakContinueStack.push_back(BreakContinue());
1880 extendRegion(S->getBody());
1881 Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
1882 BreakContinue BC = BreakContinueStack.pop_back_val();
1883
1884 // The body count applies to the area immediately after the collection.
1885 auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
1886 if (Gap)
1887 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
1888
1889 Counter LoopCount =
1890 addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
1891 auto BranchCount = getBranchCounterPair(S, LoopCount);
1892 assert(BranchCount.Executed.isZero() || BranchCount.Executed == BodyCount);
1893 Counter OutCount = addCounters(BC.BreakCount, BranchCount.Skipped);
1894 if (!IsCounterEqual(OutCount, ParentCount)) {
1895 pushRegion(OutCount);
1896 GapRegionCounter = OutCount;
1897 }
1898 }
1899
1900 void VisitSwitchStmt(const SwitchStmt *S) {
1901 extendRegion(S);
1902 if (S->getInit())
1903 Visit(S->getInit());
1904 Visit(S->getCond());
1905
1906 BreakContinueStack.push_back(BreakContinue());
1907
1908 const Stmt *Body = S->getBody();
1909 extendRegion(Body);
1910 if (const auto *CS = dyn_cast<CompoundStmt>(Body)) {
1911 if (!CS->body_empty()) {
1912 // Make a region for the body of the switch. If the body starts with
1913 // a case, that case will reuse this region; otherwise, this covers
1914 // the unreachable code at the beginning of the switch body.
1915 size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1916 getRegion().setGap(true);
1917 Visit(Body);
1918
1919 // Set the end for the body of the switch, if it isn't already set.
1920 for (size_t i = RegionStack.size(); i != Index; --i) {
1921 if (!RegionStack[i - 1].hasEndLoc())
1922 RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
1923 }
1924
1925 popRegions(Index);
1926 }
1927 } else
1928 propagateCounts(Counter::getZero(), Body);
1929 BreakContinue BC = BreakContinueStack.pop_back_val();
1930
1931 if (!BreakContinueStack.empty())
1932 BreakContinueStack.back().ContinueCount = addCounters(
1933 BreakContinueStack.back().ContinueCount, BC.ContinueCount);
1934
1935 Counter ParentCount = getRegion().getCounter();
1936 Counter ExitCount = getRegionCounter(S);
1937 SourceLocation ExitLoc = getEnd(S);
1938 pushRegion(ExitCount);
1939 GapRegionCounter = ExitCount;
1940
1941 // Ensure that handleFileExit recognizes when the end location is located
1942 // in a different file.
1943 MostRecentLocation = getStart(S);
1944 handleFileExit(ExitLoc);
1945
1946 // Create a Branch Region around each Case. Subtract the case's
1947 // counter from the Parent counter to track the "False" branch count.
1948 Counter CaseCountSum;
1949 bool HasDefaultCase = false;
1950 const SwitchCase *Case = S->getSwitchCaseList();
1951 for (; Case; Case = Case->getNextSwitchCase()) {
1952 HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case);
1953 auto CaseCount = createSwitchCaseRegion(Case, ParentCount);
1954 CaseCountSum = addCounters(CaseCountSum, CaseCount, /*Simplify=*/false);
1955 }
1956 // If no explicit default case exists, create a branch region to represent
1957 // the hidden branch, which will be added later by the CodeGen. This region
1958 // will be associated with the switch statement's condition.
1959 if (!HasDefaultCase) {
1960 auto Counters = getSwitchImplicitDefaultCounterPair(
1961 S->getCond(), ParentCount, CaseCountSum);
1962 createBranchRegion(S->getCond(), Counters.first, Counters.second);
1963 }
1964 }
1965
1966 void VisitSwitchCase(const SwitchCase *S) {
1967 extendRegion(S);
1968
1969 SourceMappingRegion &Parent = getRegion();
1970 Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
1971
1972 // Reuse the existing region if it starts at our label. This is typical of
1973 // the first case in a switch.
1974 if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
1975 Parent.setCounter(Count);
1976 else
1977 pushRegion(Count, getStart(S));
1978
1979 GapRegionCounter = Count;
1980
1981 if (const auto *CS = dyn_cast<CaseStmt>(S)) {
1982 Visit(CS->getLHS());
1983 if (const Expr *RHS = CS->getRHS())
1984 Visit(RHS);
1985 }
1986 Visit(S->getSubStmt());
1987 }
1988
1989 void coverIfConsteval(const IfStmt *S) {
1990 assert(S->isConsteval());
1991
1992 const auto *Then = S->getThen();
1993 const auto *Else = S->getElse();
1994
1995 // It's better for llvm-cov to create a new region with same counter
1996 // so line-coverage can be properly calculated for lines containing
1997 // a skipped region (without it the line is marked uncovered)
1998 const Counter ParentCount = getRegion().getCounter();
1999
2000 extendRegion(S);
2001
2002 if (S->isNegatedConsteval()) {
2003 // ignore 'if consteval'
2004 markSkipped(S->getIfLoc(), getStart(Then));
2005 propagateCounts(ParentCount, Then);
2006
2007 if (Else) {
2008 // ignore 'else <else>'
2009 markSkipped(getEnd(Then), getEnd(Else));
2010 }
2011 } else {
2012 assert(S->isNonNegatedConsteval());
2013 // ignore 'if consteval <then> [else]'
2014 markSkipped(S->getIfLoc(), Else ? getStart(Else) : getEnd(Then));
2015
2016 if (Else)
2017 propagateCounts(ParentCount, Else);
2018 }
2019 }
2020
2021 void coverIfConstexpr(const IfStmt *S) {
2022 assert(S->isConstexpr());
2023
2024 // evaluate constant condition...
2025 const bool isTrue =
2026 S->getCond()
2028 .getBoolValue();
2029
2030 extendRegion(S);
2031
2032 // I'm using 'propagateCounts' later as new region is better and allows me
2033 // to properly calculate line coverage in llvm-cov utility
2034 const Counter ParentCount = getRegion().getCounter();
2035
2036 // ignore 'if constexpr ('
2037 SourceLocation startOfSkipped = S->getIfLoc();
2038
2039 if (const auto *Init = S->getInit()) {
2040 const auto start = getStart(Init);
2041 const auto end = getEnd(Init);
2042
2043 // this check is to make sure typedef here which doesn't have valid source
2044 // location won't crash it
2045 if (start.isValid() && end.isValid()) {
2046 markSkipped(startOfSkipped, start);
2047 propagateCounts(ParentCount, Init);
2048 startOfSkipped = getEnd(Init);
2049 }
2050 }
2051
2052 const auto *Then = S->getThen();
2053 const auto *Else = S->getElse();
2054
2055 if (isTrue) {
2056 // ignore '<condition>)'
2057 markSkipped(startOfSkipped, getStart(Then));
2058 propagateCounts(ParentCount, Then);
2059
2060 if (Else)
2061 // ignore 'else <else>'
2062 markSkipped(getEnd(Then), getEnd(Else));
2063 } else {
2064 // ignore '<condition>) <then> [else]'
2065 markSkipped(startOfSkipped, Else ? getStart(Else) : getEnd(Then));
2066
2067 if (Else)
2068 propagateCounts(ParentCount, Else);
2069 }
2070 }
2071
2072 void VisitIfStmt(const IfStmt *S) {
2073 // "if constexpr" and "if consteval" are not normal conditional statements,
2074 // their discarded statement should be skipped
2075 if (S->isConsteval())
2076 return coverIfConsteval(S);
2077 else if (S->isConstexpr())
2078 return coverIfConstexpr(S);
2079
2080 extendRegion(S);
2081 if (S->getInit())
2082 Visit(S->getInit());
2083
2084 // Extend into the condition before we propagate through it below - this is
2085 // needed to handle macros that generate the "if" but not the condition.
2086 extendRegion(S->getCond());
2087
2088 Counter ParentCount = getRegion().getCounter();
2089 auto [ThenCount, ElseCount] = getBranchCounterPair(S, ParentCount);
2090
2091 // Emitting a counter for the condition makes it easier to interpret the
2092 // counter for the body when looking at the coverage.
2093 propagateCounts(ParentCount, S->getCond());
2094
2095 // The 'then' count applies to the area immediately after the condition.
2096 std::optional<SourceRange> Gap =
2097 findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
2098 if (Gap)
2099 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
2100
2101 extendRegion(S->getThen());
2102 Counter OutCount = propagateCounts(ThenCount, S->getThen());
2103
2104 if (const Stmt *Else = S->getElse()) {
2105 bool ThenHasTerminateStmt = HasTerminateStmt;
2106 HasTerminateStmt = false;
2107 // The 'else' count applies to the area immediately after the 'then'.
2108 std::optional<SourceRange> Gap =
2109 findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
2110 if (Gap)
2111 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
2112 extendRegion(Else);
2113
2114 OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
2115
2116 if (ThenHasTerminateStmt)
2117 HasTerminateStmt = true;
2118 } else
2119 OutCount = addCounters(OutCount, ElseCount);
2120
2121 if (!IsCounterEqual(OutCount, ParentCount)) {
2122 pushRegion(OutCount);
2123 GapRegionCounter = OutCount;
2124 }
2125
2126 // Create Branch Region around condition.
2127 createBranchRegion(S->getCond(), ThenCount, ElseCount);
2128 }
2129
2130 void VisitCXXTryStmt(const CXXTryStmt *S) {
2131 extendRegion(S);
2132 // Handle macros that generate the "try" but not the rest.
2133 extendRegion(S->getTryBlock());
2134
2135 Counter ParentCount = getRegion().getCounter();
2136 propagateCounts(ParentCount, S->getTryBlock());
2137
2138 for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
2139 Visit(S->getHandler(I));
2140
2141 Counter ExitCount = getRegionCounter(S);
2142 pushRegion(ExitCount);
2143 }
2144
2145 void VisitCXXCatchStmt(const CXXCatchStmt *S) {
2146 propagateCounts(getRegionCounter(S), S->getHandlerBlock());
2147 }
2148
2149 void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
2150 extendRegion(E);
2151
2152 Counter ParentCount = getRegion().getCounter();
2153 auto [TrueCount, FalseCount] = getBranchCounterPair(E, ParentCount);
2154 Counter OutCount;
2155
2156 if (const auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) {
2157 propagateCounts(ParentCount, BCO->getCommon());
2158 OutCount = TrueCount;
2159 } else {
2160 propagateCounts(ParentCount, E->getCond());
2161 // The 'then' count applies to the area immediately after the condition.
2162 auto Gap =
2163 findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr()));
2164 if (Gap)
2165 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
2166
2167 extendRegion(E->getTrueExpr());
2168 OutCount = propagateCounts(TrueCount, E->getTrueExpr());
2169 }
2170
2171 extendRegion(E->getFalseExpr());
2172 OutCount =
2173 addCounters(OutCount, propagateCounts(FalseCount, E->getFalseExpr()));
2174
2175 if (!IsCounterEqual(OutCount, ParentCount)) {
2176 pushRegion(OutCount);
2177 GapRegionCounter = OutCount;
2178 }
2179
2180 // Create Branch Region around condition.
2181 createBranchRegion(E->getCond(), TrueCount, FalseCount);
2182 }
2183
2184 inline unsigned findMCDCBranchesInSourceRegion(
2185 unsigned Since, std::function<void(SourceMappingRegion &SR)> CB) {
2186 unsigned I = SourceRegions.size() - 1;
2187 unsigned Count = 0;
2188 while (I >= Since) {
2189 auto &SR = SourceRegions[I];
2190 if (SR.isMCDCDecision()) {
2191 // Skip a sub Decision and don't modify records in it.
2192 I = MCDCBuilder.skipSourceRegionIndexForDecisions(I);
2193 } else if (SR.isMCDCBranch()) {
2194 ++Count;
2195 CB(SR);
2196 }
2197
2198 if (I-- <= Since)
2199 break;
2200 }
2201
2202 return Count;
2203 }
2204
2205 void createOrCancelDecision(const Expr *E, unsigned Since) {
2206 auto *SC = CodeGenFunction::stripCond(E);
2207 auto NumConds = MCDCBuilder.getTotalConditionsAndPop(SC);
2208 if (NumConds == 0)
2209 return;
2210
2211 // Extract [ID, Conds] to construct the graph.
2212 llvm::SmallVector<mcdc::ConditionIDs> CondIDs(NumConds);
2213 findMCDCBranchesInSourceRegion(Since, [&](const SourceMappingRegion &SR) {
2214 auto [ID, Conds] = SR.getMCDCBranchParams();
2215 CondIDs[ID] = Conds;
2216 });
2217
2218 // Construct the graph and calculate `Indices`.
2219 mcdc::TVIdxBuilder Builder(CondIDs);
2220 unsigned NumTVs = Builder.NumTestVectors;
2221 unsigned MaxTVs = CVM.getCodeGenModule().getCodeGenOpts().MCDCMaxTVs;
2222 assert(MaxTVs < mcdc::TVIdxBuilder::HardMaxTVs);
2223
2224 if (NumTVs > MaxTVs) {
2225 // NumTVs exceeds MaxTVs -- warn and cancel the Decision.
2226 cancelDecision(SC, Since, NumTVs, MaxTVs, NumConds);
2227 return;
2228 }
2229
2230 // Update the state for CodeGenPGO
2231 assert(MCDCState.DecisionByStmt.contains(SC));
2232 MCDCState.DecisionByStmt[SC].update(MCDCState.BitmapBits, // Top
2233 std::move(Builder.Indices));
2234
2235 auto DecisionParams = mcdc::DecisionParameters{
2236 MCDCState.BitmapBits += NumTVs, // Tail
2237 NumConds,
2238 };
2239
2240 // Create MCDC Decision Region.
2241 createDecisionRegion(E, DecisionParams);
2242
2243 // Memo
2244 assert(SourceRegions.back().isMCDCDecision());
2245 MCDCBuilder.addDecisionRegionRange(Since, SourceRegions.size() - 1);
2246 }
2247
2248 // Warn and cancel the Decision.
2249 void cancelDecision(const Expr *Decision, unsigned Since, int NumTVs,
2250 int MaxTVs, unsigned NumConds) {
2251 auto &Diag = CVM.getCodeGenModule().getDiags();
2252 Diag.Report(Decision->getBeginLoc(), diag::warn_pgo_test_vector_limit)
2253 << NumTVs << MaxTVs;
2254
2255 // Restore MCDCBranch to Branch.
2256 unsigned FoundCount = findMCDCBranchesInSourceRegion(
2257 Since, [](SourceMappingRegion &SR) { SR.resetMCDCParams(); });
2258 assert(FoundCount == NumConds &&
2259 "Didn't find all MCDCBranches to be restored");
2260 (void)FoundCount;
2261
2262 // Tell CodeGenPGO not to instrument.
2263 MCDCState.BranchByStmt.remove_if([&](const auto &Entry) {
2264 return Entry.second.DecisionStmt == Decision;
2265 });
2266 MCDCState.DecisionByStmt.erase(Decision);
2267 }
2268
2269 /// Check if E belongs to system headers.
2270 bool isExprInSystemHeader(const BinaryOperator *E) const {
2271 return (!SystemHeadersCoverage &&
2275 }
2276
2277 void VisitUnaryLNot(const UnaryOperator *E) {
2278 MCDCBuilder.swapConds();
2279 Visit(E->getSubExpr());
2280 MCDCBuilder.swapConds();
2281 }
2282
2283 void VisitBinLAnd(const BinaryOperator *E) {
2284 if (isExprInSystemHeader(E)) {
2285 LeafExprSet.insert(E);
2286 return;
2287 }
2288
2289 unsigned SourceRegionsSince = SourceRegions.size();
2290
2291 // Keep track of Binary Operator and assign MCDC condition IDs.
2292 auto [_, RHSid] = MCDCBuilder.pushAndAssignIDs(E);
2293
2294 // DecisionRHS inherits CurCondIDs.
2295 auto &CurCondIDs = MCDCBuilder.getCurCondIDs();
2296 auto DecisionRHS = CurCondIDs;
2297
2298 CurCondIDs[true] = RHSid;
2299 auto DecisionLHS = CurCondIDs;
2300
2301 extendRegion(E->getLHS());
2302 propagateCounts(getRegion().getCounter(), E->getLHS());
2303 handleFileExit(getEnd(E->getLHS()));
2304
2305 // Restore CurCondIDs.
2306 {
2307 auto &CurCondIDs =
2308 MCDCBuilder.getCurCondIDs(); // Stack may be reallocated.
2309 CurCondIDs[true] = DecisionRHS[true];
2310 assert(CurCondIDs == DecisionRHS);
2311 }
2312
2313 if (auto Gap =
2314 findGapAreaBetween(getEnd(E->getLHS()), getStart(E->getRHS()))) {
2315 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));
2316 }
2317
2318 // Counter tracks the right hand side of a logical and operator.
2319 extendRegion(E->getRHS());
2320 propagateCounts(getRegionCounter(E), E->getRHS());
2321
2322 // Extract the Parent Region Counter.
2323 Counter ParentCnt = getRegion().getCounter();
2324
2325 // Extract the RHS's Execution Counter.
2326 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2327
2328 // Extract the RHS's "True" Instance Counter.
2329 auto [RHSTrueCnt, RHSExitCnt] =
2330 getBranchCounterPair(E->getRHS(), RHSExecCnt);
2331
2332 // Create Branch Region around LHS condition.
2333 createBranchRegion(E->getLHS(), RHSExecCnt, LHSExitCnt, DecisionLHS);
2334
2335 // Create Branch Region around RHS condition.
2336 createBranchRegion(E->getRHS(), RHSTrueCnt, RHSExitCnt, DecisionRHS);
2337
2338 // Create MCDC Decision Region when E is at the top level.
2339 createOrCancelDecision(E, SourceRegionsSince);
2340 }
2341
2342 // Determine whether the right side of OR operation need to be visited.
2343 bool shouldVisitRHS(const Expr *LHS) {
2344 bool LHSIsTrue = false;
2345 bool LHSIsConst = false;
2346 if (!LHS->isValueDependent())
2347 LHSIsConst = LHS->EvaluateAsBooleanCondition(
2348 LHSIsTrue, CVM.getCodeGenModule().getContext());
2349 return !LHSIsConst || (LHSIsConst && !LHSIsTrue);
2350 }
2351
2352 void VisitBinLOr(const BinaryOperator *E) {
2353 if (isExprInSystemHeader(E)) {
2354 LeafExprSet.insert(E);
2355 return;
2356 }
2357
2358 unsigned SourceRegionsSince = SourceRegions.size();
2359
2360 // Keep track of Binary Operator and assign MCDC condition IDs.
2361 auto [_, RHSid] = MCDCBuilder.pushAndAssignIDs(E);
2362
2363 // Push the LHS decision IDs onto the DecisionStack.
2364 auto &CurCondIDs = MCDCBuilder.getCurCondIDs();
2365 auto DecisionRHS = CurCondIDs;
2366 CurCondIDs[false] = RHSid;
2367 auto DecisionLHS = CurCondIDs;
2368
2369 extendRegion(E->getLHS());
2370 Counter OutCount = propagateCounts(getRegion().getCounter(), E->getLHS());
2371 handleFileExit(getEnd(E->getLHS()));
2372
2373 // Track LHS True/False Decision.
2374 {
2375 auto &CurCondIDs =
2376 MCDCBuilder.getCurCondIDs(); // Stack may be reallocated.
2377 CurCondIDs[false] = DecisionRHS[false];
2378 assert(CurCondIDs == DecisionRHS);
2379 }
2380
2381 if (auto Gap =
2382 findGapAreaBetween(getEnd(E->getLHS()), getStart(E->getRHS()))) {
2383 fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), getRegionCounter(E));
2384 }
2385
2386 // Counter tracks the right hand side of a logical or operator.
2387 extendRegion(E->getRHS());
2388 propagateCounts(getRegionCounter(E), E->getRHS());
2389
2390 // Extract the Parent Region Counter.
2391 Counter ParentCnt = getRegion().getCounter();
2392
2393 // Extract the RHS's Execution Counter.
2394 auto [RHSExecCnt, LHSExitCnt] = getBranchCounterPair(E, ParentCnt);
2395
2396 // Extract the RHS's "False" Instance Counter.
2397 auto [RHSFalseCnt, RHSExitCnt] =
2398 getBranchCounterPair(E->getRHS(), RHSExecCnt);
2399
2400 if (!shouldVisitRHS(E->getLHS())) {
2401 GapRegionCounter = OutCount;
2402 }
2403
2404 // Create Branch Region around LHS condition.
2405 createBranchRegion(E->getLHS(), LHSExitCnt, RHSExecCnt, DecisionLHS);
2406
2407 // Create Branch Region around RHS condition.
2408 createBranchRegion(E->getRHS(), RHSExitCnt, RHSFalseCnt, DecisionRHS);
2409
2410 // Create MCDC Decision Region when E is at the top level.
2411 createOrCancelDecision(E, SourceRegionsSince);
2412 }
2413
2414 void VisitLambdaExpr(const LambdaExpr *LE) {
2415 // Lambdas are treated as their own functions for now, so we shouldn't
2416 // propagate counts into them.
2417 }
2418
2419 void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *AILE) {
2420 Visit(AILE->getCommonExpr()->getSourceExpr());
2421 }
2422
2423 void VisitPseudoObjectExpr(const PseudoObjectExpr *POE) {
2424 // Just visit syntatic expression as this is what users actually write.
2425 VisitStmt(POE->getSyntacticForm());
2426 }
2427
2428 void VisitOpaqueValueExpr(const OpaqueValueExpr* OVE) {
2429 if (OVE->isUnique())
2430 Visit(OVE->getSourceExpr());
2431 }
2432};
2433
2434} // end anonymous namespace
2435
2436static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
2437 ArrayRef<CounterExpression> Expressions,
2439 OS << FunctionName << ":\n";
2440 CounterMappingContext Ctx(Expressions);
2441 for (const auto &R : Regions) {
2442 OS.indent(2);
2443 switch (R.Kind) {
2444 case CounterMappingRegion::CodeRegion:
2445 break;
2446 case CounterMappingRegion::ExpansionRegion:
2447 OS << "Expansion,";
2448 break;
2449 case CounterMappingRegion::SkippedRegion:
2450 OS << "Skipped,";
2451 break;
2452 case CounterMappingRegion::GapRegion:
2453 OS << "Gap,";
2454 break;
2455 case CounterMappingRegion::BranchRegion:
2456 case CounterMappingRegion::MCDCBranchRegion:
2457 OS << "Branch,";
2458 break;
2459 case CounterMappingRegion::MCDCDecisionRegion:
2460 OS << "Decision,";
2461 break;
2462 }
2463
2464 OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
2465 << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = ";
2466
2467 if (const auto *DecisionParams =
2468 std::get_if<mcdc::DecisionParameters>(&R.MCDCParams)) {
2469 OS << "M:" << DecisionParams->BitmapIdx;
2470 OS << ", C:" << DecisionParams->NumConditions;
2471 } else {
2472 Ctx.dump(R.Count, OS);
2473
2474 if (R.isBranch()) {
2475 OS << ", ";
2476 Ctx.dump(R.FalseCount, OS);
2477 }
2478 }
2479
2480 if (const auto *BranchParams =
2481 std::get_if<mcdc::BranchParameters>(&R.MCDCParams)) {
2482 OS << " [" << BranchParams->ID + 1 << ","
2483 << BranchParams->Conds[true] + 1;
2484 OS << "," << BranchParams->Conds[false] + 1 << "] ";
2485 }
2486
2487 if (R.Kind == CounterMappingRegion::ExpansionRegion)
2488 OS << " (Expanded file = " << R.ExpandedFileID << ")";
2489 OS << "\n";
2490 }
2491}
2492
2494 CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
2495 : CGM(CGM), SourceInfo(SourceInfo) {}
2496
2497std::string CoverageMappingModuleGen::getCurrentDirname() {
2499}
2500
2501std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
2502 llvm::SmallString<256> Path(Filename);
2503 llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
2504
2505 /// Traverse coverage prefix map in reverse order because prefix replacements
2506 /// are applied in reverse order starting from the last one when multiple
2507 /// prefix replacement options are provided.
2508 for (const auto &[From, To] :
2509 llvm::reverse(CGM.getCodeGenOpts().CoveragePrefixMap)) {
2510 if (llvm::sys::path::replace_path_prefix(Path, From, To))
2511 break;
2512 }
2513 return Path.str().str();
2514}
2515
2516static std::string getInstrProfSection(const CodeGenModule &CGM,
2517 llvm::InstrProfSectKind SK) {
2518 return llvm::getInstrProfSectionName(
2519 SK, CGM.getContext().getTargetInfo().getTriple().getObjectFormat());
2520}
2521
2522void CoverageMappingModuleGen::emitFunctionMappingRecord(
2523 const FunctionInfo &Info, uint64_t FilenamesRef) {
2524 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
2525
2526 // Assign a name to the function record. This is used to merge duplicates.
2527 std::string FuncRecordName = "__covrec_" + llvm::utohexstr(Info.NameHash);
2528
2529 // A dummy description for a function included-but-not-used in a TU can be
2530 // replaced by full description provided by a different TU. The two kinds of
2531 // descriptions play distinct roles: therefore, assign them different names
2532 // to prevent `linkonce_odr` merging.
2533 if (Info.IsUsed)
2534 FuncRecordName += "u";
2535
2536 // Create the function record type.
2537 const uint64_t NameHash = Info.NameHash;
2538 const uint64_t FuncHash = Info.FuncHash;
2539 const std::string &CoverageMapping = Info.CoverageMapping;
2540#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
2541 llvm::Type *FunctionRecordTypes[] = {
2542#include "llvm/ProfileData/InstrProfData.inc"
2543 };
2544 auto *FunctionRecordTy =
2545 llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes),
2546 /*isPacked=*/true);
2547
2548 // Create the function record constant.
2549#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
2550 llvm::Constant *FunctionRecordVals[] = {
2551 #include "llvm/ProfileData/InstrProfData.inc"
2552 };
2553 auto *FuncRecordConstant =
2554 llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals));
2555
2556 // Create the function record global.
2557 auto *FuncRecord = new llvm::GlobalVariable(
2558 CGM.getModule(), FunctionRecordTy, /*isConstant=*/true,
2559 llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
2560 FuncRecordName);
2561 FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
2562 FuncRecord->setSection(getInstrProfSection(CGM, llvm::IPSK_covfun));
2563 FuncRecord->setAlignment(llvm::Align(8));
2564 if (CGM.supportsCOMDAT())
2565 FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
2566
2567 // Make sure the data doesn't get deleted.
2568 CGM.addUsedGlobal(FuncRecord);
2569}
2570
2572 llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
2573 const std::string &CoverageMapping, bool IsUsed) {
2574 const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
2575 FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
2576
2577 if (!IsUsed)
2578 FunctionNames.push_back(NamePtr);
2579
2580 if (CGM.getCodeGenOpts().DumpCoverageMapping) {
2581 // Dump the coverage mapping data for this function by decoding the
2582 // encoded data. This allows us to dump the mapping regions which were
2583 // also processed by the CoverageMappingWriter which performs
2584 // additional minimization operations such as reducing the number of
2585 // expressions.
2587 std::vector<StringRef> Filenames;
2588 std::vector<CounterExpression> Expressions;
2589 std::vector<CounterMappingRegion> Regions;
2590 FilenameStrs.resize(FileEntries.size() + 1);
2591 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2592 for (const auto &Entry : FileEntries) {
2593 auto I = Entry.second;
2594 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2595 }
2596 ArrayRef<std::string> FilenameRefs = llvm::ArrayRef(FilenameStrs);
2597 RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
2598 Expressions, Regions);
2599 if (Reader.read())
2600 return;
2601 dump(llvm::outs(), NameValue, Expressions, Regions);
2602 }
2603}
2604
2606 if (FunctionRecords.empty())
2607 return;
2608 llvm::LLVMContext &Ctx = CGM.getLLVMContext();
2609 auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
2610
2611 // Create the filenames and merge them with coverage mappings
2613 FilenameStrs.resize(FileEntries.size() + 1);
2614 // The first filename is the current working directory.
2615 FilenameStrs[0] = normalizeFilename(getCurrentDirname());
2616 for (const auto &Entry : FileEntries) {
2617 auto I = Entry.second;
2618 FilenameStrs[I] = normalizeFilename(Entry.first.getName());
2619 }
2620
2621 std::string Filenames;
2622 {
2623 llvm::raw_string_ostream OS(Filenames);
2624 CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
2625 }
2626 auto *FilenamesVal =
2627 llvm::ConstantDataArray::getString(Ctx, Filenames, false);
2628 const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
2629
2630 // Emit the function records.
2631 for (const FunctionInfo &Info : FunctionRecords)
2632 emitFunctionMappingRecord(Info, FilenamesRef);
2633
2634 const unsigned NRecords = 0;
2635 const size_t FilenamesSize = Filenames.size();
2636 const unsigned CoverageMappingSize = 0;
2637 llvm::Type *CovDataHeaderTypes[] = {
2638#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
2639#include "llvm/ProfileData/InstrProfData.inc"
2640 };
2641 auto CovDataHeaderTy =
2642 llvm::StructType::get(Ctx, ArrayRef(CovDataHeaderTypes));
2643 llvm::Constant *CovDataHeaderVals[] = {
2644#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
2645#include "llvm/ProfileData/InstrProfData.inc"
2646 };
2647 auto CovDataHeaderVal =
2648 llvm::ConstantStruct::get(CovDataHeaderTy, ArrayRef(CovDataHeaderVals));
2649
2650 // Create the coverage data record
2651 llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
2652 auto CovDataTy = llvm::StructType::get(Ctx, ArrayRef(CovDataTypes));
2653 llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
2654 auto CovDataVal = llvm::ConstantStruct::get(CovDataTy, ArrayRef(TUDataVals));
2655 auto CovData = new llvm::GlobalVariable(
2656 CGM.getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage,
2657 CovDataVal, llvm::getCoverageMappingVarName());
2658
2659 CovData->setSection(getInstrProfSection(CGM, llvm::IPSK_covmap));
2660 CovData->setAlignment(llvm::Align(8));
2661
2662 // Make sure the data doesn't get deleted.
2663 CGM.addUsedGlobal(CovData);
2664 // Create the deferred function records array
2665 if (!FunctionNames.empty()) {
2666 auto AddrSpace = FunctionNames.front()->getType()->getPointerAddressSpace();
2667 auto NamesArrTy = llvm::ArrayType::get(
2668 llvm::PointerType::get(Ctx, AddrSpace), FunctionNames.size());
2669 auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
2670 // This variable will *NOT* be emitted to the object file. It is used
2671 // to pass the list of names referenced to codegen.
2672 new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
2673 llvm::GlobalValue::InternalLinkage, NamesArrVal,
2674 llvm::getCoverageUnusedNamesVarName());
2675 }
2676}
2677
2679 return FileEntries.try_emplace(File, FileEntries.size() + 1).first->second;
2680}
2681
2683 llvm::raw_ostream &OS) {
2684 assert(CounterMap && MCDCState);
2685 CounterCoverageMappingBuilder Walker(CVM, *CounterMap, *MCDCState, SM,
2686 LangOpts);
2687 Walker.VisitDecl(D);
2688 Walker.write(OS);
2689}
2690
2692 llvm::raw_ostream &OS) {
2693 EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
2694 Walker.VisitDecl(D);
2695 Walker.write(OS);
2696}
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)
Token Tok
The Token.
Result
Implement __builtin_bit_cast and related operations.
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
Definition ASTContext.h:927
Expr * getCond() const
getCond - Return the expression representing the condition for the ?
Definition Expr.h:4537
Expr * getTrueExpr() const
getTrueExpr - Return the subexpression representing the value of the expression if the condition eval...
Definition Expr.h:4543
SourceLocation getQuestionLoc() const
Definition Expr.h:4386
Expr * getFalseExpr() const
getFalseExpr - Return the subexpression representing the value of the expression if the condition eva...
Definition Expr.h:4549
OpaqueValueExpr * getCommonExpr() const
Get the common subexpression shared by all initializations (the source array).
Definition Expr.h:5995
Expr * getLHS() const
Definition Expr.h:4094
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Expr.h:4099
SourceLocation getOperatorLoc() const
Definition Expr.h:4086
Expr * getRHS() const
Definition Expr.h:4096
SourceLocation getEndLoc() const LLVM_READONLY
Definition Expr.h:4102
Stmt * getHandlerBlock() const
Definition StmtCXX.h:52
DeclStmt * getLoopVarStmt()
Definition StmtCXX.h:170
DeclStmt * getRangeStmt()
Definition StmtCXX.h:163
SourceLocation getRParenLoc() const
Definition StmtCXX.h:206
const Expr * getSubExpr() const
Definition ExprCXX.h:1231
CXXCatchStmt * getHandler(unsigned i)
Definition StmtCXX.h:109
unsigned getNumHandlers() const
Definition StmtCXX.h:108
CompoundStmt * getTryBlock()
Definition StmtCXX.h:101
Expr * getCallee()
Definition Expr.h:3096
SourceLocation getBegin() const
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.
Definition StmtCXX.h:498
CompoundStmt * getBody() const
Retrieve the body of the coroutine as written.
Definition StmtCXX.h:381
Expr * getOperand() const
Definition ExprCXX.h:5323
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
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...
Definition DeclBase.h:1104
virtual bool hasBody() const
Returns true if this Decl represents a declaration for a body of code, such as a function or method d...
Definition DeclBase.h:1110
Stmt * getBody()
Definition Stmt.h:2866
Expr * getCond()
Definition Stmt.h:2859
bool isValueDependent() const
Determines whether the value of this expression depends on.
Definition Expr.h:177
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext=false) const
EvaluateAsBooleanCondition - Return true if this is a constant which we can fold and convert to a boo...
QualType getType() const
Definition Expr.h:144
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Definition FileEntry.h:57
bool isValid() const
Stmt * getInit()
Definition Stmt.h:2912
SourceLocation getRParenLoc() const
Definition Stmt.h:2957
Stmt * getBody()
Definition Stmt.h:2941
Expr * getInc()
Definition Stmt.h:2940
Expr * getCond()
Definition Stmt.h:2939
Stmt * getThen()
Definition Stmt.h:2357
SourceLocation getIfLoc() const
Definition Stmt.h:2434
Stmt * getInit()
Definition Stmt.h:2418
bool isNonNegatedConsteval() const
Definition Stmt.h:2453
Expr * getCond()
Definition Stmt.h:2345
bool isConstexpr() const
Definition Stmt.h:2461
bool isNegatedConsteval() const
Definition Stmt.h:2457
Stmt * getElse()
Definition Stmt.h:2366
SourceLocation getRParenLoc() const
Definition Stmt.h:2488
bool isConsteval() const
Definition Stmt.h:2448
Stmt * getSubStmt()
Definition Stmt.h:2177
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 ...
Definition Lexer.cpp:509
SourceLocation getRParenLoc() const
Definition StmtObjC.h:54
Expr * getSourceExpr() const
The source expression of an opaque value expression is the expression which originally generated the ...
Definition Expr.h:1234
bool isUnique() const
Definition Expr.h:1242
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.
Definition Expr.h:6853
Expr * getRetValue()
Definition Stmt.h:3196
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.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
SourceLocation getFileLoc(SourceLocation Loc) const
Given Loc, if it is a macro location return the expansion location or the spelling location,...
StringRef getBufferName(SourceLocation Loc, bool *Invalid=nullptr) const
Return the filename or buffer identifier of the buffer the location is in.
bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc=nullptr) const
Tests whether the given source location represents a macro argument's expansion into the function-lik...
unsigned getSpellingColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID.
SourceLocation getLocForEndOfFile(FileID FID) const
Return the source location corresponding to the last byte of the specified file.
FileIDAndOffset getDecomposedSpellingLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
SourceLocation getIncludeLoc(FileID FID) const
Returns the include location if FID is a #include'd file otherwise it returns an invalid location.
unsigned getFileIDSize(FileID FID) const
The size of the SLocEntry that FID represents.
CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
bool isWrittenInScratchSpace(SourceLocation Loc) const
Returns whether Loc is located in a <scratch space> file.
bool isInFileID(SourceLocation Loc, FileID FID, unsigned *RelativeOffset=nullptr) const
Given a specific FileID, returns true if Loc is inside that FileID chunk and sets relative offset (of...
bool isInSystemHeader(SourceLocation Loc) const
Returns if a SourceLocation is in a system header.
unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid=nullptr) const
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file.
bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const
Returns true if the spelling locations for both SourceLocations are part of the same file buffer.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
const SrcMgr::SLocEntry & getSLocEntry(FileID FID, bool *Invalid=nullptr) const
A trivial tuple used to represent a source range.
SourceLocation getExpansionLocStart() const
SourceLocation getExpansionLocEnd() const
const ExpansionInfo & getExpansion() const
CompoundStmt * getSubStmt()
Definition Expr.h:4618
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:367
child_range children()
Definition Stmt.cpp:304
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
Stmt * getSubStmt()
Definition Stmt.h:2122
SourceLocation getColonLoc() const
Definition Stmt.h:1908
const SwitchCase * getNextSwitchCase() const
Definition Stmt.h:1902
Expr * getCond()
Definition Stmt.h:2581
Stmt * getBody()
Definition Stmt.h:2593
Stmt * getInit()
Definition Stmt.h:2598
SwitchCase * getSwitchCaseList()
Definition Stmt.h:2649
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Token - This structure provides full information about a lexed token.
Definition Token.h:36
Expr * getSubExpr() const
Definition Expr.h:2291
Expr * getCond()
Definition Stmt.h:2758
SourceLocation getRParenLoc() const
Definition Stmt.h:2816
Stmt * getBody()
Definition Stmt.h:2770
@ Decl
The l-value was an access to a declared entity or something equivalently strong, like the address of ...
Definition CGValue.h:146
llvm::cl::opt< std::string > Filter
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
FunctionType::ExtInfo getFunctionExtInfo(const Type &t)
Definition TypeBase.h:8624
Expr * Cond
};
unsigned long uint64_t
cl::opt< bool > SystemHeadersCoverage
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
cl::opt< bool > EnableSingleByteCoverage
int const char * function
Definition c++config.h:31
#define false
Definition stdbool.h:26
llvm::DenseMap< const Stmt *, Branch > BranchByStmt
Definition MCDCState.h:60
llvm::DenseMap< const Stmt *, Decision > DecisionByStmt
Definition MCDCState.h:53