10b57cec5SDimitry Andric //===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Instrumentation-based code coverage mapping generator
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "CoverageMappingGen.h"
140b57cec5SDimitry Andric #include "CodeGenFunction.h"
150b57cec5SDimitry Andric #include "clang/AST/StmtVisitor.h"
165ffd83dbSDimitry Andric #include "clang/Basic/Diagnostic.h"
175ffd83dbSDimitry Andric #include "clang/Basic/FileManager.h"
185ffd83dbSDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h"
190b57cec5SDimitry Andric #include "clang/Lex/Lexer.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
210b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
220b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMapping.h"
230b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
240b57cec5SDimitry Andric #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
250b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h"
260b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
270b57cec5SDimitry Andric #include "llvm/Support/Path.h"
28bdd1243dSDimitry Andric #include <optional>
290b57cec5SDimitry Andric 
305ffd83dbSDimitry Andric // This selects the coverage mapping format defined when `InstrProfData.inc`
315ffd83dbSDimitry Andric // is textually included.
325ffd83dbSDimitry Andric #define COVMAP_V3
335ffd83dbSDimitry Andric 
34e8d8bef9SDimitry Andric static llvm::cl::opt<bool> EmptyLineCommentCoverage(
35e8d8bef9SDimitry Andric     "emptyline-comment-coverage",
36e8d8bef9SDimitry Andric     llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only "
37e8d8bef9SDimitry Andric                    "disable it on test)"),
38e8d8bef9SDimitry Andric     llvm::cl::init(true), llvm::cl::Hidden);
39e8d8bef9SDimitry Andric 
40a58f00eaSDimitry Andric llvm::cl::opt<bool> SystemHeadersCoverage(
41fe013be4SDimitry Andric     "system-headers-coverage",
42fe013be4SDimitry Andric     llvm::cl::desc("Enable collecting coverage from system headers"),
43fe013be4SDimitry Andric     llvm::cl::init(false), llvm::cl::Hidden);
44fe013be4SDimitry Andric 
450b57cec5SDimitry Andric using namespace clang;
460b57cec5SDimitry Andric using namespace CodeGen;
470b57cec5SDimitry Andric using namespace llvm::coverage;
480b57cec5SDimitry Andric 
49e8d8bef9SDimitry Andric CoverageSourceInfo *
setUpCoverageCallbacks(Preprocessor & PP)50e8d8bef9SDimitry Andric CoverageMappingModuleGen::setUpCoverageCallbacks(Preprocessor &PP) {
51e8d8bef9SDimitry Andric   CoverageSourceInfo *CoverageInfo =
52e8d8bef9SDimitry Andric       new CoverageSourceInfo(PP.getSourceManager());
53e8d8bef9SDimitry Andric   PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(CoverageInfo));
54e8d8bef9SDimitry Andric   if (EmptyLineCommentCoverage) {
55e8d8bef9SDimitry Andric     PP.addCommentHandler(CoverageInfo);
56e8d8bef9SDimitry Andric     PP.setEmptylineHandler(CoverageInfo);
57e8d8bef9SDimitry Andric     PP.setPreprocessToken(true);
58e8d8bef9SDimitry Andric     PP.setTokenWatcher([CoverageInfo](clang::Token Tok) {
59e8d8bef9SDimitry Andric       // Update previous token location.
60e8d8bef9SDimitry Andric       CoverageInfo->PrevTokLoc = Tok.getLocation();
61e8d8bef9SDimitry Andric       if (Tok.getKind() != clang::tok::eod)
62e8d8bef9SDimitry Andric         CoverageInfo->updateNextTokLoc(Tok.getLocation());
63e8d8bef9SDimitry Andric     });
64e8d8bef9SDimitry Andric   }
65e8d8bef9SDimitry Andric   return CoverageInfo;
66e8d8bef9SDimitry Andric }
67e8d8bef9SDimitry Andric 
AddSkippedRange(SourceRange Range,SkippedRange::Kind RangeKind)6881ad6265SDimitry Andric void CoverageSourceInfo::AddSkippedRange(SourceRange Range,
6981ad6265SDimitry Andric                                          SkippedRange::Kind RangeKind) {
70e8d8bef9SDimitry Andric   if (EmptyLineCommentCoverage && !SkippedRanges.empty() &&
71e8d8bef9SDimitry Andric       PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
72e8d8bef9SDimitry Andric       SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
73e8d8bef9SDimitry Andric                                     Range.getBegin()))
74e8d8bef9SDimitry Andric     SkippedRanges.back().Range.setEnd(Range.getEnd());
75e8d8bef9SDimitry Andric   else
7681ad6265SDimitry Andric     SkippedRanges.push_back({Range, RangeKind, PrevTokLoc});
77e8d8bef9SDimitry Andric }
78e8d8bef9SDimitry Andric 
SourceRangeSkipped(SourceRange Range,SourceLocation)790b57cec5SDimitry Andric void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) {
8081ad6265SDimitry Andric   AddSkippedRange(Range, SkippedRange::PPIfElse);
81e8d8bef9SDimitry Andric }
82e8d8bef9SDimitry Andric 
HandleEmptyline(SourceRange Range)83e8d8bef9SDimitry Andric void CoverageSourceInfo::HandleEmptyline(SourceRange Range) {
8481ad6265SDimitry Andric   AddSkippedRange(Range, SkippedRange::EmptyLine);
85e8d8bef9SDimitry Andric }
86e8d8bef9SDimitry Andric 
HandleComment(Preprocessor & PP,SourceRange Range)87e8d8bef9SDimitry Andric bool CoverageSourceInfo::HandleComment(Preprocessor &PP, SourceRange Range) {
8881ad6265SDimitry Andric   AddSkippedRange(Range, SkippedRange::Comment);
89e8d8bef9SDimitry Andric   return false;
90e8d8bef9SDimitry Andric }
91e8d8bef9SDimitry Andric 
updateNextTokLoc(SourceLocation Loc)92e8d8bef9SDimitry Andric void CoverageSourceInfo::updateNextTokLoc(SourceLocation Loc) {
93e8d8bef9SDimitry Andric   if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
94e8d8bef9SDimitry Andric     SkippedRanges.back().NextTokLoc = Loc;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric namespace {
98cdc20ff6SDimitry Andric using MCDCConditionID = CounterMappingRegion::MCDCConditionID;
99cdc20ff6SDimitry Andric using MCDCParameters = CounterMappingRegion::MCDCParameters;
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric /// A region of source code that can be mapped to a counter.
1020b57cec5SDimitry Andric class SourceMappingRegion {
103e8d8bef9SDimitry Andric   /// Primary Counter that is also used for Branch Regions for "True" branches.
1040b57cec5SDimitry Andric   Counter Count;
1050b57cec5SDimitry Andric 
106e8d8bef9SDimitry Andric   /// Secondary Counter used for Branch Regions for "False" branches.
107bdd1243dSDimitry Andric   std::optional<Counter> FalseCount;
108e8d8bef9SDimitry Andric 
109cdc20ff6SDimitry Andric   /// Parameters used for Modified Condition/Decision Coverage
110cdc20ff6SDimitry Andric   MCDCParameters MCDCParams;
111cdc20ff6SDimitry Andric 
1120b57cec5SDimitry Andric   /// The region's starting location.
113bdd1243dSDimitry Andric   std::optional<SourceLocation> LocStart;
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   /// The region's ending location.
116bdd1243dSDimitry Andric   std::optional<SourceLocation> LocEnd;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   /// Whether this region is a gap region. The count from a gap region is set
1190b57cec5SDimitry Andric   /// as the line execution count if there are no other regions on the line.
1200b57cec5SDimitry Andric   bool GapRegion;
1210b57cec5SDimitry Andric 
122a58f00eaSDimitry Andric   /// Whetever this region is skipped ('if constexpr' or 'if consteval' untaken
123a58f00eaSDimitry Andric   /// branch, or anything skipped but not empty line / comments)
124a58f00eaSDimitry Andric   bool SkippedRegion;
125a58f00eaSDimitry Andric 
1260b57cec5SDimitry Andric public:
SourceMappingRegion(Counter Count,std::optional<SourceLocation> LocStart,std::optional<SourceLocation> LocEnd,bool GapRegion=false)127bdd1243dSDimitry Andric   SourceMappingRegion(Counter Count, std::optional<SourceLocation> LocStart,
128bdd1243dSDimitry Andric                       std::optional<SourceLocation> LocEnd,
129bdd1243dSDimitry Andric                       bool GapRegion = false)
130a58f00eaSDimitry Andric       : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
131a58f00eaSDimitry Andric         SkippedRegion(false) {}
1320b57cec5SDimitry Andric 
SourceMappingRegion(Counter Count,std::optional<Counter> FalseCount,MCDCParameters MCDCParams,std::optional<SourceLocation> LocStart,std::optional<SourceLocation> LocEnd,bool GapRegion=false)133bdd1243dSDimitry Andric   SourceMappingRegion(Counter Count, std::optional<Counter> FalseCount,
134cdc20ff6SDimitry Andric                       MCDCParameters MCDCParams,
135bdd1243dSDimitry Andric                       std::optional<SourceLocation> LocStart,
136bdd1243dSDimitry Andric                       std::optional<SourceLocation> LocEnd,
137bdd1243dSDimitry Andric                       bool GapRegion = false)
138cdc20ff6SDimitry Andric       : Count(Count), FalseCount(FalseCount), MCDCParams(MCDCParams),
139a58f00eaSDimitry Andric         LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion),
140a58f00eaSDimitry Andric         SkippedRegion(false) {}
141cdc20ff6SDimitry Andric 
SourceMappingRegion(MCDCParameters MCDCParams,std::optional<SourceLocation> LocStart,std::optional<SourceLocation> LocEnd)142cdc20ff6SDimitry Andric   SourceMappingRegion(MCDCParameters MCDCParams,
143cdc20ff6SDimitry Andric                       std::optional<SourceLocation> LocStart,
144cdc20ff6SDimitry Andric                       std::optional<SourceLocation> LocEnd)
145cdc20ff6SDimitry Andric       : MCDCParams(MCDCParams), LocStart(LocStart), LocEnd(LocEnd),
146a58f00eaSDimitry Andric         GapRegion(false), SkippedRegion(false) {}
147e8d8bef9SDimitry Andric 
getCounter() const1480b57cec5SDimitry Andric   const Counter &getCounter() const { return Count; }
1490b57cec5SDimitry Andric 
getFalseCounter() const150e8d8bef9SDimitry Andric   const Counter &getFalseCounter() const {
151e8d8bef9SDimitry Andric     assert(FalseCount && "Region has no alternate counter");
152e8d8bef9SDimitry Andric     return *FalseCount;
153e8d8bef9SDimitry Andric   }
154e8d8bef9SDimitry Andric 
setCounter(Counter C)1550b57cec5SDimitry Andric   void setCounter(Counter C) { Count = C; }
1560b57cec5SDimitry Andric 
hasStartLoc() const15781ad6265SDimitry Andric   bool hasStartLoc() const { return LocStart.has_value(); }
1580b57cec5SDimitry Andric 
setStartLoc(SourceLocation Loc)1590b57cec5SDimitry Andric   void setStartLoc(SourceLocation Loc) { LocStart = Loc; }
1600b57cec5SDimitry Andric 
getBeginLoc() const1610b57cec5SDimitry Andric   SourceLocation getBeginLoc() const {
1620b57cec5SDimitry Andric     assert(LocStart && "Region has no start location");
1630b57cec5SDimitry Andric     return *LocStart;
1640b57cec5SDimitry Andric   }
1650b57cec5SDimitry Andric 
hasEndLoc() const16681ad6265SDimitry Andric   bool hasEndLoc() const { return LocEnd.has_value(); }
1670b57cec5SDimitry Andric 
setEndLoc(SourceLocation Loc)1680b57cec5SDimitry Andric   void setEndLoc(SourceLocation Loc) {
1690b57cec5SDimitry Andric     assert(Loc.isValid() && "Setting an invalid end location");
1700b57cec5SDimitry Andric     LocEnd = Loc;
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
getEndLoc() const1730b57cec5SDimitry Andric   SourceLocation getEndLoc() const {
1740b57cec5SDimitry Andric     assert(LocEnd && "Region has no end location");
1750b57cec5SDimitry Andric     return *LocEnd;
1760b57cec5SDimitry Andric   }
1770b57cec5SDimitry Andric 
isGap() const1780b57cec5SDimitry Andric   bool isGap() const { return GapRegion; }
1790b57cec5SDimitry Andric 
setGap(bool Gap)1800b57cec5SDimitry Andric   void setGap(bool Gap) { GapRegion = Gap; }
181e8d8bef9SDimitry Andric 
isSkipped() const182a58f00eaSDimitry Andric   bool isSkipped() const { return SkippedRegion; }
183a58f00eaSDimitry Andric 
setSkipped(bool Skipped)184a58f00eaSDimitry Andric   void setSkipped(bool Skipped) { SkippedRegion = Skipped; }
185a58f00eaSDimitry Andric 
isBranch() const18681ad6265SDimitry Andric   bool isBranch() const { return FalseCount.has_value(); }
187cdc20ff6SDimitry Andric 
isMCDCDecision() const188cdc20ff6SDimitry Andric   bool isMCDCDecision() const { return MCDCParams.NumConditions != 0; }
189cdc20ff6SDimitry Andric 
getMCDCParams() const190cdc20ff6SDimitry Andric   const MCDCParameters &getMCDCParams() const { return MCDCParams; }
1910b57cec5SDimitry Andric };
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric /// Spelling locations for the start and end of a source region.
1940b57cec5SDimitry Andric struct SpellingRegion {
1950b57cec5SDimitry Andric   /// The line where the region starts.
1960b57cec5SDimitry Andric   unsigned LineStart;
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric   /// The column where the region starts.
1990b57cec5SDimitry Andric   unsigned ColumnStart;
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   /// The line where the region ends.
2020b57cec5SDimitry Andric   unsigned LineEnd;
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   /// The column where the region ends.
2050b57cec5SDimitry Andric   unsigned ColumnEnd;
2060b57cec5SDimitry Andric 
SpellingRegion__anonc2c3cfe60211::SpellingRegion2070b57cec5SDimitry Andric   SpellingRegion(SourceManager &SM, SourceLocation LocStart,
2080b57cec5SDimitry Andric                  SourceLocation LocEnd) {
2090b57cec5SDimitry Andric     LineStart = SM.getSpellingLineNumber(LocStart);
2100b57cec5SDimitry Andric     ColumnStart = SM.getSpellingColumnNumber(LocStart);
2110b57cec5SDimitry Andric     LineEnd = SM.getSpellingLineNumber(LocEnd);
2120b57cec5SDimitry Andric     ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
2130b57cec5SDimitry Andric   }
2140b57cec5SDimitry Andric 
SpellingRegion__anonc2c3cfe60211::SpellingRegion2150b57cec5SDimitry Andric   SpellingRegion(SourceManager &SM, SourceMappingRegion &R)
2160b57cec5SDimitry Andric       : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {}
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   /// Check if the start and end locations appear in source order, i.e
2190b57cec5SDimitry Andric   /// top->bottom, left->right.
isInSourceOrder__anonc2c3cfe60211::SpellingRegion2200b57cec5SDimitry Andric   bool isInSourceOrder() const {
2210b57cec5SDimitry Andric     return (LineStart < LineEnd) ||
2220b57cec5SDimitry Andric            (LineStart == LineEnd && ColumnStart <= ColumnEnd);
2230b57cec5SDimitry Andric   }
2240b57cec5SDimitry Andric };
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric /// Provides the common functionality for the different
2270b57cec5SDimitry Andric /// coverage mapping region builders.
2280b57cec5SDimitry Andric class CoverageMappingBuilder {
2290b57cec5SDimitry Andric public:
2300b57cec5SDimitry Andric   CoverageMappingModuleGen &CVM;
2310b57cec5SDimitry Andric   SourceManager &SM;
2320b57cec5SDimitry Andric   const LangOptions &LangOpts;
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric private:
2350b57cec5SDimitry Andric   /// Map of clang's FileIDs to IDs used for coverage mapping.
2360b57cec5SDimitry Andric   llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
2370b57cec5SDimitry Andric       FileIDMapping;
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric public:
2400b57cec5SDimitry Andric   /// The coverage mapping regions for this function
2410b57cec5SDimitry Andric   llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
2420b57cec5SDimitry Andric   /// The source mapping regions for this function.
2430b57cec5SDimitry Andric   std::vector<SourceMappingRegion> SourceRegions;
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric   /// A set of regions which can be used as a filter.
2460b57cec5SDimitry Andric   ///
2470b57cec5SDimitry Andric   /// It is produced by emitExpansionRegions() and is used in
2480b57cec5SDimitry Andric   /// emitSourceRegions() to suppress producing code regions if
2490b57cec5SDimitry Andric   /// the same area is covered by expansion regions.
2500b57cec5SDimitry Andric   typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
2510b57cec5SDimitry Andric       SourceRegionFilter;
2520b57cec5SDimitry Andric 
CoverageMappingBuilder(CoverageMappingModuleGen & CVM,SourceManager & SM,const LangOptions & LangOpts)2530b57cec5SDimitry Andric   CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
2540b57cec5SDimitry Andric                          const LangOptions &LangOpts)
2550b57cec5SDimitry Andric       : CVM(CVM), SM(SM), LangOpts(LangOpts) {}
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   /// Return the precise end location for the given token.
getPreciseTokenLocEnd(SourceLocation Loc)2580b57cec5SDimitry Andric   SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
2590b57cec5SDimitry Andric     // We avoid getLocForEndOfToken here, because it doesn't do what we want for
2600b57cec5SDimitry Andric     // macro locations, which we just treat as expanded files.
2610b57cec5SDimitry Andric     unsigned TokLen =
2620b57cec5SDimitry Andric         Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts);
2630b57cec5SDimitry Andric     return Loc.getLocWithOffset(TokLen);
2640b57cec5SDimitry Andric   }
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric   /// Return the start location of an included file or expanded macro.
getStartOfFileOrMacro(SourceLocation Loc)2670b57cec5SDimitry Andric   SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
2680b57cec5SDimitry Andric     if (Loc.isMacroID())
2690b57cec5SDimitry Andric       return Loc.getLocWithOffset(-SM.getFileOffset(Loc));
2700b57cec5SDimitry Andric     return SM.getLocForStartOfFile(SM.getFileID(Loc));
2710b57cec5SDimitry Andric   }
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric   /// Return the end location of an included file or expanded macro.
getEndOfFileOrMacro(SourceLocation Loc)2740b57cec5SDimitry Andric   SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
2750b57cec5SDimitry Andric     if (Loc.isMacroID())
2760b57cec5SDimitry Andric       return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) -
2770b57cec5SDimitry Andric                                   SM.getFileOffset(Loc));
2780b57cec5SDimitry Andric     return SM.getLocForEndOfFile(SM.getFileID(Loc));
2790b57cec5SDimitry Andric   }
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric   /// Find out where the current file is included or macro is expanded.
getIncludeOrExpansionLoc(SourceLocation Loc)2820b57cec5SDimitry Andric   SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) {
2830b57cec5SDimitry Andric     return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin()
2840b57cec5SDimitry Andric                            : SM.getIncludeLoc(SM.getFileID(Loc));
2850b57cec5SDimitry Andric   }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric   /// Return true if \c Loc is a location in a built-in macro.
isInBuiltin(SourceLocation Loc)2880b57cec5SDimitry Andric   bool isInBuiltin(SourceLocation Loc) {
2890b57cec5SDimitry Andric     return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>";
2900b57cec5SDimitry Andric   }
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric   /// Check whether \c Loc is included or expanded from \c Parent.
isNestedIn(SourceLocation Loc,FileID Parent)2930b57cec5SDimitry Andric   bool isNestedIn(SourceLocation Loc, FileID Parent) {
2940b57cec5SDimitry Andric     do {
2950b57cec5SDimitry Andric       Loc = getIncludeOrExpansionLoc(Loc);
2960b57cec5SDimitry Andric       if (Loc.isInvalid())
2970b57cec5SDimitry Andric         return false;
2980b57cec5SDimitry Andric     } while (!SM.isInFileID(Loc, Parent));
2990b57cec5SDimitry Andric     return true;
3000b57cec5SDimitry Andric   }
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric   /// Get the start of \c S ignoring macro arguments and builtin macros.
getStart(const Stmt * S)3030b57cec5SDimitry Andric   SourceLocation getStart(const Stmt *S) {
3040b57cec5SDimitry Andric     SourceLocation Loc = S->getBeginLoc();
3050b57cec5SDimitry Andric     while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
3060b57cec5SDimitry Andric       Loc = SM.getImmediateExpansionRange(Loc).getBegin();
3070b57cec5SDimitry Andric     return Loc;
3080b57cec5SDimitry Andric   }
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric   /// Get the end of \c S ignoring macro arguments and builtin macros.
getEnd(const Stmt * S)3110b57cec5SDimitry Andric   SourceLocation getEnd(const Stmt *S) {
3120b57cec5SDimitry Andric     SourceLocation Loc = S->getEndLoc();
3130b57cec5SDimitry Andric     while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
3140b57cec5SDimitry Andric       Loc = SM.getImmediateExpansionRange(Loc).getBegin();
3150b57cec5SDimitry Andric     return getPreciseTokenLocEnd(Loc);
3160b57cec5SDimitry Andric   }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric   /// Find the set of files we have regions for and assign IDs
3190b57cec5SDimitry Andric   ///
3200b57cec5SDimitry Andric   /// Fills \c Mapping with the virtual file mapping needed to write out
3210b57cec5SDimitry Andric   /// coverage and collects the necessary file information to emit source and
3220b57cec5SDimitry Andric   /// expansion regions.
gatherFileIDs(SmallVectorImpl<unsigned> & Mapping)3230b57cec5SDimitry Andric   void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
3240b57cec5SDimitry Andric     FileIDMapping.clear();
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric     llvm::SmallSet<FileID, 8> Visited;
3270b57cec5SDimitry Andric     SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
3280b57cec5SDimitry Andric     for (const auto &Region : SourceRegions) {
3290b57cec5SDimitry Andric       SourceLocation Loc = Region.getBeginLoc();
3300b57cec5SDimitry Andric       FileID File = SM.getFileID(Loc);
3310b57cec5SDimitry Andric       if (!Visited.insert(File).second)
3320b57cec5SDimitry Andric         continue;
3330b57cec5SDimitry Andric 
334fe013be4SDimitry Andric       // Do not map FileID's associated with system headers unless collecting
335fe013be4SDimitry Andric       // coverage from system headers is explicitly enabled.
336fe013be4SDimitry Andric       if (!SystemHeadersCoverage && SM.isInSystemHeader(SM.getSpellingLoc(Loc)))
3370b57cec5SDimitry Andric         continue;
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric       unsigned Depth = 0;
3400b57cec5SDimitry Andric       for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
3410b57cec5SDimitry Andric            Parent.isValid(); Parent = getIncludeOrExpansionLoc(Parent))
3420b57cec5SDimitry Andric         ++Depth;
3430b57cec5SDimitry Andric       FileLocs.push_back(std::make_pair(Loc, Depth));
3440b57cec5SDimitry Andric     }
3450b57cec5SDimitry Andric     llvm::stable_sort(FileLocs, llvm::less_second());
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric     for (const auto &FL : FileLocs) {
3480b57cec5SDimitry Andric       SourceLocation Loc = FL.first;
3490b57cec5SDimitry Andric       FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first;
350c9157d92SDimitry Andric       auto Entry = SM.getFileEntryRefForID(SpellingFile);
3510b57cec5SDimitry Andric       if (!Entry)
3520b57cec5SDimitry Andric         continue;
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric       FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
355c9157d92SDimitry Andric       Mapping.push_back(CVM.getFileID(*Entry));
3560b57cec5SDimitry Andric     }
3570b57cec5SDimitry Andric   }
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric   /// Get the coverage mapping file ID for \c Loc.
3600b57cec5SDimitry Andric   ///
361bdd1243dSDimitry Andric   /// If such file id doesn't exist, return std::nullopt.
getCoverageFileID(SourceLocation Loc)362bdd1243dSDimitry Andric   std::optional<unsigned> getCoverageFileID(SourceLocation Loc) {
3630b57cec5SDimitry Andric     auto Mapping = FileIDMapping.find(SM.getFileID(Loc));
3640b57cec5SDimitry Andric     if (Mapping != FileIDMapping.end())
3650b57cec5SDimitry Andric       return Mapping->second.first;
366bdd1243dSDimitry Andric     return std::nullopt;
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric 
369e8d8bef9SDimitry Andric   /// This shrinks the skipped range if it spans a line that contains a
370e8d8bef9SDimitry Andric   /// non-comment token. If shrinking the skipped range would make it empty,
371bdd1243dSDimitry Andric   /// this returns std::nullopt.
37281ad6265SDimitry Andric   /// Note this function can potentially be expensive because
37381ad6265SDimitry Andric   /// getSpellingLineNumber uses getLineNumber, which is expensive.
adjustSkippedRange(SourceManager & SM,SourceLocation LocStart,SourceLocation LocEnd,SourceLocation PrevTokLoc,SourceLocation NextTokLoc)374bdd1243dSDimitry Andric   std::optional<SpellingRegion> adjustSkippedRange(SourceManager &SM,
375e8d8bef9SDimitry Andric                                                    SourceLocation LocStart,
376e8d8bef9SDimitry Andric                                                    SourceLocation LocEnd,
377e8d8bef9SDimitry Andric                                                    SourceLocation PrevTokLoc,
378e8d8bef9SDimitry Andric                                                    SourceLocation NextTokLoc) {
379e8d8bef9SDimitry Andric     SpellingRegion SR{SM, LocStart, LocEnd};
380e8d8bef9SDimitry Andric     SR.ColumnStart = 1;
381e8d8bef9SDimitry Andric     if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
382e8d8bef9SDimitry Andric         SR.LineStart == SM.getSpellingLineNumber(PrevTokLoc))
383e8d8bef9SDimitry Andric       SR.LineStart++;
384e8d8bef9SDimitry Andric     if (NextTokLoc.isValid() && SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
385e8d8bef9SDimitry Andric         SR.LineEnd == SM.getSpellingLineNumber(NextTokLoc)) {
386e8d8bef9SDimitry Andric       SR.LineEnd--;
387e8d8bef9SDimitry Andric       SR.ColumnEnd++;
388e8d8bef9SDimitry Andric     }
389e8d8bef9SDimitry Andric     if (SR.isInSourceOrder())
390e8d8bef9SDimitry Andric       return SR;
391bdd1243dSDimitry Andric     return std::nullopt;
392e8d8bef9SDimitry Andric   }
393e8d8bef9SDimitry Andric 
3940b57cec5SDimitry Andric   /// Gather all the regions that were skipped by the preprocessor
395e8d8bef9SDimitry Andric   /// using the constructs like #if or comments.
gatherSkippedRegions()3960b57cec5SDimitry Andric   void gatherSkippedRegions() {
3970b57cec5SDimitry Andric     /// An array of the minimum lineStarts and the maximum lineEnds
3980b57cec5SDimitry Andric     /// for mapping regions from the appropriate source files.
3990b57cec5SDimitry Andric     llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
4000b57cec5SDimitry Andric     FileLineRanges.resize(
4010b57cec5SDimitry Andric         FileIDMapping.size(),
4020b57cec5SDimitry Andric         std::make_pair(std::numeric_limits<unsigned>::max(), 0));
4030b57cec5SDimitry Andric     for (const auto &R : MappingRegions) {
4040b57cec5SDimitry Andric       FileLineRanges[R.FileID].first =
4050b57cec5SDimitry Andric           std::min(FileLineRanges[R.FileID].first, R.LineStart);
4060b57cec5SDimitry Andric       FileLineRanges[R.FileID].second =
4070b57cec5SDimitry Andric           std::max(FileLineRanges[R.FileID].second, R.LineEnd);
4080b57cec5SDimitry Andric     }
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric     auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges();
411e8d8bef9SDimitry Andric     for (auto &I : SkippedRanges) {
412e8d8bef9SDimitry Andric       SourceRange Range = I.Range;
413e8d8bef9SDimitry Andric       auto LocStart = Range.getBegin();
414e8d8bef9SDimitry Andric       auto LocEnd = Range.getEnd();
4150b57cec5SDimitry Andric       assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
4160b57cec5SDimitry Andric              "region spans multiple files");
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric       auto CovFileID = getCoverageFileID(LocStart);
4190b57cec5SDimitry Andric       if (!CovFileID)
4200b57cec5SDimitry Andric         continue;
421bdd1243dSDimitry Andric       std::optional<SpellingRegion> SR;
42281ad6265SDimitry Andric       if (I.isComment())
42381ad6265SDimitry Andric         SR = adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc,
42481ad6265SDimitry Andric                                 I.NextTokLoc);
42581ad6265SDimitry Andric       else if (I.isPPIfElse() || I.isEmptyLine())
42681ad6265SDimitry Andric         SR = {SM, LocStart, LocEnd};
42781ad6265SDimitry Andric 
42881ad6265SDimitry Andric       if (!SR)
429e8d8bef9SDimitry Andric         continue;
4300b57cec5SDimitry Andric       auto Region = CounterMappingRegion::makeSkipped(
431e8d8bef9SDimitry Andric           *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
432e8d8bef9SDimitry Andric           SR->ColumnEnd);
4330b57cec5SDimitry Andric       // Make sure that we only collect the regions that are inside
4340b57cec5SDimitry Andric       // the source code of this function.
4350b57cec5SDimitry Andric       if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
4360b57cec5SDimitry Andric           Region.LineEnd <= FileLineRanges[*CovFileID].second)
4370b57cec5SDimitry Andric         MappingRegions.push_back(Region);
4380b57cec5SDimitry Andric     }
4390b57cec5SDimitry Andric   }
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric   /// Generate the coverage counter mapping regions from collected
4420b57cec5SDimitry Andric   /// source regions.
emitSourceRegions(const SourceRegionFilter & Filter)4430b57cec5SDimitry Andric   void emitSourceRegions(const SourceRegionFilter &Filter) {
4440b57cec5SDimitry Andric     for (const auto &Region : SourceRegions) {
4450b57cec5SDimitry Andric       assert(Region.hasEndLoc() && "incomplete region");
4460b57cec5SDimitry Andric 
4470b57cec5SDimitry Andric       SourceLocation LocStart = Region.getBeginLoc();
4480b57cec5SDimitry Andric       assert(SM.getFileID(LocStart).isValid() && "region in invalid file");
4490b57cec5SDimitry Andric 
450fe013be4SDimitry Andric       // Ignore regions from system headers unless collecting coverage from
451fe013be4SDimitry Andric       // system headers is explicitly enabled.
452fe013be4SDimitry Andric       if (!SystemHeadersCoverage &&
453fe013be4SDimitry Andric           SM.isInSystemHeader(SM.getSpellingLoc(LocStart)))
4540b57cec5SDimitry Andric         continue;
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric       auto CovFileID = getCoverageFileID(LocStart);
4570b57cec5SDimitry Andric       // Ignore regions that don't have a file, such as builtin macros.
4580b57cec5SDimitry Andric       if (!CovFileID)
4590b57cec5SDimitry Andric         continue;
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric       SourceLocation LocEnd = Region.getEndLoc();
4620b57cec5SDimitry Andric       assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
4630b57cec5SDimitry Andric              "region spans multiple files");
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric       // Don't add code regions for the area covered by expansion regions.
4660b57cec5SDimitry Andric       // This not only suppresses redundant regions, but sometimes prevents
4670b57cec5SDimitry Andric       // creating regions with wrong counters if, for example, a statement's
4680b57cec5SDimitry Andric       // body ends at the end of a nested macro.
4690b57cec5SDimitry Andric       if (Filter.count(std::make_pair(LocStart, LocEnd)))
4700b57cec5SDimitry Andric         continue;
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric       // Find the spelling locations for the mapping region.
4730b57cec5SDimitry Andric       SpellingRegion SR{SM, LocStart, LocEnd};
4740b57cec5SDimitry Andric       assert(SR.isInSourceOrder() && "region start and end out of order");
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric       if (Region.isGap()) {
4770b57cec5SDimitry Andric         MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
4780b57cec5SDimitry Andric             Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
4790b57cec5SDimitry Andric             SR.LineEnd, SR.ColumnEnd));
480a58f00eaSDimitry Andric       } else if (Region.isSkipped()) {
481a58f00eaSDimitry Andric         MappingRegions.push_back(CounterMappingRegion::makeSkipped(
482a58f00eaSDimitry Andric             *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd,
483a58f00eaSDimitry Andric             SR.ColumnEnd));
484e8d8bef9SDimitry Andric       } else if (Region.isBranch()) {
485e8d8bef9SDimitry Andric         MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
486cdc20ff6SDimitry Andric             Region.getCounter(), Region.getFalseCounter(),
487cdc20ff6SDimitry Andric             Region.getMCDCParams(), *CovFileID, SR.LineStart, SR.ColumnStart,
488cdc20ff6SDimitry Andric             SR.LineEnd, SR.ColumnEnd));
489cdc20ff6SDimitry Andric       } else if (Region.isMCDCDecision()) {
490cdc20ff6SDimitry Andric         MappingRegions.push_back(CounterMappingRegion::makeDecisionRegion(
491cdc20ff6SDimitry Andric             Region.getMCDCParams(), *CovFileID, SR.LineStart, SR.ColumnStart,
492cdc20ff6SDimitry Andric             SR.LineEnd, SR.ColumnEnd));
4930b57cec5SDimitry Andric       } else {
4940b57cec5SDimitry Andric         MappingRegions.push_back(CounterMappingRegion::makeRegion(
4950b57cec5SDimitry Andric             Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
4960b57cec5SDimitry Andric             SR.LineEnd, SR.ColumnEnd));
4970b57cec5SDimitry Andric       }
4980b57cec5SDimitry Andric     }
4990b57cec5SDimitry Andric   }
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric   /// Generate expansion regions for each virtual file we've seen.
emitExpansionRegions()5020b57cec5SDimitry Andric   SourceRegionFilter emitExpansionRegions() {
5030b57cec5SDimitry Andric     SourceRegionFilter Filter;
5040b57cec5SDimitry Andric     for (const auto &FM : FileIDMapping) {
5050b57cec5SDimitry Andric       SourceLocation ExpandedLoc = FM.second.second;
5060b57cec5SDimitry Andric       SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc);
5070b57cec5SDimitry Andric       if (ParentLoc.isInvalid())
5080b57cec5SDimitry Andric         continue;
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric       auto ParentFileID = getCoverageFileID(ParentLoc);
5110b57cec5SDimitry Andric       if (!ParentFileID)
5120b57cec5SDimitry Andric         continue;
5130b57cec5SDimitry Andric       auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
5140b57cec5SDimitry Andric       assert(ExpandedFileID && "expansion in uncovered file");
5150b57cec5SDimitry Andric 
5160b57cec5SDimitry Andric       SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
5170b57cec5SDimitry Andric       assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
5180b57cec5SDimitry Andric              "region spans multiple files");
5190b57cec5SDimitry Andric       Filter.insert(std::make_pair(ParentLoc, LocEnd));
5200b57cec5SDimitry Andric 
5210b57cec5SDimitry Andric       SpellingRegion SR{SM, ParentLoc, LocEnd};
5220b57cec5SDimitry Andric       assert(SR.isInSourceOrder() && "region start and end out of order");
5230b57cec5SDimitry Andric       MappingRegions.push_back(CounterMappingRegion::makeExpansion(
5240b57cec5SDimitry Andric           *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
5250b57cec5SDimitry Andric           SR.LineEnd, SR.ColumnEnd));
5260b57cec5SDimitry Andric     }
5270b57cec5SDimitry Andric     return Filter;
5280b57cec5SDimitry Andric   }
5290b57cec5SDimitry Andric };
5300b57cec5SDimitry Andric 
5310b57cec5SDimitry Andric /// Creates unreachable coverage regions for the functions that
5320b57cec5SDimitry Andric /// are not emitted.
5330b57cec5SDimitry Andric struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
EmptyCoverageMappingBuilder__anonc2c3cfe60211::EmptyCoverageMappingBuilder5340b57cec5SDimitry Andric   EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
5350b57cec5SDimitry Andric                               const LangOptions &LangOpts)
5360b57cec5SDimitry Andric       : CoverageMappingBuilder(CVM, SM, LangOpts) {}
5370b57cec5SDimitry Andric 
VisitDecl__anonc2c3cfe60211::EmptyCoverageMappingBuilder5380b57cec5SDimitry Andric   void VisitDecl(const Decl *D) {
5390b57cec5SDimitry Andric     if (!D->hasBody())
5400b57cec5SDimitry Andric       return;
5410b57cec5SDimitry Andric     auto Body = D->getBody();
5420b57cec5SDimitry Andric     SourceLocation Start = getStart(Body);
5430b57cec5SDimitry Andric     SourceLocation End = getEnd(Body);
5440b57cec5SDimitry Andric     if (!SM.isWrittenInSameFile(Start, End)) {
5450b57cec5SDimitry Andric       // Walk up to find the common ancestor.
5460b57cec5SDimitry Andric       // Correct the locations accordingly.
5470b57cec5SDimitry Andric       FileID StartFileID = SM.getFileID(Start);
5480b57cec5SDimitry Andric       FileID EndFileID = SM.getFileID(End);
5490b57cec5SDimitry Andric       while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
5500b57cec5SDimitry Andric         Start = getIncludeOrExpansionLoc(Start);
5510b57cec5SDimitry Andric         assert(Start.isValid() &&
5520b57cec5SDimitry Andric                "Declaration start location not nested within a known region");
5530b57cec5SDimitry Andric         StartFileID = SM.getFileID(Start);
5540b57cec5SDimitry Andric       }
5550b57cec5SDimitry Andric       while (StartFileID != EndFileID) {
5560b57cec5SDimitry Andric         End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
5570b57cec5SDimitry Andric         assert(End.isValid() &&
5580b57cec5SDimitry Andric                "Declaration end location not nested within a known region");
5590b57cec5SDimitry Andric         EndFileID = SM.getFileID(End);
5600b57cec5SDimitry Andric       }
5610b57cec5SDimitry Andric     }
5620b57cec5SDimitry Andric     SourceRegions.emplace_back(Counter(), Start, End);
5630b57cec5SDimitry Andric   }
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric   /// Write the mapping data to the output stream
write__anonc2c3cfe60211::EmptyCoverageMappingBuilder5660b57cec5SDimitry Andric   void write(llvm::raw_ostream &OS) {
5670b57cec5SDimitry Andric     SmallVector<unsigned, 16> FileIDMapping;
5680b57cec5SDimitry Andric     gatherFileIDs(FileIDMapping);
5690b57cec5SDimitry Andric     emitSourceRegions(SourceRegionFilter());
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric     if (MappingRegions.empty())
5720b57cec5SDimitry Andric       return;
5730b57cec5SDimitry Andric 
574bdd1243dSDimitry Andric     CoverageMappingWriter Writer(FileIDMapping, std::nullopt, MappingRegions);
5750b57cec5SDimitry Andric     Writer.write(OS);
5760b57cec5SDimitry Andric   }
5770b57cec5SDimitry Andric };
5780b57cec5SDimitry Andric 
579cdc20ff6SDimitry Andric /// A wrapper object for maintaining stacks to track the resursive AST visitor
580cdc20ff6SDimitry Andric /// walks for the purpose of assigning IDs to leaf-level conditions measured by
581cdc20ff6SDimitry Andric /// MC/DC. The object is created with a reference to the MCDCBitmapMap that was
582cdc20ff6SDimitry Andric /// created during the initial AST walk. The presence of a bitmap associated
583cdc20ff6SDimitry Andric /// with a boolean expression (top-level logical operator nest) indicates that
584cdc20ff6SDimitry Andric /// the boolean expression qualified for MC/DC.  The resulting condition IDs
585cdc20ff6SDimitry Andric /// are preserved in a map reference that is also provided during object
586cdc20ff6SDimitry Andric /// creation.
587cdc20ff6SDimitry Andric struct MCDCCoverageBuilder {
588cdc20ff6SDimitry Andric 
589a58f00eaSDimitry Andric   struct DecisionIDPair {
590a58f00eaSDimitry Andric     MCDCConditionID TrueID = 0;
591a58f00eaSDimitry Andric     MCDCConditionID FalseID = 0;
592a58f00eaSDimitry Andric   };
593a58f00eaSDimitry Andric 
594cdc20ff6SDimitry Andric   /// The AST walk recursively visits nested logical-AND or logical-OR binary
595cdc20ff6SDimitry Andric   /// operator nodes and then visits their LHS and RHS children nodes.  As this
596cdc20ff6SDimitry Andric   /// happens, the algorithm will assign IDs to each operator's LHS and RHS side
597cdc20ff6SDimitry Andric   /// as the walk moves deeper into the nest.  At each level of the recursive
598cdc20ff6SDimitry Andric   /// nest, the LHS and RHS may actually correspond to larger subtrees (not
599cdc20ff6SDimitry Andric   /// leaf-conditions). If this is the case, when that node is visited, the ID
600cdc20ff6SDimitry Andric   /// assigned to the subtree is re-assigned to its LHS, and a new ID is given
601cdc20ff6SDimitry Andric   /// to its RHS. At the end of the walk, all leaf-level conditions will have a
602cdc20ff6SDimitry Andric   /// unique ID -- keep in mind that the final set of IDs may not be in
603cdc20ff6SDimitry Andric   /// numerical order from left to right.
604cdc20ff6SDimitry Andric   ///
605cdc20ff6SDimitry Andric   /// Example: "x = (A && B) || (C && D) || (D && F)"
606cdc20ff6SDimitry Andric   ///
607cdc20ff6SDimitry Andric   ///      Visit Depth1:
608cdc20ff6SDimitry Andric   ///              (A && B) || (C && D) || (D && F)
609cdc20ff6SDimitry Andric   ///              ^-------LHS--------^    ^-RHS--^
610cdc20ff6SDimitry Andric   ///                      ID=1              ID=2
611cdc20ff6SDimitry Andric   ///
612cdc20ff6SDimitry Andric   ///      Visit LHS-Depth2:
613cdc20ff6SDimitry Andric   ///              (A && B) || (C && D)
614cdc20ff6SDimitry Andric   ///              ^-LHS--^    ^-RHS--^
615cdc20ff6SDimitry Andric   ///                ID=1        ID=3
616cdc20ff6SDimitry Andric   ///
617cdc20ff6SDimitry Andric   ///      Visit LHS-Depth3:
618cdc20ff6SDimitry Andric   ///               (A && B)
619cdc20ff6SDimitry Andric   ///               LHS   RHS
620cdc20ff6SDimitry Andric   ///               ID=1  ID=4
621cdc20ff6SDimitry Andric   ///
622cdc20ff6SDimitry Andric   ///      Visit RHS-Depth3:
623cdc20ff6SDimitry Andric   ///                         (C && D)
624cdc20ff6SDimitry Andric   ///                         LHS   RHS
625cdc20ff6SDimitry Andric   ///                         ID=3  ID=5
626cdc20ff6SDimitry Andric   ///
627cdc20ff6SDimitry Andric   ///      Visit RHS-Depth2:              (D && F)
628cdc20ff6SDimitry Andric   ///                                     LHS   RHS
629cdc20ff6SDimitry Andric   ///                                     ID=2  ID=6
630cdc20ff6SDimitry Andric   ///
631cdc20ff6SDimitry Andric   ///      Visit Depth1:
632cdc20ff6SDimitry Andric   ///              (A && B)  || (C && D)  || (D && F)
633cdc20ff6SDimitry Andric   ///              ID=1  ID=4   ID=3  ID=5   ID=2  ID=6
634cdc20ff6SDimitry Andric   ///
635cdc20ff6SDimitry Andric   /// A node ID of '0' always means MC/DC isn't being tracked.
636cdc20ff6SDimitry Andric   ///
637a58f00eaSDimitry Andric   /// As the AST walk proceeds recursively, the algorithm will also use a stack
638cdc20ff6SDimitry Andric   /// to track the IDs of logical-AND and logical-OR operations on the RHS so
639cdc20ff6SDimitry Andric   /// that it can be determined which nodes are executed next, depending on how
640cdc20ff6SDimitry Andric   /// a LHS or RHS of a logical-AND or logical-OR is evaluated.  This
641cdc20ff6SDimitry Andric   /// information relies on the assigned IDs and are embedded within the
642cdc20ff6SDimitry Andric   /// coverage region IDs of each branch region associated with a leaf-level
643cdc20ff6SDimitry Andric   /// condition. This information helps the visualization tool reconstruct all
644a58f00eaSDimitry Andric   /// possible test vectors for the purposes of MC/DC analysis. If a "next" node
645cdc20ff6SDimitry Andric   /// ID is '0', it means it's the end of the test vector. The following rules
646cdc20ff6SDimitry Andric   /// are used:
647cdc20ff6SDimitry Andric   ///
648cdc20ff6SDimitry Andric   /// For logical-AND ("LHS && RHS"):
649cdc20ff6SDimitry Andric   /// - If LHS is TRUE, execution goes to the RHS node.
650cdc20ff6SDimitry Andric   /// - If LHS is FALSE, execution goes to the LHS node of the next logical-OR.
651cdc20ff6SDimitry Andric   ///   If that does not exist, execution exits (ID == 0).
652cdc20ff6SDimitry Andric   ///
653cdc20ff6SDimitry Andric   /// - If RHS is TRUE, execution goes to LHS node of the next logical-AND.
654cdc20ff6SDimitry Andric   ///   If that does not exist, execution exits (ID == 0).
655cdc20ff6SDimitry Andric   /// - If RHS is FALSE, execution goes to the LHS node of the next logical-OR.
656cdc20ff6SDimitry Andric   ///   If that does not exist, execution exits (ID == 0).
657cdc20ff6SDimitry Andric   ///
658cdc20ff6SDimitry Andric   /// For logical-OR ("LHS || RHS"):
659cdc20ff6SDimitry Andric   /// - If LHS is TRUE, execution goes to the LHS node of the next logical-AND.
660cdc20ff6SDimitry Andric   ///   If that does not exist, execution exits (ID == 0).
661cdc20ff6SDimitry Andric   /// - If LHS is FALSE, execution goes to the RHS node.
662cdc20ff6SDimitry Andric   ///
663cdc20ff6SDimitry Andric   /// - If RHS is TRUE, execution goes to LHS node of the next logical-AND.
664cdc20ff6SDimitry Andric   ///   If that does not exist, execution exits (ID == 0).
665cdc20ff6SDimitry Andric   /// - If RHS is FALSE, execution goes to the LHS node of the next logical-OR.
666cdc20ff6SDimitry Andric   ///   If that does not exist, execution exits (ID == 0).
667cdc20ff6SDimitry Andric   ///
668cdc20ff6SDimitry Andric   /// Finally, the condition IDs are also used when instrumenting the code to
669cdc20ff6SDimitry Andric   /// indicate a unique offset into a temporary bitmap that represents the true
670cdc20ff6SDimitry Andric   /// or false evaluation of that particular condition.
671cdc20ff6SDimitry Andric   ///
672cdc20ff6SDimitry Andric   /// NOTE regarding the use of CodeGenFunction::stripCond(). Even though, for
673cdc20ff6SDimitry Andric   /// simplicity, parentheses and unary logical-NOT operators are considered
674cdc20ff6SDimitry Andric   /// part of their underlying condition for both MC/DC and branch coverage, the
675cdc20ff6SDimitry Andric   /// condition IDs themselves are assigned and tracked using the underlying
676cdc20ff6SDimitry Andric   /// condition itself.  This is done solely for consistency since parentheses
677cdc20ff6SDimitry Andric   /// and logical-NOTs are ignored when checking whether the condition is
678cdc20ff6SDimitry Andric   /// actually an instrumentable condition. This can also make debugging a bit
679cdc20ff6SDimitry Andric   /// easier.
680cdc20ff6SDimitry Andric 
681cdc20ff6SDimitry Andric private:
682cdc20ff6SDimitry Andric   CodeGenModule &CGM;
683cdc20ff6SDimitry Andric 
684a58f00eaSDimitry Andric   llvm::SmallVector<DecisionIDPair> DecisionStack;
685cdc20ff6SDimitry Andric   llvm::DenseMap<const Stmt *, MCDCConditionID> &CondIDs;
686cdc20ff6SDimitry Andric   llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap;
687cdc20ff6SDimitry Andric   MCDCConditionID NextID = 1;
688cdc20ff6SDimitry Andric   bool NotMapped = false;
689cdc20ff6SDimitry Andric 
690a58f00eaSDimitry Andric   /// Represent a sentinel value of [0,0] for the bottom of DecisionStack.
691a58f00eaSDimitry Andric   static constexpr DecisionIDPair DecisionStackSentinel{0, 0};
692a58f00eaSDimitry Andric 
693cdc20ff6SDimitry Andric   /// Is this a logical-AND operation?
isLAnd__anonc2c3cfe60211::MCDCCoverageBuilder694cdc20ff6SDimitry Andric   bool isLAnd(const BinaryOperator *E) const {
695cdc20ff6SDimitry Andric     return E->getOpcode() == BO_LAnd;
696cdc20ff6SDimitry Andric   }
697cdc20ff6SDimitry Andric 
698cdc20ff6SDimitry Andric public:
MCDCCoverageBuilder__anonc2c3cfe60211::MCDCCoverageBuilder699cdc20ff6SDimitry Andric   MCDCCoverageBuilder(CodeGenModule &CGM,
700cdc20ff6SDimitry Andric                       llvm::DenseMap<const Stmt *, MCDCConditionID> &CondIDMap,
701cdc20ff6SDimitry Andric                       llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap)
702a58f00eaSDimitry Andric       : CGM(CGM), DecisionStack(1, DecisionStackSentinel), CondIDs(CondIDMap),
703a58f00eaSDimitry Andric         MCDCBitmapMap(MCDCBitmapMap) {}
704cdc20ff6SDimitry Andric 
705a58f00eaSDimitry Andric   /// Return whether the build of the control flow map is at the top-level
706a58f00eaSDimitry Andric   /// (root) of a logical operator nest in a boolean expression prior to the
707a58f00eaSDimitry Andric   /// assignment of condition IDs.
isIdle__anonc2c3cfe60211::MCDCCoverageBuilder708a58f00eaSDimitry Andric   bool isIdle() const { return (NextID == 1 && !NotMapped); }
709cdc20ff6SDimitry Andric 
710a58f00eaSDimitry Andric   /// Return whether any IDs have been assigned in the build of the control
711a58f00eaSDimitry Andric   /// flow map, indicating that the map is being generated for this boolean
712a58f00eaSDimitry Andric   /// expression.
isBuilding__anonc2c3cfe60211::MCDCCoverageBuilder713a58f00eaSDimitry Andric   bool isBuilding() const { return (NextID > 1); }
714a58f00eaSDimitry Andric 
715a58f00eaSDimitry Andric   /// Set the given condition's ID.
setCondID__anonc2c3cfe60211::MCDCCoverageBuilder716a58f00eaSDimitry Andric   void setCondID(const Expr *Cond, MCDCConditionID ID) {
717a58f00eaSDimitry Andric     CondIDs[CodeGenFunction::stripCond(Cond)] = ID;
718cdc20ff6SDimitry Andric   }
719cdc20ff6SDimitry Andric 
720cdc20ff6SDimitry Andric   /// Return the ID of a given condition.
getCondID__anonc2c3cfe60211::MCDCCoverageBuilder721cdc20ff6SDimitry Andric   MCDCConditionID getCondID(const Expr *Cond) const {
722cdc20ff6SDimitry Andric     auto I = CondIDs.find(CodeGenFunction::stripCond(Cond));
723cdc20ff6SDimitry Andric     if (I == CondIDs.end())
724cdc20ff6SDimitry Andric       return 0;
725cdc20ff6SDimitry Andric     else
726cdc20ff6SDimitry Andric       return I->second;
727cdc20ff6SDimitry Andric   }
728cdc20ff6SDimitry Andric 
729a58f00eaSDimitry Andric   /// Return the LHS Decision ([0,0] if not set).
back__anonc2c3cfe60211::MCDCCoverageBuilder730a58f00eaSDimitry Andric   const DecisionIDPair &back() const { return DecisionStack.back(); }
731a58f00eaSDimitry Andric 
732cdc20ff6SDimitry Andric   /// Push the binary operator statement to track the nest level and assign IDs
733cdc20ff6SDimitry Andric   /// to the operator's LHS and RHS.  The RHS may be a larger subtree that is
734cdc20ff6SDimitry Andric   /// broken up on successive levels.
pushAndAssignIDs__anonc2c3cfe60211::MCDCCoverageBuilder735cdc20ff6SDimitry Andric   void pushAndAssignIDs(const BinaryOperator *E) {
736cdc20ff6SDimitry Andric     if (!CGM.getCodeGenOpts().MCDCCoverage)
737cdc20ff6SDimitry Andric       return;
738cdc20ff6SDimitry Andric 
739cdc20ff6SDimitry Andric     // If binary expression is disqualified, don't do mapping.
740a58f00eaSDimitry Andric     if (!isBuilding() && !MCDCBitmapMap.contains(CodeGenFunction::stripCond(E)))
741cdc20ff6SDimitry Andric       NotMapped = true;
742cdc20ff6SDimitry Andric 
743cdc20ff6SDimitry Andric     // Don't go any further if we don't need to map condition IDs.
744cdc20ff6SDimitry Andric     if (NotMapped)
745cdc20ff6SDimitry Andric       return;
746cdc20ff6SDimitry Andric 
747a58f00eaSDimitry Andric     const DecisionIDPair &ParentDecision = DecisionStack.back();
748a58f00eaSDimitry Andric 
749cdc20ff6SDimitry Andric     // If the operator itself has an assigned ID, this means it represents a
750a58f00eaSDimitry Andric     // larger subtree.  In this case, assign that ID to its LHS node.  Its RHS
751a58f00eaSDimitry Andric     // will receive a new ID below. Otherwise, assign ID+1 to LHS.
752a58f00eaSDimitry Andric     if (CondIDs.contains(CodeGenFunction::stripCond(E)))
753a58f00eaSDimitry Andric       setCondID(E->getLHS(), getCondID(E));
754a58f00eaSDimitry Andric     else
755a58f00eaSDimitry Andric       setCondID(E->getLHS(), NextID++);
756cdc20ff6SDimitry Andric 
757a58f00eaSDimitry Andric     // Assign a ID+1 for the RHS.
758a58f00eaSDimitry Andric     MCDCConditionID RHSid = NextID++;
759a58f00eaSDimitry Andric     setCondID(E->getRHS(), RHSid);
760a58f00eaSDimitry Andric 
761a58f00eaSDimitry Andric     // Push the LHS decision IDs onto the DecisionStack.
762a58f00eaSDimitry Andric     if (isLAnd(E))
763a58f00eaSDimitry Andric       DecisionStack.push_back({RHSid, ParentDecision.FalseID});
764a58f00eaSDimitry Andric     else
765a58f00eaSDimitry Andric       DecisionStack.push_back({ParentDecision.TrueID, RHSid});
766cdc20ff6SDimitry Andric   }
767cdc20ff6SDimitry Andric 
768a58f00eaSDimitry Andric   /// Pop and return the LHS Decision ([0,0] if not set).
pop__anonc2c3cfe60211::MCDCCoverageBuilder769a58f00eaSDimitry Andric   DecisionIDPair pop() {
770a58f00eaSDimitry Andric     if (!CGM.getCodeGenOpts().MCDCCoverage || NotMapped)
771a58f00eaSDimitry Andric       return DecisionStack.front();
772cdc20ff6SDimitry Andric 
773a58f00eaSDimitry Andric     assert(DecisionStack.size() > 1);
774a58f00eaSDimitry Andric     DecisionIDPair D = DecisionStack.back();
775a58f00eaSDimitry Andric     DecisionStack.pop_back();
776a58f00eaSDimitry Andric     return D;
777cdc20ff6SDimitry Andric   }
778cdc20ff6SDimitry Andric 
779a58f00eaSDimitry Andric   /// Return the total number of conditions and reset the state. The number of
780a58f00eaSDimitry Andric   /// conditions is zero if the expression isn't mapped.
getTotalConditionsAndReset__anonc2c3cfe60211::MCDCCoverageBuilder781a58f00eaSDimitry Andric   unsigned getTotalConditionsAndReset(const BinaryOperator *E) {
782cdc20ff6SDimitry Andric     if (!CGM.getCodeGenOpts().MCDCCoverage)
783cdc20ff6SDimitry Andric       return 0;
784cdc20ff6SDimitry Andric 
785a58f00eaSDimitry Andric     assert(!isIdle());
786a58f00eaSDimitry Andric     assert(DecisionStack.size() == 1);
787cdc20ff6SDimitry Andric 
788cdc20ff6SDimitry Andric     // Reset state if not doing mapping.
789a58f00eaSDimitry Andric     if (NotMapped) {
790cdc20ff6SDimitry Andric       NotMapped = false;
791a58f00eaSDimitry Andric       assert(NextID == 1);
792cdc20ff6SDimitry Andric       return 0;
793cdc20ff6SDimitry Andric     }
794cdc20ff6SDimitry Andric 
795a58f00eaSDimitry Andric     // Set number of conditions and reset.
796a58f00eaSDimitry Andric     unsigned TotalConds = NextID - 1;
797cdc20ff6SDimitry Andric 
798cdc20ff6SDimitry Andric     // Reset ID back to beginning.
799cdc20ff6SDimitry Andric     NextID = 1;
800a58f00eaSDimitry Andric 
801cdc20ff6SDimitry Andric     return TotalConds;
802cdc20ff6SDimitry Andric   }
803cdc20ff6SDimitry Andric };
804cdc20ff6SDimitry Andric 
8050b57cec5SDimitry Andric /// A StmtVisitor that creates coverage mapping regions which map
8060b57cec5SDimitry Andric /// from the source code locations to the PGO counters.
8070b57cec5SDimitry Andric struct CounterCoverageMappingBuilder
8080b57cec5SDimitry Andric     : public CoverageMappingBuilder,
8090b57cec5SDimitry Andric       public ConstStmtVisitor<CounterCoverageMappingBuilder> {
8100b57cec5SDimitry Andric   /// The map of statements to count values.
8110b57cec5SDimitry Andric   llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
8120b57cec5SDimitry Andric 
813cdc20ff6SDimitry Andric   /// The map of statements to bitmap coverage object values.
814cdc20ff6SDimitry Andric   llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap;
815cdc20ff6SDimitry Andric 
8160b57cec5SDimitry Andric   /// A stack of currently live regions.
817cdc20ff6SDimitry Andric   llvm::SmallVector<SourceMappingRegion> RegionStack;
818cdc20ff6SDimitry Andric 
819cdc20ff6SDimitry Andric   /// An object to manage MCDC regions.
820cdc20ff6SDimitry Andric   MCDCCoverageBuilder MCDCBuilder;
8210b57cec5SDimitry Andric 
8220b57cec5SDimitry Andric   CounterExpressionBuilder Builder;
8230b57cec5SDimitry Andric 
8240b57cec5SDimitry Andric   /// A location in the most recently visited file or macro.
8250b57cec5SDimitry Andric   ///
8260b57cec5SDimitry Andric   /// This is used to adjust the active source regions appropriately when
8270b57cec5SDimitry Andric   /// expressions cross file or macro boundaries.
8280b57cec5SDimitry Andric   SourceLocation MostRecentLocation;
8290b57cec5SDimitry Andric 
830fe6060f1SDimitry Andric   /// Whether the visitor at a terminate statement.
831fe6060f1SDimitry Andric   bool HasTerminateStmt = false;
832fe6060f1SDimitry Andric 
833fe6060f1SDimitry Andric   /// Gap region counter after terminate statement.
834fe6060f1SDimitry Andric   Counter GapRegionCounter;
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric   /// Return a counter for the subtraction of \c RHS from \c LHS
subtractCounters__anonc2c3cfe60211::CounterCoverageMappingBuilder83781ad6265SDimitry Andric   Counter subtractCounters(Counter LHS, Counter RHS, bool Simplify = true) {
83881ad6265SDimitry Andric     return Builder.subtract(LHS, RHS, Simplify);
8390b57cec5SDimitry Andric   }
8400b57cec5SDimitry Andric 
8410b57cec5SDimitry Andric   /// Return a counter for the sum of \c LHS and \c RHS.
addCounters__anonc2c3cfe60211::CounterCoverageMappingBuilder84281ad6265SDimitry Andric   Counter addCounters(Counter LHS, Counter RHS, bool Simplify = true) {
84381ad6265SDimitry Andric     return Builder.add(LHS, RHS, Simplify);
8440b57cec5SDimitry Andric   }
8450b57cec5SDimitry Andric 
addCounters__anonc2c3cfe60211::CounterCoverageMappingBuilder84681ad6265SDimitry Andric   Counter addCounters(Counter C1, Counter C2, Counter C3,
84781ad6265SDimitry Andric                       bool Simplify = true) {
84881ad6265SDimitry Andric     return addCounters(addCounters(C1, C2, Simplify), C3, Simplify);
8490b57cec5SDimitry Andric   }
8500b57cec5SDimitry Andric 
8510b57cec5SDimitry Andric   /// Return the region counter for the given statement.
8520b57cec5SDimitry Andric   ///
8530b57cec5SDimitry Andric   /// This should only be called on statements that have a dedicated counter.
getRegionCounter__anonc2c3cfe60211::CounterCoverageMappingBuilder8540b57cec5SDimitry Andric   Counter getRegionCounter(const Stmt *S) {
8550b57cec5SDimitry Andric     return Counter::getCounter(CounterMap[S]);
8560b57cec5SDimitry Andric   }
8570b57cec5SDimitry Andric 
getRegionBitmap__anonc2c3cfe60211::CounterCoverageMappingBuilder858cdc20ff6SDimitry Andric   unsigned getRegionBitmap(const Stmt *S) { return MCDCBitmapMap[S]; }
859cdc20ff6SDimitry Andric 
8600b57cec5SDimitry Andric   /// Push a region onto the stack.
8610b57cec5SDimitry Andric   ///
8620b57cec5SDimitry Andric   /// Returns the index on the stack where the region was pushed. This can be
8630b57cec5SDimitry Andric   /// used with popRegions to exit a "scope", ending the region that was pushed.
pushRegion__anonc2c3cfe60211::CounterCoverageMappingBuilder864bdd1243dSDimitry Andric   size_t pushRegion(Counter Count,
865bdd1243dSDimitry Andric                     std::optional<SourceLocation> StartLoc = std::nullopt,
866bdd1243dSDimitry Andric                     std::optional<SourceLocation> EndLoc = std::nullopt,
867cdc20ff6SDimitry Andric                     std::optional<Counter> FalseCount = std::nullopt,
868cdc20ff6SDimitry Andric                     MCDCConditionID ID = 0, MCDCConditionID TrueID = 0,
869cdc20ff6SDimitry Andric                     MCDCConditionID FalseID = 0) {
870e8d8bef9SDimitry Andric 
87181ad6265SDimitry Andric     if (StartLoc && !FalseCount) {
8720b57cec5SDimitry Andric       MostRecentLocation = *StartLoc;
8730b57cec5SDimitry Andric     }
874e8d8bef9SDimitry Andric 
875fe013be4SDimitry Andric     // If either of these locations is invalid, something elsewhere in the
876fe013be4SDimitry Andric     // compiler has broken.
877fe013be4SDimitry Andric     assert((!StartLoc || StartLoc->isValid()) && "Start location is not valid");
878fe013be4SDimitry Andric     assert((!EndLoc || EndLoc->isValid()) && "End location is not valid");
879fe013be4SDimitry Andric 
880fe013be4SDimitry Andric     // However, we can still recover without crashing.
881fe013be4SDimitry Andric     // If either location is invalid, set it to std::nullopt to avoid
882fe013be4SDimitry Andric     // letting users of RegionStack think that region has a valid start/end
883fe013be4SDimitry Andric     // location.
884fe013be4SDimitry Andric     if (StartLoc && StartLoc->isInvalid())
885fe013be4SDimitry Andric       StartLoc = std::nullopt;
886fe013be4SDimitry Andric     if (EndLoc && EndLoc->isInvalid())
887fe013be4SDimitry Andric       EndLoc = std::nullopt;
888cdc20ff6SDimitry Andric     RegionStack.emplace_back(Count, FalseCount,
889cdc20ff6SDimitry Andric                              MCDCParameters{0, 0, ID, TrueID, FalseID},
890cdc20ff6SDimitry Andric                              StartLoc, EndLoc);
891cdc20ff6SDimitry Andric 
892cdc20ff6SDimitry Andric     return RegionStack.size() - 1;
893cdc20ff6SDimitry Andric   }
894cdc20ff6SDimitry Andric 
pushRegion__anonc2c3cfe60211::CounterCoverageMappingBuilder895cdc20ff6SDimitry Andric   size_t pushRegion(unsigned BitmapIdx, unsigned Conditions,
896cdc20ff6SDimitry Andric                     std::optional<SourceLocation> StartLoc = std::nullopt,
897cdc20ff6SDimitry Andric                     std::optional<SourceLocation> EndLoc = std::nullopt) {
898cdc20ff6SDimitry Andric 
899cdc20ff6SDimitry Andric     RegionStack.emplace_back(MCDCParameters{BitmapIdx, Conditions}, StartLoc,
900cdc20ff6SDimitry Andric                              EndLoc);
9010b57cec5SDimitry Andric 
9020b57cec5SDimitry Andric     return RegionStack.size() - 1;
9030b57cec5SDimitry Andric   }
9040b57cec5SDimitry Andric 
locationDepth__anonc2c3cfe60211::CounterCoverageMappingBuilder9050b57cec5SDimitry Andric   size_t locationDepth(SourceLocation Loc) {
9060b57cec5SDimitry Andric     size_t Depth = 0;
9070b57cec5SDimitry Andric     while (Loc.isValid()) {
9080b57cec5SDimitry Andric       Loc = getIncludeOrExpansionLoc(Loc);
9090b57cec5SDimitry Andric       Depth++;
9100b57cec5SDimitry Andric     }
9110b57cec5SDimitry Andric     return Depth;
9120b57cec5SDimitry Andric   }
9130b57cec5SDimitry Andric 
9140b57cec5SDimitry Andric   /// Pop regions from the stack into the function's list of regions.
9150b57cec5SDimitry Andric   ///
9160b57cec5SDimitry Andric   /// Adds all regions from \c ParentIndex to the top of the stack to the
9170b57cec5SDimitry Andric   /// function's \c SourceRegions.
popRegions__anonc2c3cfe60211::CounterCoverageMappingBuilder9180b57cec5SDimitry Andric   void popRegions(size_t ParentIndex) {
9190b57cec5SDimitry Andric     assert(RegionStack.size() >= ParentIndex && "parent not in stack");
9200b57cec5SDimitry Andric     while (RegionStack.size() > ParentIndex) {
9210b57cec5SDimitry Andric       SourceMappingRegion &Region = RegionStack.back();
922fe013be4SDimitry Andric       if (Region.hasStartLoc() &&
923fe013be4SDimitry Andric           (Region.hasEndLoc() || RegionStack[ParentIndex].hasEndLoc())) {
9240b57cec5SDimitry Andric         SourceLocation StartLoc = Region.getBeginLoc();
9250b57cec5SDimitry Andric         SourceLocation EndLoc = Region.hasEndLoc()
9260b57cec5SDimitry Andric                                     ? Region.getEndLoc()
9270b57cec5SDimitry Andric                                     : RegionStack[ParentIndex].getEndLoc();
928e8d8bef9SDimitry Andric         bool isBranch = Region.isBranch();
9290b57cec5SDimitry Andric         size_t StartDepth = locationDepth(StartLoc);
9300b57cec5SDimitry Andric         size_t EndDepth = locationDepth(EndLoc);
9310b57cec5SDimitry Andric         while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) {
9320b57cec5SDimitry Andric           bool UnnestStart = StartDepth >= EndDepth;
9330b57cec5SDimitry Andric           bool UnnestEnd = EndDepth >= StartDepth;
9340b57cec5SDimitry Andric           if (UnnestEnd) {
935e8d8bef9SDimitry Andric             // The region ends in a nested file or macro expansion. If the
936e8d8bef9SDimitry Andric             // region is not a branch region, create a separate region for each
937e8d8bef9SDimitry Andric             // expansion, and for all regions, update the EndLoc. Branch
938e8d8bef9SDimitry Andric             // regions should not be split in order to keep a straightforward
939e8d8bef9SDimitry Andric             // correspondance between the region and its associated branch
940e8d8bef9SDimitry Andric             // condition, even if the condition spans multiple depths.
9410b57cec5SDimitry Andric             SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
9420b57cec5SDimitry Andric             assert(SM.isWrittenInSameFile(NestedLoc, EndLoc));
9430b57cec5SDimitry Andric 
944e8d8bef9SDimitry Andric             if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
945e8d8bef9SDimitry Andric               SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
946e8d8bef9SDimitry Andric                                          EndLoc);
9470b57cec5SDimitry Andric 
9480b57cec5SDimitry Andric             EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
9490b57cec5SDimitry Andric             if (EndLoc.isInvalid())
950e8d8bef9SDimitry Andric               llvm::report_fatal_error(
951e8d8bef9SDimitry Andric                   "File exit not handled before popRegions");
9520b57cec5SDimitry Andric             EndDepth--;
9530b57cec5SDimitry Andric           }
9540b57cec5SDimitry Andric           if (UnnestStart) {
955e8d8bef9SDimitry Andric             // The region ends in a nested file or macro expansion. If the
956e8d8bef9SDimitry Andric             // region is not a branch region, create a separate region for each
957e8d8bef9SDimitry Andric             // expansion, and for all regions, update the StartLoc. Branch
958e8d8bef9SDimitry Andric             // regions should not be split in order to keep a straightforward
959e8d8bef9SDimitry Andric             // correspondance between the region and its associated branch
960e8d8bef9SDimitry Andric             // condition, even if the condition spans multiple depths.
9610b57cec5SDimitry Andric             SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
9620b57cec5SDimitry Andric             assert(SM.isWrittenInSameFile(StartLoc, NestedLoc));
9630b57cec5SDimitry Andric 
964e8d8bef9SDimitry Andric             if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
965e8d8bef9SDimitry Andric               SourceRegions.emplace_back(Region.getCounter(), StartLoc,
966e8d8bef9SDimitry Andric                                          NestedLoc);
9670b57cec5SDimitry Andric 
9680b57cec5SDimitry Andric             StartLoc = getIncludeOrExpansionLoc(StartLoc);
9690b57cec5SDimitry Andric             if (StartLoc.isInvalid())
970e8d8bef9SDimitry Andric               llvm::report_fatal_error(
971e8d8bef9SDimitry Andric                   "File exit not handled before popRegions");
9720b57cec5SDimitry Andric             StartDepth--;
9730b57cec5SDimitry Andric           }
9740b57cec5SDimitry Andric         }
9750b57cec5SDimitry Andric         Region.setStartLoc(StartLoc);
9760b57cec5SDimitry Andric         Region.setEndLoc(EndLoc);
9770b57cec5SDimitry Andric 
978e8d8bef9SDimitry Andric         if (!isBranch) {
9790b57cec5SDimitry Andric           MostRecentLocation = EndLoc;
980e8d8bef9SDimitry Andric           // If this region happens to span an entire expansion, we need to
981e8d8bef9SDimitry Andric           // make sure we don't overlap the parent region with it.
9820b57cec5SDimitry Andric           if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
9830b57cec5SDimitry Andric               EndLoc == getEndOfFileOrMacro(EndLoc))
9840b57cec5SDimitry Andric             MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
985e8d8bef9SDimitry Andric         }
9860b57cec5SDimitry Andric 
9870b57cec5SDimitry Andric         assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
9880b57cec5SDimitry Andric         assert(SpellingRegion(SM, Region).isInSourceOrder());
9890b57cec5SDimitry Andric         SourceRegions.push_back(Region);
9900b57cec5SDimitry Andric       }
9910b57cec5SDimitry Andric       RegionStack.pop_back();
9920b57cec5SDimitry Andric     }
9930b57cec5SDimitry Andric   }
9940b57cec5SDimitry Andric 
9950b57cec5SDimitry Andric   /// Return the currently active region.
getRegion__anonc2c3cfe60211::CounterCoverageMappingBuilder9960b57cec5SDimitry Andric   SourceMappingRegion &getRegion() {
9970b57cec5SDimitry Andric     assert(!RegionStack.empty() && "statement has no region");
9980b57cec5SDimitry Andric     return RegionStack.back();
9990b57cec5SDimitry Andric   }
10000b57cec5SDimitry Andric 
10010b57cec5SDimitry Andric   /// Propagate counts through the children of \p S if \p VisitChildren is true.
10020b57cec5SDimitry Andric   /// Otherwise, only emit a count for \p S itself.
propagateCounts__anonc2c3cfe60211::CounterCoverageMappingBuilder10030b57cec5SDimitry Andric   Counter propagateCounts(Counter TopCount, const Stmt *S,
10040b57cec5SDimitry Andric                           bool VisitChildren = true) {
10050b57cec5SDimitry Andric     SourceLocation StartLoc = getStart(S);
10060b57cec5SDimitry Andric     SourceLocation EndLoc = getEnd(S);
10070b57cec5SDimitry Andric     size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
10080b57cec5SDimitry Andric     if (VisitChildren)
10090b57cec5SDimitry Andric       Visit(S);
10100b57cec5SDimitry Andric     Counter ExitCount = getRegion().getCounter();
10110b57cec5SDimitry Andric     popRegions(Index);
10120b57cec5SDimitry Andric 
10130b57cec5SDimitry Andric     // The statement may be spanned by an expansion. Make sure we handle a file
10140b57cec5SDimitry Andric     // exit out of this expansion before moving to the next statement.
10150b57cec5SDimitry Andric     if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
10160b57cec5SDimitry Andric       MostRecentLocation = EndLoc;
10170b57cec5SDimitry Andric 
10180b57cec5SDimitry Andric     return ExitCount;
10190b57cec5SDimitry Andric   }
10200b57cec5SDimitry Andric 
1021e8d8bef9SDimitry Andric   /// Determine whether the given condition can be constant folded.
ConditionFoldsToBool__anonc2c3cfe60211::CounterCoverageMappingBuilder1022e8d8bef9SDimitry Andric   bool ConditionFoldsToBool(const Expr *Cond) {
1023e8d8bef9SDimitry Andric     Expr::EvalResult Result;
1024e8d8bef9SDimitry Andric     return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext()));
1025e8d8bef9SDimitry Andric   }
1026e8d8bef9SDimitry Andric 
1027a58f00eaSDimitry Andric   using MCDCDecisionIDPair = MCDCCoverageBuilder::DecisionIDPair;
1028a58f00eaSDimitry Andric 
1029e8d8bef9SDimitry Andric   /// Create a Branch Region around an instrumentable condition for coverage
1030e8d8bef9SDimitry Andric   /// and add it to the function's SourceRegions.  A branch region tracks a
1031e8d8bef9SDimitry Andric   /// "True" counter and a "False" counter for boolean expressions that
1032e8d8bef9SDimitry Andric   /// result in the generation of a branch.
1033a58f00eaSDimitry Andric   void
createBranchRegion__anonc2c3cfe60211::CounterCoverageMappingBuilder1034a58f00eaSDimitry Andric   createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt,
1035a58f00eaSDimitry Andric                      const MCDCDecisionIDPair &IDPair = MCDCDecisionIDPair()) {
1036e8d8bef9SDimitry Andric     // Check for NULL conditions.
1037e8d8bef9SDimitry Andric     if (!C)
1038e8d8bef9SDimitry Andric       return;
1039e8d8bef9SDimitry Andric 
1040e8d8bef9SDimitry Andric     // Ensure we are an instrumentable condition (i.e. no "&&" or "||").  Push
1041e8d8bef9SDimitry Andric     // region onto RegionStack but immediately pop it (which adds it to the
1042e8d8bef9SDimitry Andric     // function's SourceRegions) because it doesn't apply to any other source
1043e8d8bef9SDimitry Andric     // code other than the Condition.
1044e8d8bef9SDimitry Andric     if (CodeGenFunction::isInstrumentedCondition(C)) {
1045a58f00eaSDimitry Andric       MCDCConditionID ID = MCDCBuilder.getCondID(C);
1046a58f00eaSDimitry Andric       MCDCConditionID TrueID = IDPair.TrueID;
1047a58f00eaSDimitry Andric       MCDCConditionID FalseID = IDPair.FalseID;
1048a58f00eaSDimitry Andric 
1049e8d8bef9SDimitry Andric       // If a condition can fold to true or false, the corresponding branch
1050e8d8bef9SDimitry Andric       // will be removed.  Create a region with both counters hard-coded to
1051e8d8bef9SDimitry Andric       // zero. This allows us to visualize them in a special way.
1052e8d8bef9SDimitry Andric       // Alternatively, we can prevent any optimization done via
1053e8d8bef9SDimitry Andric       // constant-folding by ensuring that ConstantFoldsToSimpleInteger() in
1054e8d8bef9SDimitry Andric       // CodeGenFunction.c always returns false, but that is very heavy-handed.
1055e8d8bef9SDimitry Andric       if (ConditionFoldsToBool(C))
1056e8d8bef9SDimitry Andric         popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C),
1057cdc20ff6SDimitry Andric                               Counter::getZero(), ID, TrueID, FalseID));
1058e8d8bef9SDimitry Andric       else
1059e8d8bef9SDimitry Andric         // Otherwise, create a region with the True counter and False counter.
1060cdc20ff6SDimitry Andric         popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt, ID,
1061cdc20ff6SDimitry Andric                               TrueID, FalseID));
1062e8d8bef9SDimitry Andric     }
1063e8d8bef9SDimitry Andric   }
1064e8d8bef9SDimitry Andric 
1065cdc20ff6SDimitry Andric   /// Create a Decision Region with a BitmapIdx and number of Conditions. This
1066cdc20ff6SDimitry Andric   /// type of region "contains" branch regions, one for each of the conditions.
1067cdc20ff6SDimitry Andric   /// The visualization tool will group everything together.
createDecisionRegion__anonc2c3cfe60211::CounterCoverageMappingBuilder1068cdc20ff6SDimitry Andric   void createDecisionRegion(const Expr *C, unsigned BitmapIdx, unsigned Conds) {
1069cdc20ff6SDimitry Andric     popRegions(pushRegion(BitmapIdx, Conds, getStart(C), getEnd(C)));
1070cdc20ff6SDimitry Andric   }
1071cdc20ff6SDimitry Andric 
1072e8d8bef9SDimitry Andric   /// Create a Branch Region around a SwitchCase for code coverage
1073e8d8bef9SDimitry Andric   /// and add it to the function's SourceRegions.
createSwitchCaseRegion__anonc2c3cfe60211::CounterCoverageMappingBuilder1074e8d8bef9SDimitry Andric   void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt,
1075e8d8bef9SDimitry Andric                               Counter FalseCnt) {
1076e8d8bef9SDimitry Andric     // Push region onto RegionStack but immediately pop it (which adds it to
1077e8d8bef9SDimitry Andric     // the function's SourceRegions) because it doesn't apply to any other
1078e8d8bef9SDimitry Andric     // source other than the SwitchCase.
1079e8d8bef9SDimitry Andric     popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt));
1080e8d8bef9SDimitry Andric   }
1081e8d8bef9SDimitry Andric 
10820b57cec5SDimitry Andric   /// Check whether a region with bounds \c StartLoc and \c EndLoc
10830b57cec5SDimitry Andric   /// is already added to \c SourceRegions.
isRegionAlreadyAdded__anonc2c3cfe60211::CounterCoverageMappingBuilder1084e8d8bef9SDimitry Andric   bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
1085e8d8bef9SDimitry Andric                             bool isBranch = false) {
1086349cc55cSDimitry Andric     return llvm::any_of(
1087349cc55cSDimitry Andric         llvm::reverse(SourceRegions), [&](const SourceMappingRegion &Region) {
10880b57cec5SDimitry Andric           return Region.getBeginLoc() == StartLoc &&
1089349cc55cSDimitry Andric                  Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch;
10900b57cec5SDimitry Andric         });
10910b57cec5SDimitry Andric   }
10920b57cec5SDimitry Andric 
10930b57cec5SDimitry Andric   /// Adjust the most recently visited location to \c EndLoc.
10940b57cec5SDimitry Andric   ///
10950b57cec5SDimitry Andric   /// This should be used after visiting any statements in non-source order.
adjustForOutOfOrderTraversal__anonc2c3cfe60211::CounterCoverageMappingBuilder10960b57cec5SDimitry Andric   void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
10970b57cec5SDimitry Andric     MostRecentLocation = EndLoc;
10980b57cec5SDimitry Andric     // The code region for a whole macro is created in handleFileExit() when
10990b57cec5SDimitry Andric     // it detects exiting of the virtual file of that macro. If we visited
11000b57cec5SDimitry Andric     // statements in non-source order, we might already have such a region
11010b57cec5SDimitry Andric     // added, for example, if a body of a loop is divided among multiple
11020b57cec5SDimitry Andric     // macros. Avoid adding duplicate regions in such case.
11030b57cec5SDimitry Andric     if (getRegion().hasEndLoc() &&
11040b57cec5SDimitry Andric         MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
11050b57cec5SDimitry Andric         isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
1106e8d8bef9SDimitry Andric                              MostRecentLocation, getRegion().isBranch()))
11070b57cec5SDimitry Andric       MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
11080b57cec5SDimitry Andric   }
11090b57cec5SDimitry Andric 
11100b57cec5SDimitry Andric   /// Adjust regions and state when \c NewLoc exits a file.
11110b57cec5SDimitry Andric   ///
11120b57cec5SDimitry Andric   /// If moving from our most recently tracked location to \c NewLoc exits any
11130b57cec5SDimitry Andric   /// files, this adjusts our current region stack and creates the file regions
11140b57cec5SDimitry Andric   /// for the exited file.
handleFileExit__anonc2c3cfe60211::CounterCoverageMappingBuilder11150b57cec5SDimitry Andric   void handleFileExit(SourceLocation NewLoc) {
11160b57cec5SDimitry Andric     if (NewLoc.isInvalid() ||
11170b57cec5SDimitry Andric         SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
11180b57cec5SDimitry Andric       return;
11190b57cec5SDimitry Andric 
11200b57cec5SDimitry Andric     // If NewLoc is not in a file that contains MostRecentLocation, walk up to
11210b57cec5SDimitry Andric     // find the common ancestor.
11220b57cec5SDimitry Andric     SourceLocation LCA = NewLoc;
11230b57cec5SDimitry Andric     FileID ParentFile = SM.getFileID(LCA);
11240b57cec5SDimitry Andric     while (!isNestedIn(MostRecentLocation, ParentFile)) {
11250b57cec5SDimitry Andric       LCA = getIncludeOrExpansionLoc(LCA);
11260b57cec5SDimitry Andric       if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
11270b57cec5SDimitry Andric         // Since there isn't a common ancestor, no file was exited. We just need
11280b57cec5SDimitry Andric         // to adjust our location to the new file.
11290b57cec5SDimitry Andric         MostRecentLocation = NewLoc;
11300b57cec5SDimitry Andric         return;
11310b57cec5SDimitry Andric       }
11320b57cec5SDimitry Andric       ParentFile = SM.getFileID(LCA);
11330b57cec5SDimitry Andric     }
11340b57cec5SDimitry Andric 
11350b57cec5SDimitry Andric     llvm::SmallSet<SourceLocation, 8> StartLocs;
1136bdd1243dSDimitry Andric     std::optional<Counter> ParentCounter;
11370b57cec5SDimitry Andric     for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
11380b57cec5SDimitry Andric       if (!I.hasStartLoc())
11390b57cec5SDimitry Andric         continue;
11400b57cec5SDimitry Andric       SourceLocation Loc = I.getBeginLoc();
11410b57cec5SDimitry Andric       if (!isNestedIn(Loc, ParentFile)) {
11420b57cec5SDimitry Andric         ParentCounter = I.getCounter();
11430b57cec5SDimitry Andric         break;
11440b57cec5SDimitry Andric       }
11450b57cec5SDimitry Andric 
11460b57cec5SDimitry Andric       while (!SM.isInFileID(Loc, ParentFile)) {
11470b57cec5SDimitry Andric         // The most nested region for each start location is the one with the
11480b57cec5SDimitry Andric         // correct count. We avoid creating redundant regions by stopping once
11490b57cec5SDimitry Andric         // we've seen this region.
1150e8d8bef9SDimitry Andric         if (StartLocs.insert(Loc).second) {
1151e8d8bef9SDimitry Andric           if (I.isBranch())
1152cdc20ff6SDimitry Andric             SourceRegions.emplace_back(
1153cdc20ff6SDimitry Andric                 I.getCounter(), I.getFalseCounter(),
1154cdc20ff6SDimitry Andric                 MCDCParameters{0, 0, I.getMCDCParams().ID,
1155cdc20ff6SDimitry Andric                                I.getMCDCParams().TrueID,
1156cdc20ff6SDimitry Andric                                I.getMCDCParams().FalseID},
1157cdc20ff6SDimitry Andric                 Loc, getEndOfFileOrMacro(Loc), I.isBranch());
1158e8d8bef9SDimitry Andric           else
11590b57cec5SDimitry Andric             SourceRegions.emplace_back(I.getCounter(), Loc,
11600b57cec5SDimitry Andric                                        getEndOfFileOrMacro(Loc));
1161e8d8bef9SDimitry Andric         }
11620b57cec5SDimitry Andric         Loc = getIncludeOrExpansionLoc(Loc);
11630b57cec5SDimitry Andric       }
11640b57cec5SDimitry Andric       I.setStartLoc(getPreciseTokenLocEnd(Loc));
11650b57cec5SDimitry Andric     }
11660b57cec5SDimitry Andric 
11670b57cec5SDimitry Andric     if (ParentCounter) {
11680b57cec5SDimitry Andric       // If the file is contained completely by another region and doesn't
11690b57cec5SDimitry Andric       // immediately start its own region, the whole file gets a region
11700b57cec5SDimitry Andric       // corresponding to the parent.
11710b57cec5SDimitry Andric       SourceLocation Loc = MostRecentLocation;
11720b57cec5SDimitry Andric       while (isNestedIn(Loc, ParentFile)) {
11730b57cec5SDimitry Andric         SourceLocation FileStart = getStartOfFileOrMacro(Loc);
11740b57cec5SDimitry Andric         if (StartLocs.insert(FileStart).second) {
11750b57cec5SDimitry Andric           SourceRegions.emplace_back(*ParentCounter, FileStart,
11760b57cec5SDimitry Andric                                      getEndOfFileOrMacro(Loc));
11770b57cec5SDimitry Andric           assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder());
11780b57cec5SDimitry Andric         }
11790b57cec5SDimitry Andric         Loc = getIncludeOrExpansionLoc(Loc);
11800b57cec5SDimitry Andric       }
11810b57cec5SDimitry Andric     }
11820b57cec5SDimitry Andric 
11830b57cec5SDimitry Andric     MostRecentLocation = NewLoc;
11840b57cec5SDimitry Andric   }
11850b57cec5SDimitry Andric 
11860b57cec5SDimitry Andric   /// Ensure that \c S is included in the current region.
extendRegion__anonc2c3cfe60211::CounterCoverageMappingBuilder11870b57cec5SDimitry Andric   void extendRegion(const Stmt *S) {
11880b57cec5SDimitry Andric     SourceMappingRegion &Region = getRegion();
11890b57cec5SDimitry Andric     SourceLocation StartLoc = getStart(S);
11900b57cec5SDimitry Andric 
11910b57cec5SDimitry Andric     handleFileExit(StartLoc);
11920b57cec5SDimitry Andric     if (!Region.hasStartLoc())
11930b57cec5SDimitry Andric       Region.setStartLoc(StartLoc);
11940b57cec5SDimitry Andric   }
11950b57cec5SDimitry Andric 
11960b57cec5SDimitry Andric   /// Mark \c S as a terminator, starting a zero region.
terminateRegion__anonc2c3cfe60211::CounterCoverageMappingBuilder11970b57cec5SDimitry Andric   void terminateRegion(const Stmt *S) {
11980b57cec5SDimitry Andric     extendRegion(S);
11990b57cec5SDimitry Andric     SourceMappingRegion &Region = getRegion();
12000b57cec5SDimitry Andric     SourceLocation EndLoc = getEnd(S);
12010b57cec5SDimitry Andric     if (!Region.hasEndLoc())
12020b57cec5SDimitry Andric       Region.setEndLoc(EndLoc);
12030b57cec5SDimitry Andric     pushRegion(Counter::getZero());
1204fe6060f1SDimitry Andric     HasTerminateStmt = true;
12050b57cec5SDimitry Andric   }
12060b57cec5SDimitry Andric 
12070b57cec5SDimitry Andric   /// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
findGapAreaBetween__anonc2c3cfe60211::CounterCoverageMappingBuilder1208bdd1243dSDimitry Andric   std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
12090b57cec5SDimitry Andric                                                 SourceLocation BeforeLoc) {
1210*fe72d8ecSDimitry Andric     // Some statements (like AttributedStmt and ImplicitValueInitExpr) don't
1211*fe72d8ecSDimitry Andric     // have valid source locations. Do not emit a gap region if this is the case
1212*fe72d8ecSDimitry Andric     // in either AfterLoc end or BeforeLoc end.
1213*fe72d8ecSDimitry Andric     if (AfterLoc.isInvalid() || BeforeLoc.isInvalid())
1214*fe72d8ecSDimitry Andric       return std::nullopt;
1215*fe72d8ecSDimitry Andric 
1216fe6060f1SDimitry Andric     // If AfterLoc is in function-like macro, use the right parenthesis
1217fe6060f1SDimitry Andric     // location.
1218fe6060f1SDimitry Andric     if (AfterLoc.isMacroID()) {
1219fe6060f1SDimitry Andric       FileID FID = SM.getFileID(AfterLoc);
1220fe6060f1SDimitry Andric       const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion();
1221fe6060f1SDimitry Andric       if (EI->isFunctionMacroExpansion())
1222fe6060f1SDimitry Andric         AfterLoc = EI->getExpansionLocEnd();
1223fe6060f1SDimitry Andric     }
1224fe6060f1SDimitry Andric 
1225fe6060f1SDimitry Andric     size_t StartDepth = locationDepth(AfterLoc);
1226fe6060f1SDimitry Andric     size_t EndDepth = locationDepth(BeforeLoc);
1227fe6060f1SDimitry Andric     while (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
1228fe6060f1SDimitry Andric       bool UnnestStart = StartDepth >= EndDepth;
1229fe6060f1SDimitry Andric       bool UnnestEnd = EndDepth >= StartDepth;
1230fe6060f1SDimitry Andric       if (UnnestEnd) {
1231fe6060f1SDimitry Andric         assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1232fe6060f1SDimitry Andric                                       BeforeLoc));
1233fe6060f1SDimitry Andric 
1234fe6060f1SDimitry Andric         BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1235fe6060f1SDimitry Andric         assert(BeforeLoc.isValid());
1236fe6060f1SDimitry Andric         EndDepth--;
1237fe6060f1SDimitry Andric       }
1238fe6060f1SDimitry Andric       if (UnnestStart) {
1239fe6060f1SDimitry Andric         assert(SM.isWrittenInSameFile(AfterLoc,
1240fe6060f1SDimitry Andric                                       getEndOfFileOrMacro(AfterLoc)));
1241fe6060f1SDimitry Andric 
1242fe6060f1SDimitry Andric         AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
1243fe6060f1SDimitry Andric         assert(AfterLoc.isValid());
1244fe6060f1SDimitry Andric         AfterLoc = getPreciseTokenLocEnd(AfterLoc);
1245fe6060f1SDimitry Andric         assert(AfterLoc.isValid());
1246fe6060f1SDimitry Andric         StartDepth--;
1247fe6060f1SDimitry Andric       }
1248fe6060f1SDimitry Andric     }
1249fe6060f1SDimitry Andric     AfterLoc = getPreciseTokenLocEnd(AfterLoc);
12500b57cec5SDimitry Andric     // If the start and end locations of the gap are both within the same macro
12510b57cec5SDimitry Andric     // file, the range may not be in source order.
12520b57cec5SDimitry Andric     if (AfterLoc.isMacroID() || BeforeLoc.isMacroID())
1253bdd1243dSDimitry Andric       return std::nullopt;
1254fe6060f1SDimitry Andric     if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
1255fe6060f1SDimitry Andric         !SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder())
1256bdd1243dSDimitry Andric       return std::nullopt;
12570b57cec5SDimitry Andric     return {{AfterLoc, BeforeLoc}};
12580b57cec5SDimitry Andric   }
12590b57cec5SDimitry Andric 
12600b57cec5SDimitry Andric   /// Emit a gap region between \p StartLoc and \p EndLoc with the given count.
fillGapAreaWithCount__anonc2c3cfe60211::CounterCoverageMappingBuilder12610b57cec5SDimitry Andric   void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
12620b57cec5SDimitry Andric                             Counter Count) {
12630b57cec5SDimitry Andric     if (StartLoc == EndLoc)
12640b57cec5SDimitry Andric       return;
12650b57cec5SDimitry Andric     assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder());
12660b57cec5SDimitry Andric     handleFileExit(StartLoc);
12670b57cec5SDimitry Andric     size_t Index = pushRegion(Count, StartLoc, EndLoc);
12680b57cec5SDimitry Andric     getRegion().setGap(true);
12690b57cec5SDimitry Andric     handleFileExit(EndLoc);
12700b57cec5SDimitry Andric     popRegions(Index);
12710b57cec5SDimitry Andric   }
12720b57cec5SDimitry Andric 
1273a58f00eaSDimitry Andric   /// Find a valid range starting with \p StartingLoc and ending before \p
1274a58f00eaSDimitry Andric   /// BeforeLoc.
findAreaStartingFromTo__anonc2c3cfe60211::CounterCoverageMappingBuilder1275a58f00eaSDimitry Andric   std::optional<SourceRange> findAreaStartingFromTo(SourceLocation StartingLoc,
1276a58f00eaSDimitry Andric                                                     SourceLocation BeforeLoc) {
1277a58f00eaSDimitry Andric     // If StartingLoc is in function-like macro, use its start location.
1278a58f00eaSDimitry Andric     if (StartingLoc.isMacroID()) {
1279a58f00eaSDimitry Andric       FileID FID = SM.getFileID(StartingLoc);
1280a58f00eaSDimitry Andric       const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion();
1281a58f00eaSDimitry Andric       if (EI->isFunctionMacroExpansion())
1282a58f00eaSDimitry Andric         StartingLoc = EI->getExpansionLocStart();
1283a58f00eaSDimitry Andric     }
1284a58f00eaSDimitry Andric 
1285a58f00eaSDimitry Andric     size_t StartDepth = locationDepth(StartingLoc);
1286a58f00eaSDimitry Andric     size_t EndDepth = locationDepth(BeforeLoc);
1287a58f00eaSDimitry Andric     while (!SM.isWrittenInSameFile(StartingLoc, BeforeLoc)) {
1288a58f00eaSDimitry Andric       bool UnnestStart = StartDepth >= EndDepth;
1289a58f00eaSDimitry Andric       bool UnnestEnd = EndDepth >= StartDepth;
1290a58f00eaSDimitry Andric       if (UnnestEnd) {
1291a58f00eaSDimitry Andric         assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
1292a58f00eaSDimitry Andric                                       BeforeLoc));
1293a58f00eaSDimitry Andric 
1294a58f00eaSDimitry Andric         BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
1295a58f00eaSDimitry Andric         assert(BeforeLoc.isValid());
1296a58f00eaSDimitry Andric         EndDepth--;
1297a58f00eaSDimitry Andric       }
1298a58f00eaSDimitry Andric       if (UnnestStart) {
1299a58f00eaSDimitry Andric         assert(SM.isWrittenInSameFile(StartingLoc,
1300a58f00eaSDimitry Andric                                       getStartOfFileOrMacro(StartingLoc)));
1301a58f00eaSDimitry Andric 
1302a58f00eaSDimitry Andric         StartingLoc = getIncludeOrExpansionLoc(StartingLoc);
1303a58f00eaSDimitry Andric         assert(StartingLoc.isValid());
1304a58f00eaSDimitry Andric         StartDepth--;
1305a58f00eaSDimitry Andric       }
1306a58f00eaSDimitry Andric     }
1307a58f00eaSDimitry Andric     // If the start and end locations of the gap are both within the same macro
1308a58f00eaSDimitry Andric     // file, the range may not be in source order.
1309a58f00eaSDimitry Andric     if (StartingLoc.isMacroID() || BeforeLoc.isMacroID())
1310a58f00eaSDimitry Andric       return std::nullopt;
1311a58f00eaSDimitry Andric     if (!SM.isWrittenInSameFile(StartingLoc, BeforeLoc) ||
1312a58f00eaSDimitry Andric         !SpellingRegion(SM, StartingLoc, BeforeLoc).isInSourceOrder())
1313a58f00eaSDimitry Andric       return std::nullopt;
1314a58f00eaSDimitry Andric     return {{StartingLoc, BeforeLoc}};
1315a58f00eaSDimitry Andric   }
1316a58f00eaSDimitry Andric 
markSkipped__anonc2c3cfe60211::CounterCoverageMappingBuilder1317a58f00eaSDimitry Andric   void markSkipped(SourceLocation StartLoc, SourceLocation BeforeLoc) {
1318a58f00eaSDimitry Andric     const auto Skipped = findAreaStartingFromTo(StartLoc, BeforeLoc);
1319a58f00eaSDimitry Andric 
1320a58f00eaSDimitry Andric     if (!Skipped)
1321a58f00eaSDimitry Andric       return;
1322a58f00eaSDimitry Andric 
1323a58f00eaSDimitry Andric     const auto NewStartLoc = Skipped->getBegin();
1324a58f00eaSDimitry Andric     const auto EndLoc = Skipped->getEnd();
1325a58f00eaSDimitry Andric 
1326a58f00eaSDimitry Andric     if (NewStartLoc == EndLoc)
1327a58f00eaSDimitry Andric       return;
1328a58f00eaSDimitry Andric     assert(SpellingRegion(SM, NewStartLoc, EndLoc).isInSourceOrder());
1329a58f00eaSDimitry Andric     handleFileExit(NewStartLoc);
1330a58f00eaSDimitry Andric     size_t Index = pushRegion({}, NewStartLoc, EndLoc);
1331a58f00eaSDimitry Andric     getRegion().setSkipped(true);
1332a58f00eaSDimitry Andric     handleFileExit(EndLoc);
1333a58f00eaSDimitry Andric     popRegions(Index);
1334a58f00eaSDimitry Andric   }
1335a58f00eaSDimitry Andric 
13360b57cec5SDimitry Andric   /// Keep counts of breaks and continues inside loops.
13370b57cec5SDimitry Andric   struct BreakContinue {
13380b57cec5SDimitry Andric     Counter BreakCount;
13390b57cec5SDimitry Andric     Counter ContinueCount;
13400b57cec5SDimitry Andric   };
13410b57cec5SDimitry Andric   SmallVector<BreakContinue, 8> BreakContinueStack;
13420b57cec5SDimitry Andric 
CounterCoverageMappingBuilder__anonc2c3cfe60211::CounterCoverageMappingBuilder13430b57cec5SDimitry Andric   CounterCoverageMappingBuilder(
13440b57cec5SDimitry Andric       CoverageMappingModuleGen &CVM,
1345cdc20ff6SDimitry Andric       llvm::DenseMap<const Stmt *, unsigned> &CounterMap,
1346cdc20ff6SDimitry Andric       llvm::DenseMap<const Stmt *, unsigned> &MCDCBitmapMap,
1347cdc20ff6SDimitry Andric       llvm::DenseMap<const Stmt *, MCDCConditionID> &CondIDMap,
1348cdc20ff6SDimitry Andric       SourceManager &SM, const LangOptions &LangOpts)
1349cdc20ff6SDimitry Andric       : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
1350cdc20ff6SDimitry Andric         MCDCBitmapMap(MCDCBitmapMap),
1351cdc20ff6SDimitry Andric         MCDCBuilder(CVM.getCodeGenModule(), CondIDMap, MCDCBitmapMap) {}
13520b57cec5SDimitry Andric 
13530b57cec5SDimitry Andric   /// Write the mapping data to the output stream
write__anonc2c3cfe60211::CounterCoverageMappingBuilder13540b57cec5SDimitry Andric   void write(llvm::raw_ostream &OS) {
13550b57cec5SDimitry Andric     llvm::SmallVector<unsigned, 8> VirtualFileMapping;
13560b57cec5SDimitry Andric     gatherFileIDs(VirtualFileMapping);
13570b57cec5SDimitry Andric     SourceRegionFilter Filter = emitExpansionRegions();
13580b57cec5SDimitry Andric     emitSourceRegions(Filter);
13590b57cec5SDimitry Andric     gatherSkippedRegions();
13600b57cec5SDimitry Andric 
13610b57cec5SDimitry Andric     if (MappingRegions.empty())
13620b57cec5SDimitry Andric       return;
13630b57cec5SDimitry Andric 
13640b57cec5SDimitry Andric     CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
13650b57cec5SDimitry Andric                                  MappingRegions);
13660b57cec5SDimitry Andric     Writer.write(OS);
13670b57cec5SDimitry Andric   }
13680b57cec5SDimitry Andric 
VisitStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder13690b57cec5SDimitry Andric   void VisitStmt(const Stmt *S) {
13700b57cec5SDimitry Andric     if (S->getBeginLoc().isValid())
13710b57cec5SDimitry Andric       extendRegion(S);
1372fe6060f1SDimitry Andric     const Stmt *LastStmt = nullptr;
1373fe6060f1SDimitry Andric     bool SaveTerminateStmt = HasTerminateStmt;
1374fe6060f1SDimitry Andric     HasTerminateStmt = false;
1375fe6060f1SDimitry Andric     GapRegionCounter = Counter::getZero();
13760b57cec5SDimitry Andric     for (const Stmt *Child : S->children())
1377fe6060f1SDimitry Andric       if (Child) {
1378fe6060f1SDimitry Andric         // If last statement contains terminate statements, add a gap area
1379*fe72d8ecSDimitry Andric         // between the two statements.
1380*fe72d8ecSDimitry Andric         if (LastStmt && HasTerminateStmt) {
1381fe6060f1SDimitry Andric           auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
1382fe6060f1SDimitry Andric           if (Gap)
1383fe6060f1SDimitry Andric             fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
1384fe6060f1SDimitry Andric                                  GapRegionCounter);
1385fe6060f1SDimitry Andric           SaveTerminateStmt = true;
1386fe6060f1SDimitry Andric           HasTerminateStmt = false;
1387fe6060f1SDimitry Andric         }
13880b57cec5SDimitry Andric         this->Visit(Child);
1389fe6060f1SDimitry Andric         LastStmt = Child;
1390fe6060f1SDimitry Andric       }
1391fe6060f1SDimitry Andric     if (SaveTerminateStmt)
1392fe6060f1SDimitry Andric       HasTerminateStmt = true;
13930b57cec5SDimitry Andric     handleFileExit(getEnd(S));
13940b57cec5SDimitry Andric   }
13950b57cec5SDimitry Andric 
VisitDecl__anonc2c3cfe60211::CounterCoverageMappingBuilder13960b57cec5SDimitry Andric   void VisitDecl(const Decl *D) {
13970b57cec5SDimitry Andric     Stmt *Body = D->getBody();
13980b57cec5SDimitry Andric 
1399fe013be4SDimitry Andric     // Do not propagate region counts into system headers unless collecting
1400fe013be4SDimitry Andric     // coverage from system headers is explicitly enabled.
1401fe013be4SDimitry Andric     if (!SystemHeadersCoverage && Body &&
1402fe013be4SDimitry Andric         SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
14030b57cec5SDimitry Andric       return;
14040b57cec5SDimitry Andric 
14050b57cec5SDimitry Andric     // Do not visit the artificial children nodes of defaulted methods. The
14060b57cec5SDimitry Andric     // lexer may not be able to report back precise token end locations for
14070b57cec5SDimitry Andric     // these children nodes (llvm.org/PR39822), and moreover users will not be
14080b57cec5SDimitry Andric     // able to see coverage for them.
1409c9157d92SDimitry Andric     Counter BodyCounter = getRegionCounter(Body);
14100b57cec5SDimitry Andric     bool Defaulted = false;
14110b57cec5SDimitry Andric     if (auto *Method = dyn_cast<CXXMethodDecl>(D))
14120b57cec5SDimitry Andric       Defaulted = Method->isDefaulted();
1413c9157d92SDimitry Andric     if (auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
1414c9157d92SDimitry Andric       for (auto *Initializer : Ctor->inits()) {
1415c9157d92SDimitry Andric         if (Initializer->isWritten()) {
1416c9157d92SDimitry Andric           auto *Init = Initializer->getInit();
1417c9157d92SDimitry Andric           if (getStart(Init).isValid() && getEnd(Init).isValid())
1418c9157d92SDimitry Andric             propagateCounts(BodyCounter, Init);
1419c9157d92SDimitry Andric         }
1420c9157d92SDimitry Andric       }
1421c9157d92SDimitry Andric     }
14220b57cec5SDimitry Andric 
1423c9157d92SDimitry Andric     propagateCounts(BodyCounter, Body,
14240b57cec5SDimitry Andric                     /*VisitChildren=*/!Defaulted);
14250b57cec5SDimitry Andric     assert(RegionStack.empty() && "Regions entered but never exited");
14260b57cec5SDimitry Andric   }
14270b57cec5SDimitry Andric 
VisitReturnStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder14280b57cec5SDimitry Andric   void VisitReturnStmt(const ReturnStmt *S) {
14290b57cec5SDimitry Andric     extendRegion(S);
14300b57cec5SDimitry Andric     if (S->getRetValue())
14310b57cec5SDimitry Andric       Visit(S->getRetValue());
14320b57cec5SDimitry Andric     terminateRegion(S);
14330b57cec5SDimitry Andric   }
14340b57cec5SDimitry Andric 
VisitCoroutineBodyStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder14355ffd83dbSDimitry Andric   void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
14365ffd83dbSDimitry Andric     extendRegion(S);
14375ffd83dbSDimitry Andric     Visit(S->getBody());
14385ffd83dbSDimitry Andric   }
14395ffd83dbSDimitry Andric 
VisitCoreturnStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder14405ffd83dbSDimitry Andric   void VisitCoreturnStmt(const CoreturnStmt *S) {
14415ffd83dbSDimitry Andric     extendRegion(S);
14425ffd83dbSDimitry Andric     if (S->getOperand())
14435ffd83dbSDimitry Andric       Visit(S->getOperand());
14445ffd83dbSDimitry Andric     terminateRegion(S);
14455ffd83dbSDimitry Andric   }
14465ffd83dbSDimitry Andric 
VisitCXXThrowExpr__anonc2c3cfe60211::CounterCoverageMappingBuilder14470b57cec5SDimitry Andric   void VisitCXXThrowExpr(const CXXThrowExpr *E) {
14480b57cec5SDimitry Andric     extendRegion(E);
14490b57cec5SDimitry Andric     if (E->getSubExpr())
14500b57cec5SDimitry Andric       Visit(E->getSubExpr());
14510b57cec5SDimitry Andric     terminateRegion(E);
14520b57cec5SDimitry Andric   }
14530b57cec5SDimitry Andric 
VisitGotoStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder14540b57cec5SDimitry Andric   void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); }
14550b57cec5SDimitry Andric 
VisitLabelStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder14560b57cec5SDimitry Andric   void VisitLabelStmt(const LabelStmt *S) {
14570b57cec5SDimitry Andric     Counter LabelCount = getRegionCounter(S);
14580b57cec5SDimitry Andric     SourceLocation Start = getStart(S);
14590b57cec5SDimitry Andric     // We can't extendRegion here or we risk overlapping with our new region.
14600b57cec5SDimitry Andric     handleFileExit(Start);
14610b57cec5SDimitry Andric     pushRegion(LabelCount, Start);
14620b57cec5SDimitry Andric     Visit(S->getSubStmt());
14630b57cec5SDimitry Andric   }
14640b57cec5SDimitry Andric 
VisitBreakStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder14650b57cec5SDimitry Andric   void VisitBreakStmt(const BreakStmt *S) {
14660b57cec5SDimitry Andric     assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
14670b57cec5SDimitry Andric     BreakContinueStack.back().BreakCount = addCounters(
14680b57cec5SDimitry Andric         BreakContinueStack.back().BreakCount, getRegion().getCounter());
14690b57cec5SDimitry Andric     // FIXME: a break in a switch should terminate regions for all preceding
14700b57cec5SDimitry Andric     // case statements, not just the most recent one.
14710b57cec5SDimitry Andric     terminateRegion(S);
14720b57cec5SDimitry Andric   }
14730b57cec5SDimitry Andric 
VisitContinueStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder14740b57cec5SDimitry Andric   void VisitContinueStmt(const ContinueStmt *S) {
14750b57cec5SDimitry Andric     assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
14760b57cec5SDimitry Andric     BreakContinueStack.back().ContinueCount = addCounters(
14770b57cec5SDimitry Andric         BreakContinueStack.back().ContinueCount, getRegion().getCounter());
14780b57cec5SDimitry Andric     terminateRegion(S);
14790b57cec5SDimitry Andric   }
14800b57cec5SDimitry Andric 
VisitCallExpr__anonc2c3cfe60211::CounterCoverageMappingBuilder14810b57cec5SDimitry Andric   void VisitCallExpr(const CallExpr *E) {
14820b57cec5SDimitry Andric     VisitStmt(E);
14830b57cec5SDimitry Andric 
14840b57cec5SDimitry Andric     // Terminate the region when we hit a noreturn function.
14850b57cec5SDimitry Andric     // (This is helpful dealing with switch statements.)
14860b57cec5SDimitry Andric     QualType CalleeType = E->getCallee()->getType();
14870b57cec5SDimitry Andric     if (getFunctionExtInfo(*CalleeType).getNoReturn())
14880b57cec5SDimitry Andric       terminateRegion(E);
14890b57cec5SDimitry Andric   }
14900b57cec5SDimitry Andric 
VisitWhileStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder14910b57cec5SDimitry Andric   void VisitWhileStmt(const WhileStmt *S) {
14920b57cec5SDimitry Andric     extendRegion(S);
14930b57cec5SDimitry Andric 
14940b57cec5SDimitry Andric     Counter ParentCount = getRegion().getCounter();
14950b57cec5SDimitry Andric     Counter BodyCount = getRegionCounter(S);
14960b57cec5SDimitry Andric 
14970b57cec5SDimitry Andric     // Handle the body first so that we can get the backedge count.
14980b57cec5SDimitry Andric     BreakContinueStack.push_back(BreakContinue());
14990b57cec5SDimitry Andric     extendRegion(S->getBody());
15000b57cec5SDimitry Andric     Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
15010b57cec5SDimitry Andric     BreakContinue BC = BreakContinueStack.pop_back_val();
15020b57cec5SDimitry Andric 
1503fe6060f1SDimitry Andric     bool BodyHasTerminateStmt = HasTerminateStmt;
1504fe6060f1SDimitry Andric     HasTerminateStmt = false;
1505fe6060f1SDimitry Andric 
15060b57cec5SDimitry Andric     // Go back to handle the condition.
15070b57cec5SDimitry Andric     Counter CondCount =
15080b57cec5SDimitry Andric         addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
15090b57cec5SDimitry Andric     propagateCounts(CondCount, S->getCond());
15100b57cec5SDimitry Andric     adjustForOutOfOrderTraversal(getEnd(S));
15110b57cec5SDimitry Andric 
15120b57cec5SDimitry Andric     // The body count applies to the area immediately after the increment.
1513fe6060f1SDimitry Andric     auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
15140b57cec5SDimitry Andric     if (Gap)
15150b57cec5SDimitry Andric       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
15160b57cec5SDimitry Andric 
15170b57cec5SDimitry Andric     Counter OutCount =
15180b57cec5SDimitry Andric         addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1519fe6060f1SDimitry Andric     if (OutCount != ParentCount) {
15200b57cec5SDimitry Andric       pushRegion(OutCount);
1521fe6060f1SDimitry Andric       GapRegionCounter = OutCount;
1522fe6060f1SDimitry Andric       if (BodyHasTerminateStmt)
1523fe6060f1SDimitry Andric         HasTerminateStmt = true;
1524fe6060f1SDimitry Andric     }
1525e8d8bef9SDimitry Andric 
1526e8d8bef9SDimitry Andric     // Create Branch Region around condition.
1527e8d8bef9SDimitry Andric     createBranchRegion(S->getCond(), BodyCount,
1528e8d8bef9SDimitry Andric                        subtractCounters(CondCount, BodyCount));
15290b57cec5SDimitry Andric   }
15300b57cec5SDimitry Andric 
VisitDoStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder15310b57cec5SDimitry Andric   void VisitDoStmt(const DoStmt *S) {
15320b57cec5SDimitry Andric     extendRegion(S);
15330b57cec5SDimitry Andric 
15340b57cec5SDimitry Andric     Counter ParentCount = getRegion().getCounter();
15350b57cec5SDimitry Andric     Counter BodyCount = getRegionCounter(S);
15360b57cec5SDimitry Andric 
15370b57cec5SDimitry Andric     BreakContinueStack.push_back(BreakContinue());
15380b57cec5SDimitry Andric     extendRegion(S->getBody());
15390b57cec5SDimitry Andric     Counter BackedgeCount =
15400b57cec5SDimitry Andric         propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
15410b57cec5SDimitry Andric     BreakContinue BC = BreakContinueStack.pop_back_val();
15420b57cec5SDimitry Andric 
1543fe6060f1SDimitry Andric     bool BodyHasTerminateStmt = HasTerminateStmt;
1544fe6060f1SDimitry Andric     HasTerminateStmt = false;
1545fe6060f1SDimitry Andric 
15460b57cec5SDimitry Andric     Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
15470b57cec5SDimitry Andric     propagateCounts(CondCount, S->getCond());
15480b57cec5SDimitry Andric 
15490b57cec5SDimitry Andric     Counter OutCount =
15500b57cec5SDimitry Andric         addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1551fe6060f1SDimitry Andric     if (OutCount != ParentCount) {
15520b57cec5SDimitry Andric       pushRegion(OutCount);
1553fe6060f1SDimitry Andric       GapRegionCounter = OutCount;
1554fe6060f1SDimitry Andric     }
1555e8d8bef9SDimitry Andric 
1556e8d8bef9SDimitry Andric     // Create Branch Region around condition.
1557e8d8bef9SDimitry Andric     createBranchRegion(S->getCond(), BodyCount,
1558e8d8bef9SDimitry Andric                        subtractCounters(CondCount, BodyCount));
1559fe6060f1SDimitry Andric 
1560fe6060f1SDimitry Andric     if (BodyHasTerminateStmt)
1561fe6060f1SDimitry Andric       HasTerminateStmt = true;
15620b57cec5SDimitry Andric   }
15630b57cec5SDimitry Andric 
VisitForStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder15640b57cec5SDimitry Andric   void VisitForStmt(const ForStmt *S) {
15650b57cec5SDimitry Andric     extendRegion(S);
15660b57cec5SDimitry Andric     if (S->getInit())
15670b57cec5SDimitry Andric       Visit(S->getInit());
15680b57cec5SDimitry Andric 
15690b57cec5SDimitry Andric     Counter ParentCount = getRegion().getCounter();
15700b57cec5SDimitry Andric     Counter BodyCount = getRegionCounter(S);
15710b57cec5SDimitry Andric 
15720b57cec5SDimitry Andric     // The loop increment may contain a break or continue.
15730b57cec5SDimitry Andric     if (S->getInc())
15740b57cec5SDimitry Andric       BreakContinueStack.emplace_back();
15750b57cec5SDimitry Andric 
15760b57cec5SDimitry Andric     // Handle the body first so that we can get the backedge count.
15770b57cec5SDimitry Andric     BreakContinueStack.emplace_back();
15780b57cec5SDimitry Andric     extendRegion(S->getBody());
15790b57cec5SDimitry Andric     Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
15800b57cec5SDimitry Andric     BreakContinue BodyBC = BreakContinueStack.pop_back_val();
15810b57cec5SDimitry Andric 
1582fe6060f1SDimitry Andric     bool BodyHasTerminateStmt = HasTerminateStmt;
1583fe6060f1SDimitry Andric     HasTerminateStmt = false;
1584fe6060f1SDimitry Andric 
15850b57cec5SDimitry Andric     // The increment is essentially part of the body but it needs to include
15860b57cec5SDimitry Andric     // the count for all the continue statements.
15870b57cec5SDimitry Andric     BreakContinue IncrementBC;
15880b57cec5SDimitry Andric     if (const Stmt *Inc = S->getInc()) {
15890b57cec5SDimitry Andric       propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
15900b57cec5SDimitry Andric       IncrementBC = BreakContinueStack.pop_back_val();
15910b57cec5SDimitry Andric     }
15920b57cec5SDimitry Andric 
15930b57cec5SDimitry Andric     // Go back to handle the condition.
15940b57cec5SDimitry Andric     Counter CondCount = addCounters(
15950b57cec5SDimitry Andric         addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
15960b57cec5SDimitry Andric         IncrementBC.ContinueCount);
15970b57cec5SDimitry Andric     if (const Expr *Cond = S->getCond()) {
15980b57cec5SDimitry Andric       propagateCounts(CondCount, Cond);
15990b57cec5SDimitry Andric       adjustForOutOfOrderTraversal(getEnd(S));
16000b57cec5SDimitry Andric     }
16010b57cec5SDimitry Andric 
16020b57cec5SDimitry Andric     // The body count applies to the area immediately after the increment.
1603fe6060f1SDimitry Andric     auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
16040b57cec5SDimitry Andric     if (Gap)
16050b57cec5SDimitry Andric       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
16060b57cec5SDimitry Andric 
16070b57cec5SDimitry Andric     Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
16080b57cec5SDimitry Andric                                    subtractCounters(CondCount, BodyCount));
1609fe6060f1SDimitry Andric     if (OutCount != ParentCount) {
16100b57cec5SDimitry Andric       pushRegion(OutCount);
1611fe6060f1SDimitry Andric       GapRegionCounter = OutCount;
1612fe6060f1SDimitry Andric       if (BodyHasTerminateStmt)
1613fe6060f1SDimitry Andric         HasTerminateStmt = true;
1614fe6060f1SDimitry Andric     }
1615e8d8bef9SDimitry Andric 
1616e8d8bef9SDimitry Andric     // Create Branch Region around condition.
1617e8d8bef9SDimitry Andric     createBranchRegion(S->getCond(), BodyCount,
1618e8d8bef9SDimitry Andric                        subtractCounters(CondCount, BodyCount));
16190b57cec5SDimitry Andric   }
16200b57cec5SDimitry Andric 
VisitCXXForRangeStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder16210b57cec5SDimitry Andric   void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
16220b57cec5SDimitry Andric     extendRegion(S);
16230b57cec5SDimitry Andric     if (S->getInit())
16240b57cec5SDimitry Andric       Visit(S->getInit());
16250b57cec5SDimitry Andric     Visit(S->getLoopVarStmt());
16260b57cec5SDimitry Andric     Visit(S->getRangeStmt());
16270b57cec5SDimitry Andric 
16280b57cec5SDimitry Andric     Counter ParentCount = getRegion().getCounter();
16290b57cec5SDimitry Andric     Counter BodyCount = getRegionCounter(S);
16300b57cec5SDimitry Andric 
16310b57cec5SDimitry Andric     BreakContinueStack.push_back(BreakContinue());
16320b57cec5SDimitry Andric     extendRegion(S->getBody());
16330b57cec5SDimitry Andric     Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
16340b57cec5SDimitry Andric     BreakContinue BC = BreakContinueStack.pop_back_val();
16350b57cec5SDimitry Andric 
1636fe6060f1SDimitry Andric     bool BodyHasTerminateStmt = HasTerminateStmt;
1637fe6060f1SDimitry Andric     HasTerminateStmt = false;
1638fe6060f1SDimitry Andric 
16390b57cec5SDimitry Andric     // The body count applies to the area immediately after the range.
1640fe6060f1SDimitry Andric     auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
16410b57cec5SDimitry Andric     if (Gap)
16420b57cec5SDimitry Andric       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
16430b57cec5SDimitry Andric 
16440b57cec5SDimitry Andric     Counter LoopCount =
16450b57cec5SDimitry Andric         addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
16460b57cec5SDimitry Andric     Counter OutCount =
16470b57cec5SDimitry Andric         addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1648fe6060f1SDimitry Andric     if (OutCount != ParentCount) {
16490b57cec5SDimitry Andric       pushRegion(OutCount);
1650fe6060f1SDimitry Andric       GapRegionCounter = OutCount;
1651fe6060f1SDimitry Andric       if (BodyHasTerminateStmt)
1652fe6060f1SDimitry Andric         HasTerminateStmt = true;
1653fe6060f1SDimitry Andric     }
1654e8d8bef9SDimitry Andric 
1655e8d8bef9SDimitry Andric     // Create Branch Region around condition.
1656e8d8bef9SDimitry Andric     createBranchRegion(S->getCond(), BodyCount,
1657e8d8bef9SDimitry Andric                        subtractCounters(LoopCount, BodyCount));
16580b57cec5SDimitry Andric   }
16590b57cec5SDimitry Andric 
VisitObjCForCollectionStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder16600b57cec5SDimitry Andric   void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
16610b57cec5SDimitry Andric     extendRegion(S);
16620b57cec5SDimitry Andric     Visit(S->getElement());
16630b57cec5SDimitry Andric 
16640b57cec5SDimitry Andric     Counter ParentCount = getRegion().getCounter();
16650b57cec5SDimitry Andric     Counter BodyCount = getRegionCounter(S);
16660b57cec5SDimitry Andric 
16670b57cec5SDimitry Andric     BreakContinueStack.push_back(BreakContinue());
16680b57cec5SDimitry Andric     extendRegion(S->getBody());
16690b57cec5SDimitry Andric     Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
16700b57cec5SDimitry Andric     BreakContinue BC = BreakContinueStack.pop_back_val();
16710b57cec5SDimitry Andric 
16720b57cec5SDimitry Andric     // The body count applies to the area immediately after the collection.
1673fe6060f1SDimitry Andric     auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
16740b57cec5SDimitry Andric     if (Gap)
16750b57cec5SDimitry Andric       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
16760b57cec5SDimitry Andric 
16770b57cec5SDimitry Andric     Counter LoopCount =
16780b57cec5SDimitry Andric         addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
16790b57cec5SDimitry Andric     Counter OutCount =
16800b57cec5SDimitry Andric         addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1681fe6060f1SDimitry Andric     if (OutCount != ParentCount) {
16820b57cec5SDimitry Andric       pushRegion(OutCount);
1683fe6060f1SDimitry Andric       GapRegionCounter = OutCount;
1684fe6060f1SDimitry Andric     }
16850b57cec5SDimitry Andric   }
16860b57cec5SDimitry Andric 
VisitSwitchStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder16870b57cec5SDimitry Andric   void VisitSwitchStmt(const SwitchStmt *S) {
16880b57cec5SDimitry Andric     extendRegion(S);
16890b57cec5SDimitry Andric     if (S->getInit())
16900b57cec5SDimitry Andric       Visit(S->getInit());
16910b57cec5SDimitry Andric     Visit(S->getCond());
16920b57cec5SDimitry Andric 
16930b57cec5SDimitry Andric     BreakContinueStack.push_back(BreakContinue());
16940b57cec5SDimitry Andric 
16950b57cec5SDimitry Andric     const Stmt *Body = S->getBody();
16960b57cec5SDimitry Andric     extendRegion(Body);
16970b57cec5SDimitry Andric     if (const auto *CS = dyn_cast<CompoundStmt>(Body)) {
16980b57cec5SDimitry Andric       if (!CS->body_empty()) {
16990b57cec5SDimitry Andric         // Make a region for the body of the switch.  If the body starts with
17000b57cec5SDimitry Andric         // a case, that case will reuse this region; otherwise, this covers
17010b57cec5SDimitry Andric         // the unreachable code at the beginning of the switch body.
1702480093f4SDimitry Andric         size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1703480093f4SDimitry Andric         getRegion().setGap(true);
1704fe6060f1SDimitry Andric         Visit(Body);
17050b57cec5SDimitry Andric 
17060b57cec5SDimitry Andric         // Set the end for the body of the switch, if it isn't already set.
17070b57cec5SDimitry Andric         for (size_t i = RegionStack.size(); i != Index; --i) {
17080b57cec5SDimitry Andric           if (!RegionStack[i - 1].hasEndLoc())
17090b57cec5SDimitry Andric             RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
17100b57cec5SDimitry Andric         }
17110b57cec5SDimitry Andric 
17120b57cec5SDimitry Andric         popRegions(Index);
17130b57cec5SDimitry Andric       }
17140b57cec5SDimitry Andric     } else
17150b57cec5SDimitry Andric       propagateCounts(Counter::getZero(), Body);
17160b57cec5SDimitry Andric     BreakContinue BC = BreakContinueStack.pop_back_val();
17170b57cec5SDimitry Andric 
17180b57cec5SDimitry Andric     if (!BreakContinueStack.empty())
17190b57cec5SDimitry Andric       BreakContinueStack.back().ContinueCount = addCounters(
17200b57cec5SDimitry Andric           BreakContinueStack.back().ContinueCount, BC.ContinueCount);
17210b57cec5SDimitry Andric 
1722e8d8bef9SDimitry Andric     Counter ParentCount = getRegion().getCounter();
17230b57cec5SDimitry Andric     Counter ExitCount = getRegionCounter(S);
17240b57cec5SDimitry Andric     SourceLocation ExitLoc = getEnd(S);
17250b57cec5SDimitry Andric     pushRegion(ExitCount);
1726fe6060f1SDimitry Andric     GapRegionCounter = ExitCount;
17270b57cec5SDimitry Andric 
17280b57cec5SDimitry Andric     // Ensure that handleFileExit recognizes when the end location is located
17290b57cec5SDimitry Andric     // in a different file.
17300b57cec5SDimitry Andric     MostRecentLocation = getStart(S);
17310b57cec5SDimitry Andric     handleFileExit(ExitLoc);
1732e8d8bef9SDimitry Andric 
1733e8d8bef9SDimitry Andric     // Create a Branch Region around each Case. Subtract the case's
1734e8d8bef9SDimitry Andric     // counter from the Parent counter to track the "False" branch count.
1735e8d8bef9SDimitry Andric     Counter CaseCountSum;
1736e8d8bef9SDimitry Andric     bool HasDefaultCase = false;
1737e8d8bef9SDimitry Andric     const SwitchCase *Case = S->getSwitchCaseList();
1738e8d8bef9SDimitry Andric     for (; Case; Case = Case->getNextSwitchCase()) {
1739e8d8bef9SDimitry Andric       HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case);
174081ad6265SDimitry Andric       CaseCountSum =
174181ad6265SDimitry Andric           addCounters(CaseCountSum, getRegionCounter(Case), /*Simplify=*/false);
1742e8d8bef9SDimitry Andric       createSwitchCaseRegion(
1743e8d8bef9SDimitry Andric           Case, getRegionCounter(Case),
1744e8d8bef9SDimitry Andric           subtractCounters(ParentCount, getRegionCounter(Case)));
1745e8d8bef9SDimitry Andric     }
174681ad6265SDimitry Andric     // Simplify is skipped while building the counters above: it can get really
174781ad6265SDimitry Andric     // slow on top of switches with thousands of cases. Instead, trigger
174881ad6265SDimitry Andric     // simplification by adding zero to the last counter.
174981ad6265SDimitry Andric     CaseCountSum = addCounters(CaseCountSum, Counter::getZero());
1750e8d8bef9SDimitry Andric 
1751e8d8bef9SDimitry Andric     // If no explicit default case exists, create a branch region to represent
1752e8d8bef9SDimitry Andric     // the hidden branch, which will be added later by the CodeGen. This region
1753e8d8bef9SDimitry Andric     // will be associated with the switch statement's condition.
1754e8d8bef9SDimitry Andric     if (!HasDefaultCase) {
1755e8d8bef9SDimitry Andric       Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum);
1756e8d8bef9SDimitry Andric       Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue);
1757e8d8bef9SDimitry Andric       createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse);
1758e8d8bef9SDimitry Andric     }
17590b57cec5SDimitry Andric   }
17600b57cec5SDimitry Andric 
VisitSwitchCase__anonc2c3cfe60211::CounterCoverageMappingBuilder17610b57cec5SDimitry Andric   void VisitSwitchCase(const SwitchCase *S) {
17620b57cec5SDimitry Andric     extendRegion(S);
17630b57cec5SDimitry Andric 
17640b57cec5SDimitry Andric     SourceMappingRegion &Parent = getRegion();
17650b57cec5SDimitry Andric 
17660b57cec5SDimitry Andric     Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
17670b57cec5SDimitry Andric     // Reuse the existing region if it starts at our label. This is typical of
17680b57cec5SDimitry Andric     // the first case in a switch.
17690b57cec5SDimitry Andric     if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
17700b57cec5SDimitry Andric       Parent.setCounter(Count);
17710b57cec5SDimitry Andric     else
17720b57cec5SDimitry Andric       pushRegion(Count, getStart(S));
17730b57cec5SDimitry Andric 
1774fe6060f1SDimitry Andric     GapRegionCounter = Count;
1775fe6060f1SDimitry Andric 
17760b57cec5SDimitry Andric     if (const auto *CS = dyn_cast<CaseStmt>(S)) {
17770b57cec5SDimitry Andric       Visit(CS->getLHS());
17780b57cec5SDimitry Andric       if (const Expr *RHS = CS->getRHS())
17790b57cec5SDimitry Andric         Visit(RHS);
17800b57cec5SDimitry Andric     }
17810b57cec5SDimitry Andric     Visit(S->getSubStmt());
17820b57cec5SDimitry Andric   }
17830b57cec5SDimitry Andric 
coverIfConsteval__anonc2c3cfe60211::CounterCoverageMappingBuilder1784a58f00eaSDimitry Andric   void coverIfConsteval(const IfStmt *S) {
1785a58f00eaSDimitry Andric     assert(S->isConsteval());
1786a58f00eaSDimitry Andric 
1787a58f00eaSDimitry Andric     const auto *Then = S->getThen();
1788a58f00eaSDimitry Andric     const auto *Else = S->getElse();
1789a58f00eaSDimitry Andric 
1790a58f00eaSDimitry Andric     // It's better for llvm-cov to create a new region with same counter
1791a58f00eaSDimitry Andric     // so line-coverage can be properly calculated for lines containing
1792a58f00eaSDimitry Andric     // a skipped region (without it the line is marked uncovered)
1793a58f00eaSDimitry Andric     const Counter ParentCount = getRegion().getCounter();
1794a58f00eaSDimitry Andric 
1795a58f00eaSDimitry Andric     extendRegion(S);
1796a58f00eaSDimitry Andric 
1797a58f00eaSDimitry Andric     if (S->isNegatedConsteval()) {
1798a58f00eaSDimitry Andric       // ignore 'if consteval'
1799a58f00eaSDimitry Andric       markSkipped(S->getIfLoc(), getStart(Then));
1800a58f00eaSDimitry Andric       propagateCounts(ParentCount, Then);
1801a58f00eaSDimitry Andric 
1802a58f00eaSDimitry Andric       if (Else) {
1803a58f00eaSDimitry Andric         // ignore 'else <else>'
1804a58f00eaSDimitry Andric         markSkipped(getEnd(Then), getEnd(Else));
1805a58f00eaSDimitry Andric       }
1806a58f00eaSDimitry Andric     } else {
1807a58f00eaSDimitry Andric       assert(S->isNonNegatedConsteval());
1808a58f00eaSDimitry Andric       // ignore 'if consteval <then> [else]'
1809a58f00eaSDimitry Andric       markSkipped(S->getIfLoc(), Else ? getStart(Else) : getEnd(Then));
1810a58f00eaSDimitry Andric 
1811a58f00eaSDimitry Andric       if (Else)
1812a58f00eaSDimitry Andric         propagateCounts(ParentCount, Else);
1813a58f00eaSDimitry Andric     }
1814a58f00eaSDimitry Andric   }
1815a58f00eaSDimitry Andric 
coverIfConstexpr__anonc2c3cfe60211::CounterCoverageMappingBuilder1816a58f00eaSDimitry Andric   void coverIfConstexpr(const IfStmt *S) {
1817a58f00eaSDimitry Andric     assert(S->isConstexpr());
1818a58f00eaSDimitry Andric 
1819a58f00eaSDimitry Andric     // evaluate constant condition...
1820b9d9368bSDimitry Andric     const bool isTrue =
1821b9d9368bSDimitry Andric         S->getCond()
1822b9d9368bSDimitry Andric             ->EvaluateKnownConstInt(CVM.getCodeGenModule().getContext())
1823b9d9368bSDimitry Andric             .getBoolValue();
1824a58f00eaSDimitry Andric 
1825a58f00eaSDimitry Andric     extendRegion(S);
1826a58f00eaSDimitry Andric 
1827a58f00eaSDimitry Andric     // I'm using 'propagateCounts' later as new region is better and allows me
1828a58f00eaSDimitry Andric     // to properly calculate line coverage in llvm-cov utility
1829a58f00eaSDimitry Andric     const Counter ParentCount = getRegion().getCounter();
1830a58f00eaSDimitry Andric 
1831a58f00eaSDimitry Andric     // ignore 'if constexpr ('
1832a58f00eaSDimitry Andric     SourceLocation startOfSkipped = S->getIfLoc();
1833a58f00eaSDimitry Andric 
1834a58f00eaSDimitry Andric     if (const auto *Init = S->getInit()) {
1835a58f00eaSDimitry Andric       const auto start = getStart(Init);
1836a58f00eaSDimitry Andric       const auto end = getEnd(Init);
1837a58f00eaSDimitry Andric 
1838a58f00eaSDimitry Andric       // this check is to make sure typedef here which doesn't have valid source
1839a58f00eaSDimitry Andric       // location won't crash it
1840a58f00eaSDimitry Andric       if (start.isValid() && end.isValid()) {
1841a58f00eaSDimitry Andric         markSkipped(startOfSkipped, start);
1842a58f00eaSDimitry Andric         propagateCounts(ParentCount, Init);
1843a58f00eaSDimitry Andric         startOfSkipped = getEnd(Init);
1844a58f00eaSDimitry Andric       }
1845a58f00eaSDimitry Andric     }
1846a58f00eaSDimitry Andric 
1847a58f00eaSDimitry Andric     const auto *Then = S->getThen();
1848a58f00eaSDimitry Andric     const auto *Else = S->getElse();
1849a58f00eaSDimitry Andric 
1850a58f00eaSDimitry Andric     if (isTrue) {
1851a58f00eaSDimitry Andric       // ignore '<condition>)'
1852a58f00eaSDimitry Andric       markSkipped(startOfSkipped, getStart(Then));
1853a58f00eaSDimitry Andric       propagateCounts(ParentCount, Then);
1854a58f00eaSDimitry Andric 
1855a58f00eaSDimitry Andric       if (Else)
1856a58f00eaSDimitry Andric         // ignore 'else <else>'
1857a58f00eaSDimitry Andric         markSkipped(getEnd(Then), getEnd(Else));
1858a58f00eaSDimitry Andric     } else {
1859a58f00eaSDimitry Andric       // ignore '<condition>) <then> [else]'
1860a58f00eaSDimitry Andric       markSkipped(startOfSkipped, Else ? getStart(Else) : getEnd(Then));
1861a58f00eaSDimitry Andric 
1862a58f00eaSDimitry Andric       if (Else)
1863a58f00eaSDimitry Andric         propagateCounts(ParentCount, Else);
1864a58f00eaSDimitry Andric     }
1865a58f00eaSDimitry Andric   }
1866a58f00eaSDimitry Andric 
VisitIfStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder18670b57cec5SDimitry Andric   void VisitIfStmt(const IfStmt *S) {
1868a58f00eaSDimitry Andric     // "if constexpr" and "if consteval" are not normal conditional statements,
1869a58f00eaSDimitry Andric     // their discarded statement should be skipped
1870a58f00eaSDimitry Andric     if (S->isConsteval())
1871a58f00eaSDimitry Andric       return coverIfConsteval(S);
1872a58f00eaSDimitry Andric     else if (S->isConstexpr())
1873a58f00eaSDimitry Andric       return coverIfConstexpr(S);
1874a58f00eaSDimitry Andric 
18750b57cec5SDimitry Andric     extendRegion(S);
18760b57cec5SDimitry Andric     if (S->getInit())
18770b57cec5SDimitry Andric       Visit(S->getInit());
18780b57cec5SDimitry Andric 
18790b57cec5SDimitry Andric     // Extend into the condition before we propagate through it below - this is
18800b57cec5SDimitry Andric     // needed to handle macros that generate the "if" but not the condition.
18810b57cec5SDimitry Andric     extendRegion(S->getCond());
18820b57cec5SDimitry Andric 
18830b57cec5SDimitry Andric     Counter ParentCount = getRegion().getCounter();
1884a58f00eaSDimitry Andric     Counter ThenCount = getRegionCounter(S);
18856c20abcdSDimitry Andric 
18860b57cec5SDimitry Andric     // Emitting a counter for the condition makes it easier to interpret the
18870b57cec5SDimitry Andric     // counter for the body when looking at the coverage.
18880b57cec5SDimitry Andric     propagateCounts(ParentCount, S->getCond());
18890b57cec5SDimitry Andric 
18900b57cec5SDimitry Andric     // The 'then' count applies to the area immediately after the condition.
1891bdd1243dSDimitry Andric     std::optional<SourceRange> Gap =
18926246ae0bSDimitry Andric         findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
18930b57cec5SDimitry Andric     if (Gap)
18940b57cec5SDimitry Andric       fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
18950b57cec5SDimitry Andric 
18960b57cec5SDimitry Andric     extendRegion(S->getThen());
18970b57cec5SDimitry Andric     Counter OutCount = propagateCounts(ThenCount, S->getThen());
1898a58f00eaSDimitry Andric     Counter ElseCount = subtractCounters(ParentCount, ThenCount);
18996c20abcdSDimitry Andric 
19000b57cec5SDimitry Andric     if (const Stmt *Else = S->getElse()) {
1901fe6060f1SDimitry Andric       bool ThenHasTerminateStmt = HasTerminateStmt;
1902fe6060f1SDimitry Andric       HasTerminateStmt = false;
19030b57cec5SDimitry Andric       // The 'else' count applies to the area immediately after the 'then'.
1904bdd1243dSDimitry Andric       std::optional<SourceRange> Gap =
19056246ae0bSDimitry Andric           findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
19060b57cec5SDimitry Andric       if (Gap)
19070b57cec5SDimitry Andric         fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
19080b57cec5SDimitry Andric       extendRegion(Else);
19090b57cec5SDimitry Andric       OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
1910fe6060f1SDimitry Andric 
1911fe6060f1SDimitry Andric       if (ThenHasTerminateStmt)
1912fe6060f1SDimitry Andric         HasTerminateStmt = true;
19130b57cec5SDimitry Andric     } else
19140b57cec5SDimitry Andric       OutCount = addCounters(OutCount, ElseCount);
19150b57cec5SDimitry Andric 
1916fe6060f1SDimitry Andric     if (OutCount != ParentCount) {
19170b57cec5SDimitry Andric       pushRegion(OutCount);
1918fe6060f1SDimitry Andric       GapRegionCounter = OutCount;
1919fe6060f1SDimitry Andric     }
1920e8d8bef9SDimitry Andric 
1921e8d8bef9SDimitry Andric     // Create Branch Region around condition.
1922e8d8bef9SDimitry Andric     createBranchRegion(S->getCond(), ThenCount,
1923e8d8bef9SDimitry Andric                        subtractCounters(ParentCount, ThenCount));
19240b57cec5SDimitry Andric   }
19250b57cec5SDimitry Andric 
VisitCXXTryStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder19260b57cec5SDimitry Andric   void VisitCXXTryStmt(const CXXTryStmt *S) {
19270b57cec5SDimitry Andric     extendRegion(S);
19280b57cec5SDimitry Andric     // Handle macros that generate the "try" but not the rest.
19290b57cec5SDimitry Andric     extendRegion(S->getTryBlock());
19300b57cec5SDimitry Andric 
19310b57cec5SDimitry Andric     Counter ParentCount = getRegion().getCounter();
19320b57cec5SDimitry Andric     propagateCounts(ParentCount, S->getTryBlock());
19330b57cec5SDimitry Andric 
19340b57cec5SDimitry Andric     for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
19350b57cec5SDimitry Andric       Visit(S->getHandler(I));
19360b57cec5SDimitry Andric 
19370b57cec5SDimitry Andric     Counter ExitCount = getRegionCounter(S);
19380b57cec5SDimitry Andric     pushRegion(ExitCount);
19390b57cec5SDimitry Andric   }
19400b57cec5SDimitry Andric 
VisitCXXCatchStmt__anonc2c3cfe60211::CounterCoverageMappingBuilder19410b57cec5SDimitry Andric   void VisitCXXCatchStmt(const CXXCatchStmt *S) {
19420b57cec5SDimitry Andric     propagateCounts(getRegionCounter(S), S->getHandlerBlock());
19430b57cec5SDimitry Andric   }
19440b57cec5SDimitry Andric 
VisitAbstractConditionalOperator__anonc2c3cfe60211::CounterCoverageMappingBuilder19450b57cec5SDimitry Andric   void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
19460b57cec5SDimitry Andric     extendRegion(E);
19470b57cec5SDimitry Andric 
19480b57cec5SDimitry Andric     Counter ParentCount = getRegion().getCounter();
19490b57cec5SDimitry Andric     Counter TrueCount = getRegionCounter(E);
19500b57cec5SDimitry Andric 
1951fe6060f1SDimitry Andric     propagateCounts(ParentCount, E->getCond());
1952fe013be4SDimitry Andric     Counter OutCount;
19530b57cec5SDimitry Andric 
19540b57cec5SDimitry Andric     if (!isa<BinaryConditionalOperator>(E)) {
19550b57cec5SDimitry Andric       // The 'then' count applies to the area immediately after the condition.
19560b57cec5SDimitry Andric       auto Gap =
19570b57cec5SDimitry Andric           findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr()));
19580b57cec5SDimitry Andric       if (Gap)
19590b57cec5SDimitry Andric         fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
19600b57cec5SDimitry Andric 
19610b57cec5SDimitry Andric       extendRegion(E->getTrueExpr());
1962fe013be4SDimitry Andric       OutCount = propagateCounts(TrueCount, E->getTrueExpr());
19630b57cec5SDimitry Andric     }
19640b57cec5SDimitry Andric 
19650b57cec5SDimitry Andric     extendRegion(E->getFalseExpr());
1966fe013be4SDimitry Andric     OutCount = addCounters(
1967fe013be4SDimitry Andric         OutCount, propagateCounts(subtractCounters(ParentCount, TrueCount),
1968fe013be4SDimitry Andric                                   E->getFalseExpr()));
1969fe013be4SDimitry Andric 
1970fe013be4SDimitry Andric     if (OutCount != ParentCount) {
1971fe013be4SDimitry Andric       pushRegion(OutCount);
1972fe013be4SDimitry Andric       GapRegionCounter = OutCount;
1973fe013be4SDimitry Andric     }
1974e8d8bef9SDimitry Andric 
1975e8d8bef9SDimitry Andric     // Create Branch Region around condition.
1976e8d8bef9SDimitry Andric     createBranchRegion(E->getCond(), TrueCount,
1977e8d8bef9SDimitry Andric                        subtractCounters(ParentCount, TrueCount));
19780b57cec5SDimitry Andric   }
19790b57cec5SDimitry Andric 
VisitBinLAnd__anonc2c3cfe60211::CounterCoverageMappingBuilder19800b57cec5SDimitry Andric   void VisitBinLAnd(const BinaryOperator *E) {
1981a58f00eaSDimitry Andric     bool IsRootNode = MCDCBuilder.isIdle();
1982a58f00eaSDimitry Andric 
1983a58f00eaSDimitry Andric     // Keep track of Binary Operator and assign MCDC condition IDs.
1984cdc20ff6SDimitry Andric     MCDCBuilder.pushAndAssignIDs(E);
1985cdc20ff6SDimitry Andric 
19860b57cec5SDimitry Andric     extendRegion(E->getLHS());
19870b57cec5SDimitry Andric     propagateCounts(getRegion().getCounter(), E->getLHS());
19880b57cec5SDimitry Andric     handleFileExit(getEnd(E->getLHS()));
19890b57cec5SDimitry Andric 
1990a58f00eaSDimitry Andric     // Track LHS True/False Decision.
1991a58f00eaSDimitry Andric     const auto DecisionLHS = MCDCBuilder.pop();
1992a58f00eaSDimitry Andric 
1993e8d8bef9SDimitry Andric     // Counter tracks the right hand side of a logical and operator.
19940b57cec5SDimitry Andric     extendRegion(E->getRHS());
19950b57cec5SDimitry Andric     propagateCounts(getRegionCounter(E), E->getRHS());
1996e8d8bef9SDimitry Andric 
1997a58f00eaSDimitry Andric     // Track RHS True/False Decision.
1998a58f00eaSDimitry Andric     const auto DecisionRHS = MCDCBuilder.back();
1999a58f00eaSDimitry Andric 
2000a58f00eaSDimitry Andric     // Create MCDC Decision Region if at top-level (root).
2001cdc20ff6SDimitry Andric     unsigned NumConds = 0;
2002a58f00eaSDimitry Andric     if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E)))
2003cdc20ff6SDimitry Andric       createDecisionRegion(E, getRegionBitmap(E), NumConds);
2004cdc20ff6SDimitry Andric 
2005e8d8bef9SDimitry Andric     // Extract the RHS's Execution Counter.
2006e8d8bef9SDimitry Andric     Counter RHSExecCnt = getRegionCounter(E);
2007e8d8bef9SDimitry Andric 
2008e8d8bef9SDimitry Andric     // Extract the RHS's "True" Instance Counter.
2009e8d8bef9SDimitry Andric     Counter RHSTrueCnt = getRegionCounter(E->getRHS());
2010e8d8bef9SDimitry Andric 
2011e8d8bef9SDimitry Andric     // Extract the Parent Region Counter.
2012e8d8bef9SDimitry Andric     Counter ParentCnt = getRegion().getCounter();
2013e8d8bef9SDimitry Andric 
2014e8d8bef9SDimitry Andric     // Create Branch Region around LHS condition.
2015e8d8bef9SDimitry Andric     createBranchRegion(E->getLHS(), RHSExecCnt,
2016a58f00eaSDimitry Andric                        subtractCounters(ParentCnt, RHSExecCnt), DecisionLHS);
2017e8d8bef9SDimitry Andric 
2018e8d8bef9SDimitry Andric     // Create Branch Region around RHS condition.
2019e8d8bef9SDimitry Andric     createBranchRegion(E->getRHS(), RHSTrueCnt,
2020a58f00eaSDimitry Andric                        subtractCounters(RHSExecCnt, RHSTrueCnt), DecisionRHS);
20210b57cec5SDimitry Andric   }
20220b57cec5SDimitry Andric 
2023fe013be4SDimitry Andric   // Determine whether the right side of OR operation need to be visited.
shouldVisitRHS__anonc2c3cfe60211::CounterCoverageMappingBuilder2024fe013be4SDimitry Andric   bool shouldVisitRHS(const Expr *LHS) {
2025fe013be4SDimitry Andric     bool LHSIsTrue = false;
2026fe013be4SDimitry Andric     bool LHSIsConst = false;
2027fe013be4SDimitry Andric     if (!LHS->isValueDependent())
2028fe013be4SDimitry Andric       LHSIsConst = LHS->EvaluateAsBooleanCondition(
2029fe013be4SDimitry Andric           LHSIsTrue, CVM.getCodeGenModule().getContext());
2030fe013be4SDimitry Andric     return !LHSIsConst || (LHSIsConst && !LHSIsTrue);
2031fe013be4SDimitry Andric   }
2032fe013be4SDimitry Andric 
VisitBinLOr__anonc2c3cfe60211::CounterCoverageMappingBuilder20330b57cec5SDimitry Andric   void VisitBinLOr(const BinaryOperator *E) {
2034a58f00eaSDimitry Andric     bool IsRootNode = MCDCBuilder.isIdle();
2035a58f00eaSDimitry Andric 
2036a58f00eaSDimitry Andric     // Keep track of Binary Operator and assign MCDC condition IDs.
2037cdc20ff6SDimitry Andric     MCDCBuilder.pushAndAssignIDs(E);
2038cdc20ff6SDimitry Andric 
20390b57cec5SDimitry Andric     extendRegion(E->getLHS());
2040fe013be4SDimitry Andric     Counter OutCount = propagateCounts(getRegion().getCounter(), E->getLHS());
20410b57cec5SDimitry Andric     handleFileExit(getEnd(E->getLHS()));
20420b57cec5SDimitry Andric 
2043a58f00eaSDimitry Andric     // Track LHS True/False Decision.
2044a58f00eaSDimitry Andric     const auto DecisionLHS = MCDCBuilder.pop();
2045a58f00eaSDimitry Andric 
2046e8d8bef9SDimitry Andric     // Counter tracks the right hand side of a logical or operator.
20470b57cec5SDimitry Andric     extendRegion(E->getRHS());
20480b57cec5SDimitry Andric     propagateCounts(getRegionCounter(E), E->getRHS());
2049e8d8bef9SDimitry Andric 
2050a58f00eaSDimitry Andric     // Track RHS True/False Decision.
2051a58f00eaSDimitry Andric     const auto DecisionRHS = MCDCBuilder.back();
2052a58f00eaSDimitry Andric 
2053a58f00eaSDimitry Andric     // Create MCDC Decision Region if at top-level (root).
2054cdc20ff6SDimitry Andric     unsigned NumConds = 0;
2055a58f00eaSDimitry Andric     if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E)))
2056cdc20ff6SDimitry Andric       createDecisionRegion(E, getRegionBitmap(E), NumConds);
2057cdc20ff6SDimitry Andric 
2058e8d8bef9SDimitry Andric     // Extract the RHS's Execution Counter.
2059e8d8bef9SDimitry Andric     Counter RHSExecCnt = getRegionCounter(E);
2060e8d8bef9SDimitry Andric 
2061e8d8bef9SDimitry Andric     // Extract the RHS's "False" Instance Counter.
2062e8d8bef9SDimitry Andric     Counter RHSFalseCnt = getRegionCounter(E->getRHS());
2063e8d8bef9SDimitry Andric 
2064fe013be4SDimitry Andric     if (!shouldVisitRHS(E->getLHS())) {
2065fe013be4SDimitry Andric       GapRegionCounter = OutCount;
2066fe013be4SDimitry Andric     }
2067fe013be4SDimitry Andric 
2068e8d8bef9SDimitry Andric     // Extract the Parent Region Counter.
2069e8d8bef9SDimitry Andric     Counter ParentCnt = getRegion().getCounter();
2070e8d8bef9SDimitry Andric 
2071e8d8bef9SDimitry Andric     // Create Branch Region around LHS condition.
2072e8d8bef9SDimitry Andric     createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
2073a58f00eaSDimitry Andric                        RHSExecCnt, DecisionLHS);
2074e8d8bef9SDimitry Andric 
2075e8d8bef9SDimitry Andric     // Create Branch Region around RHS condition.
2076e8d8bef9SDimitry Andric     createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
2077a58f00eaSDimitry Andric                        RHSFalseCnt, DecisionRHS);
20780b57cec5SDimitry Andric   }
20790b57cec5SDimitry Andric 
VisitLambdaExpr__anonc2c3cfe60211::CounterCoverageMappingBuilder20800b57cec5SDimitry Andric   void VisitLambdaExpr(const LambdaExpr *LE) {
20810b57cec5SDimitry Andric     // Lambdas are treated as their own functions for now, so we shouldn't
20820b57cec5SDimitry Andric     // propagate counts into them.
20830b57cec5SDimitry Andric   }
2084fe013be4SDimitry Andric 
VisitPseudoObjectExpr__anonc2c3cfe60211::CounterCoverageMappingBuilder2085fe013be4SDimitry Andric   void VisitPseudoObjectExpr(const PseudoObjectExpr *POE) {
2086fe013be4SDimitry Andric     // Just visit syntatic expression as this is what users actually write.
2087fe013be4SDimitry Andric     VisitStmt(POE->getSyntacticForm());
2088fe013be4SDimitry Andric   }
2089fe013be4SDimitry Andric 
VisitOpaqueValueExpr__anonc2c3cfe60211::CounterCoverageMappingBuilder2090fe013be4SDimitry Andric   void VisitOpaqueValueExpr(const OpaqueValueExpr* OVE) {
2091fe013be4SDimitry Andric     Visit(OVE->getSourceExpr());
2092fe013be4SDimitry Andric   }
20930b57cec5SDimitry Andric };
20940b57cec5SDimitry Andric 
20950b57cec5SDimitry Andric } // end anonymous namespace
20960b57cec5SDimitry Andric 
dump(llvm::raw_ostream & OS,StringRef FunctionName,ArrayRef<CounterExpression> Expressions,ArrayRef<CounterMappingRegion> Regions)20970b57cec5SDimitry Andric static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
20980b57cec5SDimitry Andric                  ArrayRef<CounterExpression> Expressions,
20990b57cec5SDimitry Andric                  ArrayRef<CounterMappingRegion> Regions) {
21000b57cec5SDimitry Andric   OS << FunctionName << ":\n";
21010b57cec5SDimitry Andric   CounterMappingContext Ctx(Expressions);
21020b57cec5SDimitry Andric   for (const auto &R : Regions) {
21030b57cec5SDimitry Andric     OS.indent(2);
21040b57cec5SDimitry Andric     switch (R.Kind) {
21050b57cec5SDimitry Andric     case CounterMappingRegion::CodeRegion:
21060b57cec5SDimitry Andric       break;
21070b57cec5SDimitry Andric     case CounterMappingRegion::ExpansionRegion:
21080b57cec5SDimitry Andric       OS << "Expansion,";
21090b57cec5SDimitry Andric       break;
21100b57cec5SDimitry Andric     case CounterMappingRegion::SkippedRegion:
21110b57cec5SDimitry Andric       OS << "Skipped,";
21120b57cec5SDimitry Andric       break;
21130b57cec5SDimitry Andric     case CounterMappingRegion::GapRegion:
21140b57cec5SDimitry Andric       OS << "Gap,";
21150b57cec5SDimitry Andric       break;
2116e8d8bef9SDimitry Andric     case CounterMappingRegion::BranchRegion:
2117c9157d92SDimitry Andric     case CounterMappingRegion::MCDCBranchRegion:
2118e8d8bef9SDimitry Andric       OS << "Branch,";
2119e8d8bef9SDimitry Andric       break;
2120c9157d92SDimitry Andric     case CounterMappingRegion::MCDCDecisionRegion:
2121c9157d92SDimitry Andric       OS << "Decision,";
2122c9157d92SDimitry Andric       break;
21230b57cec5SDimitry Andric     }
21240b57cec5SDimitry Andric 
21250b57cec5SDimitry Andric     OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
21260b57cec5SDimitry Andric        << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = ";
2127cdc20ff6SDimitry Andric 
2128cdc20ff6SDimitry Andric     if (R.Kind == CounterMappingRegion::MCDCDecisionRegion) {
2129cdc20ff6SDimitry Andric       OS << "M:" << R.MCDCParams.BitmapIdx;
2130cdc20ff6SDimitry Andric       OS << ", C:" << R.MCDCParams.NumConditions;
2131cdc20ff6SDimitry Andric     } else {
21320b57cec5SDimitry Andric       Ctx.dump(R.Count, OS);
2133e8d8bef9SDimitry Andric 
2134cdc20ff6SDimitry Andric       if (R.Kind == CounterMappingRegion::BranchRegion ||
2135cdc20ff6SDimitry Andric           R.Kind == CounterMappingRegion::MCDCBranchRegion) {
2136e8d8bef9SDimitry Andric         OS << ", ";
2137e8d8bef9SDimitry Andric         Ctx.dump(R.FalseCount, OS);
2138e8d8bef9SDimitry Andric       }
2139cdc20ff6SDimitry Andric     }
2140cdc20ff6SDimitry Andric 
2141cdc20ff6SDimitry Andric     if (R.Kind == CounterMappingRegion::MCDCBranchRegion) {
2142cdc20ff6SDimitry Andric       OS << " [" << R.MCDCParams.ID << "," << R.MCDCParams.TrueID;
2143cdc20ff6SDimitry Andric       OS << "," << R.MCDCParams.FalseID << "] ";
2144cdc20ff6SDimitry Andric     }
2145e8d8bef9SDimitry Andric 
21460b57cec5SDimitry Andric     if (R.Kind == CounterMappingRegion::ExpansionRegion)
21470b57cec5SDimitry Andric       OS << " (Expanded file = " << R.ExpandedFileID << ")";
21480b57cec5SDimitry Andric     OS << "\n";
21490b57cec5SDimitry Andric   }
21500b57cec5SDimitry Andric }
21510b57cec5SDimitry Andric 
CoverageMappingModuleGen(CodeGenModule & CGM,CoverageSourceInfo & SourceInfo)2152e8d8bef9SDimitry Andric CoverageMappingModuleGen::CoverageMappingModuleGen(
2153e8d8bef9SDimitry Andric     CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
2154fe013be4SDimitry Andric     : CGM(CGM), SourceInfo(SourceInfo) {}
2155fe6060f1SDimitry Andric 
getCurrentDirname()2156fe6060f1SDimitry Andric std::string CoverageMappingModuleGen::getCurrentDirname() {
2157fe6060f1SDimitry Andric   if (!CGM.getCodeGenOpts().CoverageCompilationDir.empty())
2158fe6060f1SDimitry Andric     return CGM.getCodeGenOpts().CoverageCompilationDir;
2159fe6060f1SDimitry Andric 
2160fe6060f1SDimitry Andric   SmallString<256> CWD;
2161fe6060f1SDimitry Andric   llvm::sys::fs::current_path(CWD);
2162fe6060f1SDimitry Andric   return CWD.str().str();
2163e8d8bef9SDimitry Andric }
2164e8d8bef9SDimitry Andric 
normalizeFilename(StringRef Filename)2165e8d8bef9SDimitry Andric std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
2166e8d8bef9SDimitry Andric   llvm::SmallString<256> Path(Filename);
2167e8d8bef9SDimitry Andric   llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
2168fe013be4SDimitry Andric 
2169fe013be4SDimitry Andric   /// Traverse coverage prefix map in reverse order because prefix replacements
2170fe013be4SDimitry Andric   /// are applied in reverse order starting from the last one when multiple
2171fe013be4SDimitry Andric   /// prefix replacement options are provided.
2172fe013be4SDimitry Andric   for (const auto &[From, To] :
2173fe013be4SDimitry Andric        llvm::reverse(CGM.getCodeGenOpts().CoveragePrefixMap)) {
2174fe013be4SDimitry Andric     if (llvm::sys::path::replace_path_prefix(Path, From, To))
2175e8d8bef9SDimitry Andric       break;
2176e8d8bef9SDimitry Andric   }
2177e8d8bef9SDimitry Andric   return Path.str().str();
2178e8d8bef9SDimitry Andric }
2179e8d8bef9SDimitry Andric 
getInstrProfSection(const CodeGenModule & CGM,llvm::InstrProfSectKind SK)21805ffd83dbSDimitry Andric static std::string getInstrProfSection(const CodeGenModule &CGM,
21815ffd83dbSDimitry Andric                                        llvm::InstrProfSectKind SK) {
21825ffd83dbSDimitry Andric   return llvm::getInstrProfSectionName(
21835ffd83dbSDimitry Andric       SK, CGM.getContext().getTargetInfo().getTriple().getObjectFormat());
21845ffd83dbSDimitry Andric }
21855ffd83dbSDimitry Andric 
emitFunctionMappingRecord(const FunctionInfo & Info,uint64_t FilenamesRef)21865ffd83dbSDimitry Andric void CoverageMappingModuleGen::emitFunctionMappingRecord(
21875ffd83dbSDimitry Andric     const FunctionInfo &Info, uint64_t FilenamesRef) {
21880b57cec5SDimitry Andric   llvm::LLVMContext &Ctx = CGM.getLLVMContext();
21895ffd83dbSDimitry Andric 
21905ffd83dbSDimitry Andric   // Assign a name to the function record. This is used to merge duplicates.
21915ffd83dbSDimitry Andric   std::string FuncRecordName = "__covrec_" + llvm::utohexstr(Info.NameHash);
21925ffd83dbSDimitry Andric 
21935ffd83dbSDimitry Andric   // A dummy description for a function included-but-not-used in a TU can be
21945ffd83dbSDimitry Andric   // replaced by full description provided by a different TU. The two kinds of
21955ffd83dbSDimitry Andric   // descriptions play distinct roles: therefore, assign them different names
21965ffd83dbSDimitry Andric   // to prevent `linkonce_odr` merging.
21975ffd83dbSDimitry Andric   if (Info.IsUsed)
21985ffd83dbSDimitry Andric     FuncRecordName += "u";
21995ffd83dbSDimitry Andric 
22005ffd83dbSDimitry Andric   // Create the function record type.
22015ffd83dbSDimitry Andric   const uint64_t NameHash = Info.NameHash;
22025ffd83dbSDimitry Andric   const uint64_t FuncHash = Info.FuncHash;
22035ffd83dbSDimitry Andric   const std::string &CoverageMapping = Info.CoverageMapping;
22040b57cec5SDimitry Andric #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
22050b57cec5SDimitry Andric   llvm::Type *FunctionRecordTypes[] = {
22060b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc"
22070b57cec5SDimitry Andric   };
22085ffd83dbSDimitry Andric   auto *FunctionRecordTy =
2209bdd1243dSDimitry Andric       llvm::StructType::get(Ctx, ArrayRef(FunctionRecordTypes),
22100b57cec5SDimitry Andric                             /*isPacked=*/true);
22110b57cec5SDimitry Andric 
22125ffd83dbSDimitry Andric   // Create the function record constant.
22130b57cec5SDimitry Andric #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
22140b57cec5SDimitry Andric   llvm::Constant *FunctionRecordVals[] = {
22150b57cec5SDimitry Andric       #include "llvm/ProfileData/InstrProfData.inc"
22160b57cec5SDimitry Andric   };
2217bdd1243dSDimitry Andric   auto *FuncRecordConstant =
2218bdd1243dSDimitry Andric       llvm::ConstantStruct::get(FunctionRecordTy, ArrayRef(FunctionRecordVals));
22195ffd83dbSDimitry Andric 
22205ffd83dbSDimitry Andric   // Create the function record global.
22215ffd83dbSDimitry Andric   auto *FuncRecord = new llvm::GlobalVariable(
22225ffd83dbSDimitry Andric       CGM.getModule(), FunctionRecordTy, /*isConstant=*/true,
22235ffd83dbSDimitry Andric       llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
22245ffd83dbSDimitry Andric       FuncRecordName);
22255ffd83dbSDimitry Andric   FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
22265ffd83dbSDimitry Andric   FuncRecord->setSection(getInstrProfSection(CGM, llvm::IPSK_covfun));
22275ffd83dbSDimitry Andric   FuncRecord->setAlignment(llvm::Align(8));
22285ffd83dbSDimitry Andric   if (CGM.supportsCOMDAT())
22295ffd83dbSDimitry Andric     FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
22305ffd83dbSDimitry Andric 
22315ffd83dbSDimitry Andric   // Make sure the data doesn't get deleted.
22325ffd83dbSDimitry Andric   CGM.addUsedGlobal(FuncRecord);
22335ffd83dbSDimitry Andric }
22345ffd83dbSDimitry Andric 
addFunctionMappingRecord(llvm::GlobalVariable * NamePtr,StringRef NameValue,uint64_t FuncHash,const std::string & CoverageMapping,bool IsUsed)22355ffd83dbSDimitry Andric void CoverageMappingModuleGen::addFunctionMappingRecord(
22365ffd83dbSDimitry Andric     llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
22375ffd83dbSDimitry Andric     const std::string &CoverageMapping, bool IsUsed) {
22385ffd83dbSDimitry Andric   const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
22395ffd83dbSDimitry Andric   FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
22405ffd83dbSDimitry Andric 
22410b57cec5SDimitry Andric   if (!IsUsed)
2242c9157d92SDimitry Andric     FunctionNames.push_back(NamePtr);
22430b57cec5SDimitry Andric 
22440b57cec5SDimitry Andric   if (CGM.getCodeGenOpts().DumpCoverageMapping) {
22450b57cec5SDimitry Andric     // Dump the coverage mapping data for this function by decoding the
22460b57cec5SDimitry Andric     // encoded data. This allows us to dump the mapping regions which were
22470b57cec5SDimitry Andric     // also processed by the CoverageMappingWriter which performs
22480b57cec5SDimitry Andric     // additional minimization operations such as reducing the number of
22490b57cec5SDimitry Andric     // expressions.
2250fe6060f1SDimitry Andric     llvm::SmallVector<std::string, 16> FilenameStrs;
22510b57cec5SDimitry Andric     std::vector<StringRef> Filenames;
22520b57cec5SDimitry Andric     std::vector<CounterExpression> Expressions;
22530b57cec5SDimitry Andric     std::vector<CounterMappingRegion> Regions;
2254fe6060f1SDimitry Andric     FilenameStrs.resize(FileEntries.size() + 1);
2255fe6060f1SDimitry Andric     FilenameStrs[0] = normalizeFilename(getCurrentDirname());
22560b57cec5SDimitry Andric     for (const auto &Entry : FileEntries) {
22570b57cec5SDimitry Andric       auto I = Entry.second;
2258c9157d92SDimitry Andric       FilenameStrs[I] = normalizeFilename(Entry.first.getName());
22590b57cec5SDimitry Andric     }
2260bdd1243dSDimitry Andric     ArrayRef<std::string> FilenameRefs = llvm::ArrayRef(FilenameStrs);
22610b57cec5SDimitry Andric     RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
22620b57cec5SDimitry Andric                                     Expressions, Regions);
22630b57cec5SDimitry Andric     if (Reader.read())
22640b57cec5SDimitry Andric       return;
22650b57cec5SDimitry Andric     dump(llvm::outs(), NameValue, Expressions, Regions);
22660b57cec5SDimitry Andric   }
22670b57cec5SDimitry Andric }
22680b57cec5SDimitry Andric 
emit()22690b57cec5SDimitry Andric void CoverageMappingModuleGen::emit() {
22700b57cec5SDimitry Andric   if (FunctionRecords.empty())
22710b57cec5SDimitry Andric     return;
22720b57cec5SDimitry Andric   llvm::LLVMContext &Ctx = CGM.getLLVMContext();
22730b57cec5SDimitry Andric   auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
22740b57cec5SDimitry Andric 
22750b57cec5SDimitry Andric   // Create the filenames and merge them with coverage mappings
22760b57cec5SDimitry Andric   llvm::SmallVector<std::string, 16> FilenameStrs;
2277fe6060f1SDimitry Andric   FilenameStrs.resize(FileEntries.size() + 1);
2278fe6060f1SDimitry Andric   // The first filename is the current working directory.
2279fe6060f1SDimitry Andric   FilenameStrs[0] = normalizeFilename(getCurrentDirname());
22800b57cec5SDimitry Andric   for (const auto &Entry : FileEntries) {
22810b57cec5SDimitry Andric     auto I = Entry.second;
2282c9157d92SDimitry Andric     FilenameStrs[I] = normalizeFilename(Entry.first.getName());
22830b57cec5SDimitry Andric   }
22840b57cec5SDimitry Andric 
22855ffd83dbSDimitry Andric   std::string Filenames;
22865ffd83dbSDimitry Andric   {
22875ffd83dbSDimitry Andric     llvm::raw_string_ostream OS(Filenames);
2288fe6060f1SDimitry Andric     CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
22890b57cec5SDimitry Andric   }
22905ffd83dbSDimitry Andric   auto *FilenamesVal =
22915ffd83dbSDimitry Andric       llvm::ConstantDataArray::getString(Ctx, Filenames, false);
22925ffd83dbSDimitry Andric   const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
22930b57cec5SDimitry Andric 
22945ffd83dbSDimitry Andric   // Emit the function records.
22955ffd83dbSDimitry Andric   for (const FunctionInfo &Info : FunctionRecords)
22965ffd83dbSDimitry Andric     emitFunctionMappingRecord(Info, FilenamesRef);
22970b57cec5SDimitry Andric 
22985ffd83dbSDimitry Andric   const unsigned NRecords = 0;
22995ffd83dbSDimitry Andric   const size_t FilenamesSize = Filenames.size();
23005ffd83dbSDimitry Andric   const unsigned CoverageMappingSize = 0;
23010b57cec5SDimitry Andric   llvm::Type *CovDataHeaderTypes[] = {
23020b57cec5SDimitry Andric #define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
23030b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc"
23040b57cec5SDimitry Andric   };
23050b57cec5SDimitry Andric   auto CovDataHeaderTy =
2306bdd1243dSDimitry Andric       llvm::StructType::get(Ctx, ArrayRef(CovDataHeaderTypes));
23070b57cec5SDimitry Andric   llvm::Constant *CovDataHeaderVals[] = {
23080b57cec5SDimitry Andric #define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
23090b57cec5SDimitry Andric #include "llvm/ProfileData/InstrProfData.inc"
23100b57cec5SDimitry Andric   };
2311bdd1243dSDimitry Andric   auto CovDataHeaderVal =
2312bdd1243dSDimitry Andric       llvm::ConstantStruct::get(CovDataHeaderTy, ArrayRef(CovDataHeaderVals));
23130b57cec5SDimitry Andric 
23140b57cec5SDimitry Andric   // Create the coverage data record
23155ffd83dbSDimitry Andric   llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
2316bdd1243dSDimitry Andric   auto CovDataTy = llvm::StructType::get(Ctx, ArrayRef(CovDataTypes));
23175ffd83dbSDimitry Andric   llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
2318bdd1243dSDimitry Andric   auto CovDataVal = llvm::ConstantStruct::get(CovDataTy, ArrayRef(TUDataVals));
23190b57cec5SDimitry Andric   auto CovData = new llvm::GlobalVariable(
23205ffd83dbSDimitry Andric       CGM.getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage,
23210b57cec5SDimitry Andric       CovDataVal, llvm::getCoverageMappingVarName());
23220b57cec5SDimitry Andric 
23235ffd83dbSDimitry Andric   CovData->setSection(getInstrProfSection(CGM, llvm::IPSK_covmap));
2324a7dea167SDimitry Andric   CovData->setAlignment(llvm::Align(8));
23250b57cec5SDimitry Andric 
23260b57cec5SDimitry Andric   // Make sure the data doesn't get deleted.
23270b57cec5SDimitry Andric   CGM.addUsedGlobal(CovData);
23280b57cec5SDimitry Andric   // Create the deferred function records array
23290b57cec5SDimitry Andric   if (!FunctionNames.empty()) {
2330c9157d92SDimitry Andric     auto NamesArrTy = llvm::ArrayType::get(llvm::PointerType::getUnqual(Ctx),
23310b57cec5SDimitry Andric                                            FunctionNames.size());
23320b57cec5SDimitry Andric     auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
23330b57cec5SDimitry Andric     // This variable will *NOT* be emitted to the object file. It is used
23340b57cec5SDimitry Andric     // to pass the list of names referenced to codegen.
23350b57cec5SDimitry Andric     new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
23360b57cec5SDimitry Andric                              llvm::GlobalValue::InternalLinkage, NamesArrVal,
23370b57cec5SDimitry Andric                              llvm::getCoverageUnusedNamesVarName());
23380b57cec5SDimitry Andric   }
23390b57cec5SDimitry Andric }
23400b57cec5SDimitry Andric 
getFileID(FileEntryRef File)2341c9157d92SDimitry Andric unsigned CoverageMappingModuleGen::getFileID(FileEntryRef File) {
23420b57cec5SDimitry Andric   auto It = FileEntries.find(File);
23430b57cec5SDimitry Andric   if (It != FileEntries.end())
23440b57cec5SDimitry Andric     return It->second;
2345fe6060f1SDimitry Andric   unsigned FileID = FileEntries.size() + 1;
23460b57cec5SDimitry Andric   FileEntries.insert(std::make_pair(File, FileID));
23470b57cec5SDimitry Andric   return FileID;
23480b57cec5SDimitry Andric }
23490b57cec5SDimitry Andric 
emitCounterMapping(const Decl * D,llvm::raw_ostream & OS)23500b57cec5SDimitry Andric void CoverageMappingGen::emitCounterMapping(const Decl *D,
23510b57cec5SDimitry Andric                                             llvm::raw_ostream &OS) {
2352cdc20ff6SDimitry Andric   assert(CounterMap && MCDCBitmapMap);
2353cdc20ff6SDimitry Andric   CounterCoverageMappingBuilder Walker(CVM, *CounterMap, *MCDCBitmapMap,
2354cdc20ff6SDimitry Andric                                        *CondIDMap, SM, LangOpts);
23550b57cec5SDimitry Andric   Walker.VisitDecl(D);
23560b57cec5SDimitry Andric   Walker.write(OS);
23570b57cec5SDimitry Andric }
23580b57cec5SDimitry Andric 
emitEmptyMapping(const Decl * D,llvm::raw_ostream & OS)23590b57cec5SDimitry Andric void CoverageMappingGen::emitEmptyMapping(const Decl *D,
23600b57cec5SDimitry Andric                                           llvm::raw_ostream &OS) {
23610b57cec5SDimitry Andric   EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
23620b57cec5SDimitry Andric   Walker.VisitDecl(D);
23630b57cec5SDimitry Andric   Walker.write(OS);
23640b57cec5SDimitry Andric }
2365