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