17330f729Sjoerg //===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // Instrumentation-based code coverage mapping generator
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
137330f729Sjoerg #include "CoverageMappingGen.h"
147330f729Sjoerg #include "CodeGenFunction.h"
157330f729Sjoerg #include "clang/AST/StmtVisitor.h"
16*e038c9c4Sjoerg #include "clang/Basic/Diagnostic.h"
17*e038c9c4Sjoerg #include "clang/Basic/FileManager.h"
18*e038c9c4Sjoerg #include "clang/Frontend/FrontendDiagnostic.h"
197330f729Sjoerg #include "clang/Lex/Lexer.h"
20*e038c9c4Sjoerg #include "llvm/ADT/Optional.h"
217330f729Sjoerg #include "llvm/ADT/SmallSet.h"
227330f729Sjoerg #include "llvm/ADT/StringExtras.h"
237330f729Sjoerg #include "llvm/ProfileData/Coverage/CoverageMapping.h"
247330f729Sjoerg #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
257330f729Sjoerg #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
267330f729Sjoerg #include "llvm/ProfileData/InstrProfReader.h"
277330f729Sjoerg #include "llvm/Support/FileSystem.h"
287330f729Sjoerg #include "llvm/Support/Path.h"
297330f729Sjoerg
30*e038c9c4Sjoerg // This selects the coverage mapping format defined when `InstrProfData.inc`
31*e038c9c4Sjoerg // is textually included.
32*e038c9c4Sjoerg #define COVMAP_V3
33*e038c9c4Sjoerg
34*e038c9c4Sjoerg static llvm::cl::opt<bool> EmptyLineCommentCoverage(
35*e038c9c4Sjoerg "emptyline-comment-coverage",
36*e038c9c4Sjoerg llvm::cl::desc("Emit emptylines and comment lines as skipped regions (only "
37*e038c9c4Sjoerg "disable it on test)"),
38*e038c9c4Sjoerg llvm::cl::init(true), llvm::cl::Hidden);
39*e038c9c4Sjoerg
407330f729Sjoerg using namespace clang;
417330f729Sjoerg using namespace CodeGen;
427330f729Sjoerg using namespace llvm::coverage;
437330f729Sjoerg
44*e038c9c4Sjoerg CoverageSourceInfo *
setUpCoverageCallbacks(Preprocessor & PP)45*e038c9c4Sjoerg CoverageMappingModuleGen::setUpCoverageCallbacks(Preprocessor &PP) {
46*e038c9c4Sjoerg CoverageSourceInfo *CoverageInfo =
47*e038c9c4Sjoerg new CoverageSourceInfo(PP.getSourceManager());
48*e038c9c4Sjoerg PP.addPPCallbacks(std::unique_ptr<PPCallbacks>(CoverageInfo));
49*e038c9c4Sjoerg if (EmptyLineCommentCoverage) {
50*e038c9c4Sjoerg PP.addCommentHandler(CoverageInfo);
51*e038c9c4Sjoerg PP.setEmptylineHandler(CoverageInfo);
52*e038c9c4Sjoerg PP.setPreprocessToken(true);
53*e038c9c4Sjoerg PP.setTokenWatcher([CoverageInfo](clang::Token Tok) {
54*e038c9c4Sjoerg // Update previous token location.
55*e038c9c4Sjoerg CoverageInfo->PrevTokLoc = Tok.getLocation();
56*e038c9c4Sjoerg if (Tok.getKind() != clang::tok::eod)
57*e038c9c4Sjoerg CoverageInfo->updateNextTokLoc(Tok.getLocation());
58*e038c9c4Sjoerg });
59*e038c9c4Sjoerg }
60*e038c9c4Sjoerg return CoverageInfo;
61*e038c9c4Sjoerg }
62*e038c9c4Sjoerg
AddSkippedRange(SourceRange Range)63*e038c9c4Sjoerg void CoverageSourceInfo::AddSkippedRange(SourceRange Range) {
64*e038c9c4Sjoerg if (EmptyLineCommentCoverage && !SkippedRanges.empty() &&
65*e038c9c4Sjoerg PrevTokLoc == SkippedRanges.back().PrevTokLoc &&
66*e038c9c4Sjoerg SourceMgr.isWrittenInSameFile(SkippedRanges.back().Range.getEnd(),
67*e038c9c4Sjoerg Range.getBegin()))
68*e038c9c4Sjoerg SkippedRanges.back().Range.setEnd(Range.getEnd());
69*e038c9c4Sjoerg else
70*e038c9c4Sjoerg SkippedRanges.push_back({Range, PrevTokLoc});
71*e038c9c4Sjoerg }
72*e038c9c4Sjoerg
SourceRangeSkipped(SourceRange Range,SourceLocation)737330f729Sjoerg void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) {
74*e038c9c4Sjoerg AddSkippedRange(Range);
75*e038c9c4Sjoerg }
76*e038c9c4Sjoerg
HandleEmptyline(SourceRange Range)77*e038c9c4Sjoerg void CoverageSourceInfo::HandleEmptyline(SourceRange Range) {
78*e038c9c4Sjoerg AddSkippedRange(Range);
79*e038c9c4Sjoerg }
80*e038c9c4Sjoerg
HandleComment(Preprocessor & PP,SourceRange Range)81*e038c9c4Sjoerg bool CoverageSourceInfo::HandleComment(Preprocessor &PP, SourceRange Range) {
82*e038c9c4Sjoerg AddSkippedRange(Range);
83*e038c9c4Sjoerg return false;
84*e038c9c4Sjoerg }
85*e038c9c4Sjoerg
updateNextTokLoc(SourceLocation Loc)86*e038c9c4Sjoerg void CoverageSourceInfo::updateNextTokLoc(SourceLocation Loc) {
87*e038c9c4Sjoerg if (!SkippedRanges.empty() && SkippedRanges.back().NextTokLoc.isInvalid())
88*e038c9c4Sjoerg SkippedRanges.back().NextTokLoc = Loc;
897330f729Sjoerg }
907330f729Sjoerg
917330f729Sjoerg namespace {
927330f729Sjoerg
937330f729Sjoerg /// A region of source code that can be mapped to a counter.
947330f729Sjoerg class SourceMappingRegion {
95*e038c9c4Sjoerg /// Primary Counter that is also used for Branch Regions for "True" branches.
967330f729Sjoerg Counter Count;
977330f729Sjoerg
98*e038c9c4Sjoerg /// Secondary Counter used for Branch Regions for "False" branches.
99*e038c9c4Sjoerg Optional<Counter> FalseCount;
100*e038c9c4Sjoerg
1017330f729Sjoerg /// The region's starting location.
1027330f729Sjoerg Optional<SourceLocation> LocStart;
1037330f729Sjoerg
1047330f729Sjoerg /// The region's ending location.
1057330f729Sjoerg Optional<SourceLocation> LocEnd;
1067330f729Sjoerg
1077330f729Sjoerg /// Whether this region is a gap region. The count from a gap region is set
1087330f729Sjoerg /// as the line execution count if there are no other regions on the line.
1097330f729Sjoerg bool GapRegion;
1107330f729Sjoerg
1117330f729Sjoerg public:
SourceMappingRegion(Counter Count,Optional<SourceLocation> LocStart,Optional<SourceLocation> LocEnd,bool GapRegion=false)1127330f729Sjoerg SourceMappingRegion(Counter Count, Optional<SourceLocation> LocStart,
113*e038c9c4Sjoerg Optional<SourceLocation> LocEnd, bool GapRegion = false)
114*e038c9c4Sjoerg : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) {
115*e038c9c4Sjoerg }
116*e038c9c4Sjoerg
SourceMappingRegion(Counter Count,Optional<Counter> FalseCount,Optional<SourceLocation> LocStart,Optional<SourceLocation> LocEnd,bool GapRegion=false)117*e038c9c4Sjoerg SourceMappingRegion(Counter Count, Optional<Counter> FalseCount,
118*e038c9c4Sjoerg Optional<SourceLocation> LocStart,
119*e038c9c4Sjoerg Optional<SourceLocation> LocEnd, bool GapRegion = false)
120*e038c9c4Sjoerg : Count(Count), FalseCount(FalseCount), LocStart(LocStart),
121*e038c9c4Sjoerg LocEnd(LocEnd), GapRegion(GapRegion) {}
1227330f729Sjoerg
getCounter() const1237330f729Sjoerg const Counter &getCounter() const { return Count; }
1247330f729Sjoerg
getFalseCounter() const125*e038c9c4Sjoerg const Counter &getFalseCounter() const {
126*e038c9c4Sjoerg assert(FalseCount && "Region has no alternate counter");
127*e038c9c4Sjoerg return *FalseCount;
128*e038c9c4Sjoerg }
129*e038c9c4Sjoerg
setCounter(Counter C)1307330f729Sjoerg void setCounter(Counter C) { Count = C; }
1317330f729Sjoerg
hasStartLoc() const1327330f729Sjoerg bool hasStartLoc() const { return LocStart.hasValue(); }
1337330f729Sjoerg
setStartLoc(SourceLocation Loc)1347330f729Sjoerg void setStartLoc(SourceLocation Loc) { LocStart = Loc; }
1357330f729Sjoerg
getBeginLoc() const1367330f729Sjoerg SourceLocation getBeginLoc() const {
1377330f729Sjoerg assert(LocStart && "Region has no start location");
1387330f729Sjoerg return *LocStart;
1397330f729Sjoerg }
1407330f729Sjoerg
hasEndLoc() const1417330f729Sjoerg bool hasEndLoc() const { return LocEnd.hasValue(); }
1427330f729Sjoerg
setEndLoc(SourceLocation Loc)1437330f729Sjoerg void setEndLoc(SourceLocation Loc) {
1447330f729Sjoerg assert(Loc.isValid() && "Setting an invalid end location");
1457330f729Sjoerg LocEnd = Loc;
1467330f729Sjoerg }
1477330f729Sjoerg
getEndLoc() const1487330f729Sjoerg SourceLocation getEndLoc() const {
1497330f729Sjoerg assert(LocEnd && "Region has no end location");
1507330f729Sjoerg return *LocEnd;
1517330f729Sjoerg }
1527330f729Sjoerg
isGap() const1537330f729Sjoerg bool isGap() const { return GapRegion; }
1547330f729Sjoerg
setGap(bool Gap)1557330f729Sjoerg void setGap(bool Gap) { GapRegion = Gap; }
156*e038c9c4Sjoerg
isBranch() const157*e038c9c4Sjoerg bool isBranch() const { return FalseCount.hasValue(); }
1587330f729Sjoerg };
1597330f729Sjoerg
1607330f729Sjoerg /// Spelling locations for the start and end of a source region.
1617330f729Sjoerg struct SpellingRegion {
1627330f729Sjoerg /// The line where the region starts.
1637330f729Sjoerg unsigned LineStart;
1647330f729Sjoerg
1657330f729Sjoerg /// The column where the region starts.
1667330f729Sjoerg unsigned ColumnStart;
1677330f729Sjoerg
1687330f729Sjoerg /// The line where the region ends.
1697330f729Sjoerg unsigned LineEnd;
1707330f729Sjoerg
1717330f729Sjoerg /// The column where the region ends.
1727330f729Sjoerg unsigned ColumnEnd;
1737330f729Sjoerg
SpellingRegion__anon8c3eb65b0211::SpellingRegion1747330f729Sjoerg SpellingRegion(SourceManager &SM, SourceLocation LocStart,
1757330f729Sjoerg SourceLocation LocEnd) {
1767330f729Sjoerg LineStart = SM.getSpellingLineNumber(LocStart);
1777330f729Sjoerg ColumnStart = SM.getSpellingColumnNumber(LocStart);
1787330f729Sjoerg LineEnd = SM.getSpellingLineNumber(LocEnd);
1797330f729Sjoerg ColumnEnd = SM.getSpellingColumnNumber(LocEnd);
1807330f729Sjoerg }
1817330f729Sjoerg
SpellingRegion__anon8c3eb65b0211::SpellingRegion1827330f729Sjoerg SpellingRegion(SourceManager &SM, SourceMappingRegion &R)
1837330f729Sjoerg : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {}
1847330f729Sjoerg
1857330f729Sjoerg /// Check if the start and end locations appear in source order, i.e
1867330f729Sjoerg /// top->bottom, left->right.
isInSourceOrder__anon8c3eb65b0211::SpellingRegion1877330f729Sjoerg bool isInSourceOrder() const {
1887330f729Sjoerg return (LineStart < LineEnd) ||
1897330f729Sjoerg (LineStart == LineEnd && ColumnStart <= ColumnEnd);
1907330f729Sjoerg }
1917330f729Sjoerg };
1927330f729Sjoerg
1937330f729Sjoerg /// Provides the common functionality for the different
1947330f729Sjoerg /// coverage mapping region builders.
1957330f729Sjoerg class CoverageMappingBuilder {
1967330f729Sjoerg public:
1977330f729Sjoerg CoverageMappingModuleGen &CVM;
1987330f729Sjoerg SourceManager &SM;
1997330f729Sjoerg const LangOptions &LangOpts;
2007330f729Sjoerg
2017330f729Sjoerg private:
2027330f729Sjoerg /// Map of clang's FileIDs to IDs used for coverage mapping.
2037330f729Sjoerg llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8>
2047330f729Sjoerg FileIDMapping;
2057330f729Sjoerg
2067330f729Sjoerg public:
2077330f729Sjoerg /// The coverage mapping regions for this function
2087330f729Sjoerg llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;
2097330f729Sjoerg /// The source mapping regions for this function.
2107330f729Sjoerg std::vector<SourceMappingRegion> SourceRegions;
2117330f729Sjoerg
2127330f729Sjoerg /// A set of regions which can be used as a filter.
2137330f729Sjoerg ///
2147330f729Sjoerg /// It is produced by emitExpansionRegions() and is used in
2157330f729Sjoerg /// emitSourceRegions() to suppress producing code regions if
2167330f729Sjoerg /// the same area is covered by expansion regions.
2177330f729Sjoerg typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8>
2187330f729Sjoerg SourceRegionFilter;
2197330f729Sjoerg
CoverageMappingBuilder(CoverageMappingModuleGen & CVM,SourceManager & SM,const LangOptions & LangOpts)2207330f729Sjoerg CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
2217330f729Sjoerg const LangOptions &LangOpts)
2227330f729Sjoerg : CVM(CVM), SM(SM), LangOpts(LangOpts) {}
2237330f729Sjoerg
2247330f729Sjoerg /// Return the precise end location for the given token.
getPreciseTokenLocEnd(SourceLocation Loc)2257330f729Sjoerg SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) {
2267330f729Sjoerg // We avoid getLocForEndOfToken here, because it doesn't do what we want for
2277330f729Sjoerg // macro locations, which we just treat as expanded files.
2287330f729Sjoerg unsigned TokLen =
2297330f729Sjoerg Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts);
2307330f729Sjoerg return Loc.getLocWithOffset(TokLen);
2317330f729Sjoerg }
2327330f729Sjoerg
2337330f729Sjoerg /// Return the start location of an included file or expanded macro.
getStartOfFileOrMacro(SourceLocation Loc)2347330f729Sjoerg SourceLocation getStartOfFileOrMacro(SourceLocation Loc) {
2357330f729Sjoerg if (Loc.isMacroID())
2367330f729Sjoerg return Loc.getLocWithOffset(-SM.getFileOffset(Loc));
2377330f729Sjoerg return SM.getLocForStartOfFile(SM.getFileID(Loc));
2387330f729Sjoerg }
2397330f729Sjoerg
2407330f729Sjoerg /// Return the end location of an included file or expanded macro.
getEndOfFileOrMacro(SourceLocation Loc)2417330f729Sjoerg SourceLocation getEndOfFileOrMacro(SourceLocation Loc) {
2427330f729Sjoerg if (Loc.isMacroID())
2437330f729Sjoerg return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) -
2447330f729Sjoerg SM.getFileOffset(Loc));
2457330f729Sjoerg return SM.getLocForEndOfFile(SM.getFileID(Loc));
2467330f729Sjoerg }
2477330f729Sjoerg
2487330f729Sjoerg /// Find out where the current file is included or macro is expanded.
getIncludeOrExpansionLoc(SourceLocation Loc)2497330f729Sjoerg SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) {
2507330f729Sjoerg return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin()
2517330f729Sjoerg : SM.getIncludeLoc(SM.getFileID(Loc));
2527330f729Sjoerg }
2537330f729Sjoerg
2547330f729Sjoerg /// Return true if \c Loc is a location in a built-in macro.
isInBuiltin(SourceLocation Loc)2557330f729Sjoerg bool isInBuiltin(SourceLocation Loc) {
2567330f729Sjoerg return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>";
2577330f729Sjoerg }
2587330f729Sjoerg
2597330f729Sjoerg /// Check whether \c Loc is included or expanded from \c Parent.
isNestedIn(SourceLocation Loc,FileID Parent)2607330f729Sjoerg bool isNestedIn(SourceLocation Loc, FileID Parent) {
2617330f729Sjoerg do {
2627330f729Sjoerg Loc = getIncludeOrExpansionLoc(Loc);
2637330f729Sjoerg if (Loc.isInvalid())
2647330f729Sjoerg return false;
2657330f729Sjoerg } while (!SM.isInFileID(Loc, Parent));
2667330f729Sjoerg return true;
2677330f729Sjoerg }
2687330f729Sjoerg
2697330f729Sjoerg /// Get the start of \c S ignoring macro arguments and builtin macros.
getStart(const Stmt * S)2707330f729Sjoerg SourceLocation getStart(const Stmt *S) {
2717330f729Sjoerg SourceLocation Loc = S->getBeginLoc();
2727330f729Sjoerg while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
2737330f729Sjoerg Loc = SM.getImmediateExpansionRange(Loc).getBegin();
2747330f729Sjoerg return Loc;
2757330f729Sjoerg }
2767330f729Sjoerg
2777330f729Sjoerg /// Get the end of \c S ignoring macro arguments and builtin macros.
getEnd(const Stmt * S)2787330f729Sjoerg SourceLocation getEnd(const Stmt *S) {
2797330f729Sjoerg SourceLocation Loc = S->getEndLoc();
2807330f729Sjoerg while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc))
2817330f729Sjoerg Loc = SM.getImmediateExpansionRange(Loc).getBegin();
2827330f729Sjoerg return getPreciseTokenLocEnd(Loc);
2837330f729Sjoerg }
2847330f729Sjoerg
2857330f729Sjoerg /// Find the set of files we have regions for and assign IDs
2867330f729Sjoerg ///
2877330f729Sjoerg /// Fills \c Mapping with the virtual file mapping needed to write out
2887330f729Sjoerg /// coverage and collects the necessary file information to emit source and
2897330f729Sjoerg /// expansion regions.
gatherFileIDs(SmallVectorImpl<unsigned> & Mapping)2907330f729Sjoerg void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) {
2917330f729Sjoerg FileIDMapping.clear();
2927330f729Sjoerg
2937330f729Sjoerg llvm::SmallSet<FileID, 8> Visited;
2947330f729Sjoerg SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs;
2957330f729Sjoerg for (const auto &Region : SourceRegions) {
2967330f729Sjoerg SourceLocation Loc = Region.getBeginLoc();
2977330f729Sjoerg FileID File = SM.getFileID(Loc);
2987330f729Sjoerg if (!Visited.insert(File).second)
2997330f729Sjoerg continue;
3007330f729Sjoerg
3017330f729Sjoerg // Do not map FileID's associated with system headers.
3027330f729Sjoerg if (SM.isInSystemHeader(SM.getSpellingLoc(Loc)))
3037330f729Sjoerg continue;
3047330f729Sjoerg
3057330f729Sjoerg unsigned Depth = 0;
3067330f729Sjoerg for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc);
3077330f729Sjoerg Parent.isValid(); Parent = getIncludeOrExpansionLoc(Parent))
3087330f729Sjoerg ++Depth;
3097330f729Sjoerg FileLocs.push_back(std::make_pair(Loc, Depth));
3107330f729Sjoerg }
3117330f729Sjoerg llvm::stable_sort(FileLocs, llvm::less_second());
3127330f729Sjoerg
3137330f729Sjoerg for (const auto &FL : FileLocs) {
3147330f729Sjoerg SourceLocation Loc = FL.first;
3157330f729Sjoerg FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first;
3167330f729Sjoerg auto Entry = SM.getFileEntryForID(SpellingFile);
3177330f729Sjoerg if (!Entry)
3187330f729Sjoerg continue;
3197330f729Sjoerg
3207330f729Sjoerg FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc);
3217330f729Sjoerg Mapping.push_back(CVM.getFileID(Entry));
3227330f729Sjoerg }
3237330f729Sjoerg }
3247330f729Sjoerg
3257330f729Sjoerg /// Get the coverage mapping file ID for \c Loc.
3267330f729Sjoerg ///
3277330f729Sjoerg /// If such file id doesn't exist, return None.
getCoverageFileID(SourceLocation Loc)3287330f729Sjoerg Optional<unsigned> getCoverageFileID(SourceLocation Loc) {
3297330f729Sjoerg auto Mapping = FileIDMapping.find(SM.getFileID(Loc));
3307330f729Sjoerg if (Mapping != FileIDMapping.end())
3317330f729Sjoerg return Mapping->second.first;
3327330f729Sjoerg return None;
3337330f729Sjoerg }
3347330f729Sjoerg
335*e038c9c4Sjoerg /// This shrinks the skipped range if it spans a line that contains a
336*e038c9c4Sjoerg /// non-comment token. If shrinking the skipped range would make it empty,
337*e038c9c4Sjoerg /// this returns None.
adjustSkippedRange(SourceManager & SM,SourceLocation LocStart,SourceLocation LocEnd,SourceLocation PrevTokLoc,SourceLocation NextTokLoc)338*e038c9c4Sjoerg Optional<SpellingRegion> adjustSkippedRange(SourceManager &SM,
339*e038c9c4Sjoerg SourceLocation LocStart,
340*e038c9c4Sjoerg SourceLocation LocEnd,
341*e038c9c4Sjoerg SourceLocation PrevTokLoc,
342*e038c9c4Sjoerg SourceLocation NextTokLoc) {
343*e038c9c4Sjoerg SpellingRegion SR{SM, LocStart, LocEnd};
344*e038c9c4Sjoerg SR.ColumnStart = 1;
345*e038c9c4Sjoerg if (PrevTokLoc.isValid() && SM.isWrittenInSameFile(LocStart, PrevTokLoc) &&
346*e038c9c4Sjoerg SR.LineStart == SM.getSpellingLineNumber(PrevTokLoc))
347*e038c9c4Sjoerg SR.LineStart++;
348*e038c9c4Sjoerg if (NextTokLoc.isValid() && SM.isWrittenInSameFile(LocEnd, NextTokLoc) &&
349*e038c9c4Sjoerg SR.LineEnd == SM.getSpellingLineNumber(NextTokLoc)) {
350*e038c9c4Sjoerg SR.LineEnd--;
351*e038c9c4Sjoerg SR.ColumnEnd++;
352*e038c9c4Sjoerg }
353*e038c9c4Sjoerg if (SR.isInSourceOrder())
354*e038c9c4Sjoerg return SR;
355*e038c9c4Sjoerg return None;
356*e038c9c4Sjoerg }
357*e038c9c4Sjoerg
3587330f729Sjoerg /// Gather all the regions that were skipped by the preprocessor
359*e038c9c4Sjoerg /// using the constructs like #if or comments.
gatherSkippedRegions()3607330f729Sjoerg void gatherSkippedRegions() {
3617330f729Sjoerg /// An array of the minimum lineStarts and the maximum lineEnds
3627330f729Sjoerg /// for mapping regions from the appropriate source files.
3637330f729Sjoerg llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges;
3647330f729Sjoerg FileLineRanges.resize(
3657330f729Sjoerg FileIDMapping.size(),
3667330f729Sjoerg std::make_pair(std::numeric_limits<unsigned>::max(), 0));
3677330f729Sjoerg for (const auto &R : MappingRegions) {
3687330f729Sjoerg FileLineRanges[R.FileID].first =
3697330f729Sjoerg std::min(FileLineRanges[R.FileID].first, R.LineStart);
3707330f729Sjoerg FileLineRanges[R.FileID].second =
3717330f729Sjoerg std::max(FileLineRanges[R.FileID].second, R.LineEnd);
3727330f729Sjoerg }
3737330f729Sjoerg
3747330f729Sjoerg auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges();
375*e038c9c4Sjoerg for (auto &I : SkippedRanges) {
376*e038c9c4Sjoerg SourceRange Range = I.Range;
377*e038c9c4Sjoerg auto LocStart = Range.getBegin();
378*e038c9c4Sjoerg auto LocEnd = Range.getEnd();
3797330f729Sjoerg assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
3807330f729Sjoerg "region spans multiple files");
3817330f729Sjoerg
3827330f729Sjoerg auto CovFileID = getCoverageFileID(LocStart);
3837330f729Sjoerg if (!CovFileID)
3847330f729Sjoerg continue;
385*e038c9c4Sjoerg Optional<SpellingRegion> SR =
386*e038c9c4Sjoerg adjustSkippedRange(SM, LocStart, LocEnd, I.PrevTokLoc, I.NextTokLoc);
387*e038c9c4Sjoerg if (!SR.hasValue())
388*e038c9c4Sjoerg continue;
3897330f729Sjoerg auto Region = CounterMappingRegion::makeSkipped(
390*e038c9c4Sjoerg *CovFileID, SR->LineStart, SR->ColumnStart, SR->LineEnd,
391*e038c9c4Sjoerg SR->ColumnEnd);
3927330f729Sjoerg // Make sure that we only collect the regions that are inside
3937330f729Sjoerg // the source code of this function.
3947330f729Sjoerg if (Region.LineStart >= FileLineRanges[*CovFileID].first &&
3957330f729Sjoerg Region.LineEnd <= FileLineRanges[*CovFileID].second)
3967330f729Sjoerg MappingRegions.push_back(Region);
3977330f729Sjoerg }
3987330f729Sjoerg }
3997330f729Sjoerg
4007330f729Sjoerg /// Generate the coverage counter mapping regions from collected
4017330f729Sjoerg /// source regions.
emitSourceRegions(const SourceRegionFilter & Filter)4027330f729Sjoerg void emitSourceRegions(const SourceRegionFilter &Filter) {
4037330f729Sjoerg for (const auto &Region : SourceRegions) {
4047330f729Sjoerg assert(Region.hasEndLoc() && "incomplete region");
4057330f729Sjoerg
4067330f729Sjoerg SourceLocation LocStart = Region.getBeginLoc();
4077330f729Sjoerg assert(SM.getFileID(LocStart).isValid() && "region in invalid file");
4087330f729Sjoerg
4097330f729Sjoerg // Ignore regions from system headers.
4107330f729Sjoerg if (SM.isInSystemHeader(SM.getSpellingLoc(LocStart)))
4117330f729Sjoerg continue;
4127330f729Sjoerg
4137330f729Sjoerg auto CovFileID = getCoverageFileID(LocStart);
4147330f729Sjoerg // Ignore regions that don't have a file, such as builtin macros.
4157330f729Sjoerg if (!CovFileID)
4167330f729Sjoerg continue;
4177330f729Sjoerg
4187330f729Sjoerg SourceLocation LocEnd = Region.getEndLoc();
4197330f729Sjoerg assert(SM.isWrittenInSameFile(LocStart, LocEnd) &&
4207330f729Sjoerg "region spans multiple files");
4217330f729Sjoerg
4227330f729Sjoerg // Don't add code regions for the area covered by expansion regions.
4237330f729Sjoerg // This not only suppresses redundant regions, but sometimes prevents
4247330f729Sjoerg // creating regions with wrong counters if, for example, a statement's
4257330f729Sjoerg // body ends at the end of a nested macro.
4267330f729Sjoerg if (Filter.count(std::make_pair(LocStart, LocEnd)))
4277330f729Sjoerg continue;
4287330f729Sjoerg
4297330f729Sjoerg // Find the spelling locations for the mapping region.
4307330f729Sjoerg SpellingRegion SR{SM, LocStart, LocEnd};
4317330f729Sjoerg assert(SR.isInSourceOrder() && "region start and end out of order");
4327330f729Sjoerg
4337330f729Sjoerg if (Region.isGap()) {
4347330f729Sjoerg MappingRegions.push_back(CounterMappingRegion::makeGapRegion(
4357330f729Sjoerg Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
4367330f729Sjoerg SR.LineEnd, SR.ColumnEnd));
437*e038c9c4Sjoerg } else if (Region.isBranch()) {
438*e038c9c4Sjoerg MappingRegions.push_back(CounterMappingRegion::makeBranchRegion(
439*e038c9c4Sjoerg Region.getCounter(), Region.getFalseCounter(), *CovFileID,
440*e038c9c4Sjoerg SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd));
4417330f729Sjoerg } else {
4427330f729Sjoerg MappingRegions.push_back(CounterMappingRegion::makeRegion(
4437330f729Sjoerg Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart,
4447330f729Sjoerg SR.LineEnd, SR.ColumnEnd));
4457330f729Sjoerg }
4467330f729Sjoerg }
4477330f729Sjoerg }
4487330f729Sjoerg
4497330f729Sjoerg /// Generate expansion regions for each virtual file we've seen.
emitExpansionRegions()4507330f729Sjoerg SourceRegionFilter emitExpansionRegions() {
4517330f729Sjoerg SourceRegionFilter Filter;
4527330f729Sjoerg for (const auto &FM : FileIDMapping) {
4537330f729Sjoerg SourceLocation ExpandedLoc = FM.second.second;
4547330f729Sjoerg SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc);
4557330f729Sjoerg if (ParentLoc.isInvalid())
4567330f729Sjoerg continue;
4577330f729Sjoerg
4587330f729Sjoerg auto ParentFileID = getCoverageFileID(ParentLoc);
4597330f729Sjoerg if (!ParentFileID)
4607330f729Sjoerg continue;
4617330f729Sjoerg auto ExpandedFileID = getCoverageFileID(ExpandedLoc);
4627330f729Sjoerg assert(ExpandedFileID && "expansion in uncovered file");
4637330f729Sjoerg
4647330f729Sjoerg SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc);
4657330f729Sjoerg assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) &&
4667330f729Sjoerg "region spans multiple files");
4677330f729Sjoerg Filter.insert(std::make_pair(ParentLoc, LocEnd));
4687330f729Sjoerg
4697330f729Sjoerg SpellingRegion SR{SM, ParentLoc, LocEnd};
4707330f729Sjoerg assert(SR.isInSourceOrder() && "region start and end out of order");
4717330f729Sjoerg MappingRegions.push_back(CounterMappingRegion::makeExpansion(
4727330f729Sjoerg *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart,
4737330f729Sjoerg SR.LineEnd, SR.ColumnEnd));
4747330f729Sjoerg }
4757330f729Sjoerg return Filter;
4767330f729Sjoerg }
4777330f729Sjoerg };
4787330f729Sjoerg
4797330f729Sjoerg /// Creates unreachable coverage regions for the functions that
4807330f729Sjoerg /// are not emitted.
4817330f729Sjoerg struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {
EmptyCoverageMappingBuilder__anon8c3eb65b0211::EmptyCoverageMappingBuilder4827330f729Sjoerg EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,
4837330f729Sjoerg const LangOptions &LangOpts)
4847330f729Sjoerg : CoverageMappingBuilder(CVM, SM, LangOpts) {}
4857330f729Sjoerg
VisitDecl__anon8c3eb65b0211::EmptyCoverageMappingBuilder4867330f729Sjoerg void VisitDecl(const Decl *D) {
4877330f729Sjoerg if (!D->hasBody())
4887330f729Sjoerg return;
4897330f729Sjoerg auto Body = D->getBody();
4907330f729Sjoerg SourceLocation Start = getStart(Body);
4917330f729Sjoerg SourceLocation End = getEnd(Body);
4927330f729Sjoerg if (!SM.isWrittenInSameFile(Start, End)) {
4937330f729Sjoerg // Walk up to find the common ancestor.
4947330f729Sjoerg // Correct the locations accordingly.
4957330f729Sjoerg FileID StartFileID = SM.getFileID(Start);
4967330f729Sjoerg FileID EndFileID = SM.getFileID(End);
4977330f729Sjoerg while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) {
4987330f729Sjoerg Start = getIncludeOrExpansionLoc(Start);
4997330f729Sjoerg assert(Start.isValid() &&
5007330f729Sjoerg "Declaration start location not nested within a known region");
5017330f729Sjoerg StartFileID = SM.getFileID(Start);
5027330f729Sjoerg }
5037330f729Sjoerg while (StartFileID != EndFileID) {
5047330f729Sjoerg End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End));
5057330f729Sjoerg assert(End.isValid() &&
5067330f729Sjoerg "Declaration end location not nested within a known region");
5077330f729Sjoerg EndFileID = SM.getFileID(End);
5087330f729Sjoerg }
5097330f729Sjoerg }
5107330f729Sjoerg SourceRegions.emplace_back(Counter(), Start, End);
5117330f729Sjoerg }
5127330f729Sjoerg
5137330f729Sjoerg /// Write the mapping data to the output stream
write__anon8c3eb65b0211::EmptyCoverageMappingBuilder5147330f729Sjoerg void write(llvm::raw_ostream &OS) {
5157330f729Sjoerg SmallVector<unsigned, 16> FileIDMapping;
5167330f729Sjoerg gatherFileIDs(FileIDMapping);
5177330f729Sjoerg emitSourceRegions(SourceRegionFilter());
5187330f729Sjoerg
5197330f729Sjoerg if (MappingRegions.empty())
5207330f729Sjoerg return;
5217330f729Sjoerg
5227330f729Sjoerg CoverageMappingWriter Writer(FileIDMapping, None, MappingRegions);
5237330f729Sjoerg Writer.write(OS);
5247330f729Sjoerg }
5257330f729Sjoerg };
5267330f729Sjoerg
5277330f729Sjoerg /// A StmtVisitor that creates coverage mapping regions which map
5287330f729Sjoerg /// from the source code locations to the PGO counters.
5297330f729Sjoerg struct CounterCoverageMappingBuilder
5307330f729Sjoerg : public CoverageMappingBuilder,
5317330f729Sjoerg public ConstStmtVisitor<CounterCoverageMappingBuilder> {
5327330f729Sjoerg /// The map of statements to count values.
5337330f729Sjoerg llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
5347330f729Sjoerg
5357330f729Sjoerg /// A stack of currently live regions.
5367330f729Sjoerg std::vector<SourceMappingRegion> RegionStack;
5377330f729Sjoerg
5387330f729Sjoerg CounterExpressionBuilder Builder;
5397330f729Sjoerg
5407330f729Sjoerg /// A location in the most recently visited file or macro.
5417330f729Sjoerg ///
5427330f729Sjoerg /// This is used to adjust the active source regions appropriately when
5437330f729Sjoerg /// expressions cross file or macro boundaries.
5447330f729Sjoerg SourceLocation MostRecentLocation;
5457330f729Sjoerg
546*e038c9c4Sjoerg /// Whether the visitor at a terminate statement.
547*e038c9c4Sjoerg bool HasTerminateStmt = false;
548*e038c9c4Sjoerg
549*e038c9c4Sjoerg /// Gap region counter after terminate statement.
550*e038c9c4Sjoerg Counter GapRegionCounter;
5517330f729Sjoerg
5527330f729Sjoerg /// Return a counter for the subtraction of \c RHS from \c LHS
subtractCounters__anon8c3eb65b0211::CounterCoverageMappingBuilder5537330f729Sjoerg Counter subtractCounters(Counter LHS, Counter RHS) {
5547330f729Sjoerg return Builder.subtract(LHS, RHS);
5557330f729Sjoerg }
5567330f729Sjoerg
5577330f729Sjoerg /// Return a counter for the sum of \c LHS and \c RHS.
addCounters__anon8c3eb65b0211::CounterCoverageMappingBuilder5587330f729Sjoerg Counter addCounters(Counter LHS, Counter RHS) {
5597330f729Sjoerg return Builder.add(LHS, RHS);
5607330f729Sjoerg }
5617330f729Sjoerg
addCounters__anon8c3eb65b0211::CounterCoverageMappingBuilder5627330f729Sjoerg Counter addCounters(Counter C1, Counter C2, Counter C3) {
5637330f729Sjoerg return addCounters(addCounters(C1, C2), C3);
5647330f729Sjoerg }
5657330f729Sjoerg
5667330f729Sjoerg /// Return the region counter for the given statement.
5677330f729Sjoerg ///
5687330f729Sjoerg /// This should only be called on statements that have a dedicated counter.
getRegionCounter__anon8c3eb65b0211::CounterCoverageMappingBuilder5697330f729Sjoerg Counter getRegionCounter(const Stmt *S) {
5707330f729Sjoerg return Counter::getCounter(CounterMap[S]);
5717330f729Sjoerg }
5727330f729Sjoerg
5737330f729Sjoerg /// Push a region onto the stack.
5747330f729Sjoerg ///
5757330f729Sjoerg /// Returns the index on the stack where the region was pushed. This can be
5767330f729Sjoerg /// used with popRegions to exit a "scope", ending the region that was pushed.
pushRegion__anon8c3eb65b0211::CounterCoverageMappingBuilder5777330f729Sjoerg size_t pushRegion(Counter Count, Optional<SourceLocation> StartLoc = None,
578*e038c9c4Sjoerg Optional<SourceLocation> EndLoc = None,
579*e038c9c4Sjoerg Optional<Counter> FalseCount = None) {
580*e038c9c4Sjoerg
581*e038c9c4Sjoerg if (StartLoc && !FalseCount.hasValue()) {
5827330f729Sjoerg MostRecentLocation = *StartLoc;
5837330f729Sjoerg }
584*e038c9c4Sjoerg
585*e038c9c4Sjoerg RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc);
5867330f729Sjoerg
5877330f729Sjoerg return RegionStack.size() - 1;
5887330f729Sjoerg }
5897330f729Sjoerg
locationDepth__anon8c3eb65b0211::CounterCoverageMappingBuilder5907330f729Sjoerg size_t locationDepth(SourceLocation Loc) {
5917330f729Sjoerg size_t Depth = 0;
5927330f729Sjoerg while (Loc.isValid()) {
5937330f729Sjoerg Loc = getIncludeOrExpansionLoc(Loc);
5947330f729Sjoerg Depth++;
5957330f729Sjoerg }
5967330f729Sjoerg return Depth;
5977330f729Sjoerg }
5987330f729Sjoerg
5997330f729Sjoerg /// Pop regions from the stack into the function's list of regions.
6007330f729Sjoerg ///
6017330f729Sjoerg /// Adds all regions from \c ParentIndex to the top of the stack to the
6027330f729Sjoerg /// function's \c SourceRegions.
popRegions__anon8c3eb65b0211::CounterCoverageMappingBuilder6037330f729Sjoerg void popRegions(size_t ParentIndex) {
6047330f729Sjoerg assert(RegionStack.size() >= ParentIndex && "parent not in stack");
6057330f729Sjoerg while (RegionStack.size() > ParentIndex) {
6067330f729Sjoerg SourceMappingRegion &Region = RegionStack.back();
6077330f729Sjoerg if (Region.hasStartLoc()) {
6087330f729Sjoerg SourceLocation StartLoc = Region.getBeginLoc();
6097330f729Sjoerg SourceLocation EndLoc = Region.hasEndLoc()
6107330f729Sjoerg ? Region.getEndLoc()
6117330f729Sjoerg : RegionStack[ParentIndex].getEndLoc();
612*e038c9c4Sjoerg bool isBranch = Region.isBranch();
6137330f729Sjoerg size_t StartDepth = locationDepth(StartLoc);
6147330f729Sjoerg size_t EndDepth = locationDepth(EndLoc);
6157330f729Sjoerg while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) {
6167330f729Sjoerg bool UnnestStart = StartDepth >= EndDepth;
6177330f729Sjoerg bool UnnestEnd = EndDepth >= StartDepth;
6187330f729Sjoerg if (UnnestEnd) {
619*e038c9c4Sjoerg // The region ends in a nested file or macro expansion. If the
620*e038c9c4Sjoerg // region is not a branch region, create a separate region for each
621*e038c9c4Sjoerg // expansion, and for all regions, update the EndLoc. Branch
622*e038c9c4Sjoerg // regions should not be split in order to keep a straightforward
623*e038c9c4Sjoerg // correspondance between the region and its associated branch
624*e038c9c4Sjoerg // condition, even if the condition spans multiple depths.
6257330f729Sjoerg SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc);
6267330f729Sjoerg assert(SM.isWrittenInSameFile(NestedLoc, EndLoc));
6277330f729Sjoerg
628*e038c9c4Sjoerg if (!isBranch && !isRegionAlreadyAdded(NestedLoc, EndLoc))
629*e038c9c4Sjoerg SourceRegions.emplace_back(Region.getCounter(), NestedLoc,
630*e038c9c4Sjoerg EndLoc);
6317330f729Sjoerg
6327330f729Sjoerg EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc));
6337330f729Sjoerg if (EndLoc.isInvalid())
634*e038c9c4Sjoerg llvm::report_fatal_error(
635*e038c9c4Sjoerg "File exit not handled before popRegions");
6367330f729Sjoerg EndDepth--;
6377330f729Sjoerg }
6387330f729Sjoerg if (UnnestStart) {
639*e038c9c4Sjoerg // The region ends in a nested file or macro expansion. If the
640*e038c9c4Sjoerg // region is not a branch region, create a separate region for each
641*e038c9c4Sjoerg // expansion, and for all regions, update the StartLoc. Branch
642*e038c9c4Sjoerg // regions should not be split in order to keep a straightforward
643*e038c9c4Sjoerg // correspondance between the region and its associated branch
644*e038c9c4Sjoerg // condition, even if the condition spans multiple depths.
6457330f729Sjoerg SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc);
6467330f729Sjoerg assert(SM.isWrittenInSameFile(StartLoc, NestedLoc));
6477330f729Sjoerg
648*e038c9c4Sjoerg if (!isBranch && !isRegionAlreadyAdded(StartLoc, NestedLoc))
649*e038c9c4Sjoerg SourceRegions.emplace_back(Region.getCounter(), StartLoc,
650*e038c9c4Sjoerg NestedLoc);
6517330f729Sjoerg
6527330f729Sjoerg StartLoc = getIncludeOrExpansionLoc(StartLoc);
6537330f729Sjoerg if (StartLoc.isInvalid())
654*e038c9c4Sjoerg llvm::report_fatal_error(
655*e038c9c4Sjoerg "File exit not handled before popRegions");
6567330f729Sjoerg StartDepth--;
6577330f729Sjoerg }
6587330f729Sjoerg }
6597330f729Sjoerg Region.setStartLoc(StartLoc);
6607330f729Sjoerg Region.setEndLoc(EndLoc);
6617330f729Sjoerg
662*e038c9c4Sjoerg if (!isBranch) {
6637330f729Sjoerg MostRecentLocation = EndLoc;
664*e038c9c4Sjoerg // If this region happens to span an entire expansion, we need to
665*e038c9c4Sjoerg // make sure we don't overlap the parent region with it.
6667330f729Sjoerg if (StartLoc == getStartOfFileOrMacro(StartLoc) &&
6677330f729Sjoerg EndLoc == getEndOfFileOrMacro(EndLoc))
6687330f729Sjoerg MostRecentLocation = getIncludeOrExpansionLoc(EndLoc);
669*e038c9c4Sjoerg }
6707330f729Sjoerg
6717330f729Sjoerg assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
6727330f729Sjoerg assert(SpellingRegion(SM, Region).isInSourceOrder());
6737330f729Sjoerg SourceRegions.push_back(Region);
6747330f729Sjoerg }
6757330f729Sjoerg RegionStack.pop_back();
6767330f729Sjoerg }
6777330f729Sjoerg }
6787330f729Sjoerg
6797330f729Sjoerg /// Return the currently active region.
getRegion__anon8c3eb65b0211::CounterCoverageMappingBuilder6807330f729Sjoerg SourceMappingRegion &getRegion() {
6817330f729Sjoerg assert(!RegionStack.empty() && "statement has no region");
6827330f729Sjoerg return RegionStack.back();
6837330f729Sjoerg }
6847330f729Sjoerg
6857330f729Sjoerg /// Propagate counts through the children of \p S if \p VisitChildren is true.
6867330f729Sjoerg /// Otherwise, only emit a count for \p S itself.
propagateCounts__anon8c3eb65b0211::CounterCoverageMappingBuilder6877330f729Sjoerg Counter propagateCounts(Counter TopCount, const Stmt *S,
6887330f729Sjoerg bool VisitChildren = true) {
6897330f729Sjoerg SourceLocation StartLoc = getStart(S);
6907330f729Sjoerg SourceLocation EndLoc = getEnd(S);
6917330f729Sjoerg size_t Index = pushRegion(TopCount, StartLoc, EndLoc);
6927330f729Sjoerg if (VisitChildren)
6937330f729Sjoerg Visit(S);
6947330f729Sjoerg Counter ExitCount = getRegion().getCounter();
6957330f729Sjoerg popRegions(Index);
6967330f729Sjoerg
6977330f729Sjoerg // The statement may be spanned by an expansion. Make sure we handle a file
6987330f729Sjoerg // exit out of this expansion before moving to the next statement.
6997330f729Sjoerg if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc()))
7007330f729Sjoerg MostRecentLocation = EndLoc;
7017330f729Sjoerg
7027330f729Sjoerg return ExitCount;
7037330f729Sjoerg }
7047330f729Sjoerg
705*e038c9c4Sjoerg /// Determine whether the given condition can be constant folded.
ConditionFoldsToBool__anon8c3eb65b0211::CounterCoverageMappingBuilder706*e038c9c4Sjoerg bool ConditionFoldsToBool(const Expr *Cond) {
707*e038c9c4Sjoerg Expr::EvalResult Result;
708*e038c9c4Sjoerg return (Cond->EvaluateAsInt(Result, CVM.getCodeGenModule().getContext()));
709*e038c9c4Sjoerg }
710*e038c9c4Sjoerg
711*e038c9c4Sjoerg /// Create a Branch Region around an instrumentable condition for coverage
712*e038c9c4Sjoerg /// and add it to the function's SourceRegions. A branch region tracks a
713*e038c9c4Sjoerg /// "True" counter and a "False" counter for boolean expressions that
714*e038c9c4Sjoerg /// result in the generation of a branch.
createBranchRegion__anon8c3eb65b0211::CounterCoverageMappingBuilder715*e038c9c4Sjoerg void createBranchRegion(const Expr *C, Counter TrueCnt, Counter FalseCnt) {
716*e038c9c4Sjoerg // Check for NULL conditions.
717*e038c9c4Sjoerg if (!C)
718*e038c9c4Sjoerg return;
719*e038c9c4Sjoerg
720*e038c9c4Sjoerg // Ensure we are an instrumentable condition (i.e. no "&&" or "||"). Push
721*e038c9c4Sjoerg // region onto RegionStack but immediately pop it (which adds it to the
722*e038c9c4Sjoerg // function's SourceRegions) because it doesn't apply to any other source
723*e038c9c4Sjoerg // code other than the Condition.
724*e038c9c4Sjoerg if (CodeGenFunction::isInstrumentedCondition(C)) {
725*e038c9c4Sjoerg // If a condition can fold to true or false, the corresponding branch
726*e038c9c4Sjoerg // will be removed. Create a region with both counters hard-coded to
727*e038c9c4Sjoerg // zero. This allows us to visualize them in a special way.
728*e038c9c4Sjoerg // Alternatively, we can prevent any optimization done via
729*e038c9c4Sjoerg // constant-folding by ensuring that ConstantFoldsToSimpleInteger() in
730*e038c9c4Sjoerg // CodeGenFunction.c always returns false, but that is very heavy-handed.
731*e038c9c4Sjoerg if (ConditionFoldsToBool(C))
732*e038c9c4Sjoerg popRegions(pushRegion(Counter::getZero(), getStart(C), getEnd(C),
733*e038c9c4Sjoerg Counter::getZero()));
734*e038c9c4Sjoerg else
735*e038c9c4Sjoerg // Otherwise, create a region with the True counter and False counter.
736*e038c9c4Sjoerg popRegions(pushRegion(TrueCnt, getStart(C), getEnd(C), FalseCnt));
737*e038c9c4Sjoerg }
738*e038c9c4Sjoerg }
739*e038c9c4Sjoerg
740*e038c9c4Sjoerg /// Create a Branch Region around a SwitchCase for code coverage
741*e038c9c4Sjoerg /// and add it to the function's SourceRegions.
createSwitchCaseRegion__anon8c3eb65b0211::CounterCoverageMappingBuilder742*e038c9c4Sjoerg void createSwitchCaseRegion(const SwitchCase *SC, Counter TrueCnt,
743*e038c9c4Sjoerg Counter FalseCnt) {
744*e038c9c4Sjoerg // Push region onto RegionStack but immediately pop it (which adds it to
745*e038c9c4Sjoerg // the function's SourceRegions) because it doesn't apply to any other
746*e038c9c4Sjoerg // source other than the SwitchCase.
747*e038c9c4Sjoerg popRegions(pushRegion(TrueCnt, getStart(SC), SC->getColonLoc(), FalseCnt));
748*e038c9c4Sjoerg }
749*e038c9c4Sjoerg
7507330f729Sjoerg /// Check whether a region with bounds \c StartLoc and \c EndLoc
7517330f729Sjoerg /// is already added to \c SourceRegions.
isRegionAlreadyAdded__anon8c3eb65b0211::CounterCoverageMappingBuilder752*e038c9c4Sjoerg bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc,
753*e038c9c4Sjoerg bool isBranch = false) {
7547330f729Sjoerg return SourceRegions.rend() !=
7557330f729Sjoerg std::find_if(SourceRegions.rbegin(), SourceRegions.rend(),
7567330f729Sjoerg [&](const SourceMappingRegion &Region) {
7577330f729Sjoerg return Region.getBeginLoc() == StartLoc &&
758*e038c9c4Sjoerg Region.getEndLoc() == EndLoc &&
759*e038c9c4Sjoerg Region.isBranch() == isBranch;
7607330f729Sjoerg });
7617330f729Sjoerg }
7627330f729Sjoerg
7637330f729Sjoerg /// Adjust the most recently visited location to \c EndLoc.
7647330f729Sjoerg ///
7657330f729Sjoerg /// This should be used after visiting any statements in non-source order.
adjustForOutOfOrderTraversal__anon8c3eb65b0211::CounterCoverageMappingBuilder7667330f729Sjoerg void adjustForOutOfOrderTraversal(SourceLocation EndLoc) {
7677330f729Sjoerg MostRecentLocation = EndLoc;
7687330f729Sjoerg // The code region for a whole macro is created in handleFileExit() when
7697330f729Sjoerg // it detects exiting of the virtual file of that macro. If we visited
7707330f729Sjoerg // statements in non-source order, we might already have such a region
7717330f729Sjoerg // added, for example, if a body of a loop is divided among multiple
7727330f729Sjoerg // macros. Avoid adding duplicate regions in such case.
7737330f729Sjoerg if (getRegion().hasEndLoc() &&
7747330f729Sjoerg MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) &&
7757330f729Sjoerg isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation),
776*e038c9c4Sjoerg MostRecentLocation, getRegion().isBranch()))
7777330f729Sjoerg MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation);
7787330f729Sjoerg }
7797330f729Sjoerg
7807330f729Sjoerg /// Adjust regions and state when \c NewLoc exits a file.
7817330f729Sjoerg ///
7827330f729Sjoerg /// If moving from our most recently tracked location to \c NewLoc exits any
7837330f729Sjoerg /// files, this adjusts our current region stack and creates the file regions
7847330f729Sjoerg /// for the exited file.
handleFileExit__anon8c3eb65b0211::CounterCoverageMappingBuilder7857330f729Sjoerg void handleFileExit(SourceLocation NewLoc) {
7867330f729Sjoerg if (NewLoc.isInvalid() ||
7877330f729Sjoerg SM.isWrittenInSameFile(MostRecentLocation, NewLoc))
7887330f729Sjoerg return;
7897330f729Sjoerg
7907330f729Sjoerg // If NewLoc is not in a file that contains MostRecentLocation, walk up to
7917330f729Sjoerg // find the common ancestor.
7927330f729Sjoerg SourceLocation LCA = NewLoc;
7937330f729Sjoerg FileID ParentFile = SM.getFileID(LCA);
7947330f729Sjoerg while (!isNestedIn(MostRecentLocation, ParentFile)) {
7957330f729Sjoerg LCA = getIncludeOrExpansionLoc(LCA);
7967330f729Sjoerg if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) {
7977330f729Sjoerg // Since there isn't a common ancestor, no file was exited. We just need
7987330f729Sjoerg // to adjust our location to the new file.
7997330f729Sjoerg MostRecentLocation = NewLoc;
8007330f729Sjoerg return;
8017330f729Sjoerg }
8027330f729Sjoerg ParentFile = SM.getFileID(LCA);
8037330f729Sjoerg }
8047330f729Sjoerg
8057330f729Sjoerg llvm::SmallSet<SourceLocation, 8> StartLocs;
8067330f729Sjoerg Optional<Counter> ParentCounter;
8077330f729Sjoerg for (SourceMappingRegion &I : llvm::reverse(RegionStack)) {
8087330f729Sjoerg if (!I.hasStartLoc())
8097330f729Sjoerg continue;
8107330f729Sjoerg SourceLocation Loc = I.getBeginLoc();
8117330f729Sjoerg if (!isNestedIn(Loc, ParentFile)) {
8127330f729Sjoerg ParentCounter = I.getCounter();
8137330f729Sjoerg break;
8147330f729Sjoerg }
8157330f729Sjoerg
8167330f729Sjoerg while (!SM.isInFileID(Loc, ParentFile)) {
8177330f729Sjoerg // The most nested region for each start location is the one with the
8187330f729Sjoerg // correct count. We avoid creating redundant regions by stopping once
8197330f729Sjoerg // we've seen this region.
820*e038c9c4Sjoerg if (StartLocs.insert(Loc).second) {
821*e038c9c4Sjoerg if (I.isBranch())
822*e038c9c4Sjoerg SourceRegions.emplace_back(I.getCounter(), I.getFalseCounter(), Loc,
823*e038c9c4Sjoerg getEndOfFileOrMacro(Loc), I.isBranch());
824*e038c9c4Sjoerg else
8257330f729Sjoerg SourceRegions.emplace_back(I.getCounter(), Loc,
8267330f729Sjoerg getEndOfFileOrMacro(Loc));
827*e038c9c4Sjoerg }
8287330f729Sjoerg Loc = getIncludeOrExpansionLoc(Loc);
8297330f729Sjoerg }
8307330f729Sjoerg I.setStartLoc(getPreciseTokenLocEnd(Loc));
8317330f729Sjoerg }
8327330f729Sjoerg
8337330f729Sjoerg if (ParentCounter) {
8347330f729Sjoerg // If the file is contained completely by another region and doesn't
8357330f729Sjoerg // immediately start its own region, the whole file gets a region
8367330f729Sjoerg // corresponding to the parent.
8377330f729Sjoerg SourceLocation Loc = MostRecentLocation;
8387330f729Sjoerg while (isNestedIn(Loc, ParentFile)) {
8397330f729Sjoerg SourceLocation FileStart = getStartOfFileOrMacro(Loc);
8407330f729Sjoerg if (StartLocs.insert(FileStart).second) {
8417330f729Sjoerg SourceRegions.emplace_back(*ParentCounter, FileStart,
8427330f729Sjoerg getEndOfFileOrMacro(Loc));
8437330f729Sjoerg assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder());
8447330f729Sjoerg }
8457330f729Sjoerg Loc = getIncludeOrExpansionLoc(Loc);
8467330f729Sjoerg }
8477330f729Sjoerg }
8487330f729Sjoerg
8497330f729Sjoerg MostRecentLocation = NewLoc;
8507330f729Sjoerg }
8517330f729Sjoerg
8527330f729Sjoerg /// Ensure that \c S is included in the current region.
extendRegion__anon8c3eb65b0211::CounterCoverageMappingBuilder8537330f729Sjoerg void extendRegion(const Stmt *S) {
8547330f729Sjoerg SourceMappingRegion &Region = getRegion();
8557330f729Sjoerg SourceLocation StartLoc = getStart(S);
8567330f729Sjoerg
8577330f729Sjoerg handleFileExit(StartLoc);
8587330f729Sjoerg if (!Region.hasStartLoc())
8597330f729Sjoerg Region.setStartLoc(StartLoc);
8607330f729Sjoerg }
8617330f729Sjoerg
8627330f729Sjoerg /// Mark \c S as a terminator, starting a zero region.
terminateRegion__anon8c3eb65b0211::CounterCoverageMappingBuilder8637330f729Sjoerg void terminateRegion(const Stmt *S) {
8647330f729Sjoerg extendRegion(S);
8657330f729Sjoerg SourceMappingRegion &Region = getRegion();
8667330f729Sjoerg SourceLocation EndLoc = getEnd(S);
8677330f729Sjoerg if (!Region.hasEndLoc())
8687330f729Sjoerg Region.setEndLoc(EndLoc);
8697330f729Sjoerg pushRegion(Counter::getZero());
870*e038c9c4Sjoerg HasTerminateStmt = true;
8717330f729Sjoerg }
8727330f729Sjoerg
8737330f729Sjoerg /// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
findGapAreaBetween__anon8c3eb65b0211::CounterCoverageMappingBuilder8747330f729Sjoerg Optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
8757330f729Sjoerg SourceLocation BeforeLoc) {
876*e038c9c4Sjoerg // If AfterLoc is in function-like macro, use the right parenthesis
877*e038c9c4Sjoerg // location.
878*e038c9c4Sjoerg if (AfterLoc.isMacroID()) {
879*e038c9c4Sjoerg FileID FID = SM.getFileID(AfterLoc);
880*e038c9c4Sjoerg const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion();
881*e038c9c4Sjoerg if (EI->isFunctionMacroExpansion())
882*e038c9c4Sjoerg AfterLoc = EI->getExpansionLocEnd();
883*e038c9c4Sjoerg }
884*e038c9c4Sjoerg
885*e038c9c4Sjoerg size_t StartDepth = locationDepth(AfterLoc);
886*e038c9c4Sjoerg size_t EndDepth = locationDepth(BeforeLoc);
887*e038c9c4Sjoerg while (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
888*e038c9c4Sjoerg bool UnnestStart = StartDepth >= EndDepth;
889*e038c9c4Sjoerg bool UnnestEnd = EndDepth >= StartDepth;
890*e038c9c4Sjoerg if (UnnestEnd) {
891*e038c9c4Sjoerg assert(SM.isWrittenInSameFile(getStartOfFileOrMacro(BeforeLoc),
892*e038c9c4Sjoerg BeforeLoc));
893*e038c9c4Sjoerg
894*e038c9c4Sjoerg BeforeLoc = getIncludeOrExpansionLoc(BeforeLoc);
895*e038c9c4Sjoerg assert(BeforeLoc.isValid());
896*e038c9c4Sjoerg EndDepth--;
897*e038c9c4Sjoerg }
898*e038c9c4Sjoerg if (UnnestStart) {
899*e038c9c4Sjoerg assert(SM.isWrittenInSameFile(AfterLoc,
900*e038c9c4Sjoerg getEndOfFileOrMacro(AfterLoc)));
901*e038c9c4Sjoerg
902*e038c9c4Sjoerg AfterLoc = getIncludeOrExpansionLoc(AfterLoc);
903*e038c9c4Sjoerg assert(AfterLoc.isValid());
904*e038c9c4Sjoerg AfterLoc = getPreciseTokenLocEnd(AfterLoc);
905*e038c9c4Sjoerg assert(AfterLoc.isValid());
906*e038c9c4Sjoerg StartDepth--;
907*e038c9c4Sjoerg }
908*e038c9c4Sjoerg }
909*e038c9c4Sjoerg AfterLoc = getPreciseTokenLocEnd(AfterLoc);
9107330f729Sjoerg // If the start and end locations of the gap are both within the same macro
9117330f729Sjoerg // file, the range may not be in source order.
9127330f729Sjoerg if (AfterLoc.isMacroID() || BeforeLoc.isMacroID())
9137330f729Sjoerg return None;
914*e038c9c4Sjoerg if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc) ||
915*e038c9c4Sjoerg !SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder())
9167330f729Sjoerg return None;
9177330f729Sjoerg return {{AfterLoc, BeforeLoc}};
9187330f729Sjoerg }
9197330f729Sjoerg
9207330f729Sjoerg /// Emit a gap region between \p StartLoc and \p EndLoc with the given count.
fillGapAreaWithCount__anon8c3eb65b0211::CounterCoverageMappingBuilder9217330f729Sjoerg void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc,
9227330f729Sjoerg Counter Count) {
9237330f729Sjoerg if (StartLoc == EndLoc)
9247330f729Sjoerg return;
9257330f729Sjoerg assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder());
9267330f729Sjoerg handleFileExit(StartLoc);
9277330f729Sjoerg size_t Index = pushRegion(Count, StartLoc, EndLoc);
9287330f729Sjoerg getRegion().setGap(true);
9297330f729Sjoerg handleFileExit(EndLoc);
9307330f729Sjoerg popRegions(Index);
9317330f729Sjoerg }
9327330f729Sjoerg
9337330f729Sjoerg /// Keep counts of breaks and continues inside loops.
9347330f729Sjoerg struct BreakContinue {
9357330f729Sjoerg Counter BreakCount;
9367330f729Sjoerg Counter ContinueCount;
9377330f729Sjoerg };
9387330f729Sjoerg SmallVector<BreakContinue, 8> BreakContinueStack;
9397330f729Sjoerg
CounterCoverageMappingBuilder__anon8c3eb65b0211::CounterCoverageMappingBuilder9407330f729Sjoerg CounterCoverageMappingBuilder(
9417330f729Sjoerg CoverageMappingModuleGen &CVM,
9427330f729Sjoerg llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM,
9437330f729Sjoerg const LangOptions &LangOpts)
944*e038c9c4Sjoerg : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {}
9457330f729Sjoerg
9467330f729Sjoerg /// Write the mapping data to the output stream
write__anon8c3eb65b0211::CounterCoverageMappingBuilder9477330f729Sjoerg void write(llvm::raw_ostream &OS) {
9487330f729Sjoerg llvm::SmallVector<unsigned, 8> VirtualFileMapping;
9497330f729Sjoerg gatherFileIDs(VirtualFileMapping);
9507330f729Sjoerg SourceRegionFilter Filter = emitExpansionRegions();
9517330f729Sjoerg emitSourceRegions(Filter);
9527330f729Sjoerg gatherSkippedRegions();
9537330f729Sjoerg
9547330f729Sjoerg if (MappingRegions.empty())
9557330f729Sjoerg return;
9567330f729Sjoerg
9577330f729Sjoerg CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(),
9587330f729Sjoerg MappingRegions);
9597330f729Sjoerg Writer.write(OS);
9607330f729Sjoerg }
9617330f729Sjoerg
VisitStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder9627330f729Sjoerg void VisitStmt(const Stmt *S) {
9637330f729Sjoerg if (S->getBeginLoc().isValid())
9647330f729Sjoerg extendRegion(S);
965*e038c9c4Sjoerg const Stmt *LastStmt = nullptr;
966*e038c9c4Sjoerg bool SaveTerminateStmt = HasTerminateStmt;
967*e038c9c4Sjoerg HasTerminateStmt = false;
968*e038c9c4Sjoerg GapRegionCounter = Counter::getZero();
9697330f729Sjoerg for (const Stmt *Child : S->children())
970*e038c9c4Sjoerg if (Child) {
971*e038c9c4Sjoerg // If last statement contains terminate statements, add a gap area
972*e038c9c4Sjoerg // between the two statements. Skipping attributed statements, because
973*e038c9c4Sjoerg // they don't have valid start location.
974*e038c9c4Sjoerg if (LastStmt && HasTerminateStmt && !dyn_cast<AttributedStmt>(Child)) {
975*e038c9c4Sjoerg auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
976*e038c9c4Sjoerg if (Gap)
977*e038c9c4Sjoerg fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
978*e038c9c4Sjoerg GapRegionCounter);
979*e038c9c4Sjoerg SaveTerminateStmt = true;
980*e038c9c4Sjoerg HasTerminateStmt = false;
981*e038c9c4Sjoerg }
9827330f729Sjoerg this->Visit(Child);
983*e038c9c4Sjoerg LastStmt = Child;
984*e038c9c4Sjoerg }
985*e038c9c4Sjoerg if (SaveTerminateStmt)
986*e038c9c4Sjoerg HasTerminateStmt = true;
9877330f729Sjoerg handleFileExit(getEnd(S));
9887330f729Sjoerg }
9897330f729Sjoerg
VisitDecl__anon8c3eb65b0211::CounterCoverageMappingBuilder9907330f729Sjoerg void VisitDecl(const Decl *D) {
9917330f729Sjoerg Stmt *Body = D->getBody();
9927330f729Sjoerg
9937330f729Sjoerg // Do not propagate region counts into system headers.
9947330f729Sjoerg if (Body && SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body))))
9957330f729Sjoerg return;
9967330f729Sjoerg
9977330f729Sjoerg // Do not visit the artificial children nodes of defaulted methods. The
9987330f729Sjoerg // lexer may not be able to report back precise token end locations for
9997330f729Sjoerg // these children nodes (llvm.org/PR39822), and moreover users will not be
10007330f729Sjoerg // able to see coverage for them.
10017330f729Sjoerg bool Defaulted = false;
10027330f729Sjoerg if (auto *Method = dyn_cast<CXXMethodDecl>(D))
10037330f729Sjoerg Defaulted = Method->isDefaulted();
10047330f729Sjoerg
10057330f729Sjoerg propagateCounts(getRegionCounter(Body), Body,
10067330f729Sjoerg /*VisitChildren=*/!Defaulted);
10077330f729Sjoerg assert(RegionStack.empty() && "Regions entered but never exited");
10087330f729Sjoerg }
10097330f729Sjoerg
VisitReturnStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder10107330f729Sjoerg void VisitReturnStmt(const ReturnStmt *S) {
10117330f729Sjoerg extendRegion(S);
10127330f729Sjoerg if (S->getRetValue())
10137330f729Sjoerg Visit(S->getRetValue());
10147330f729Sjoerg terminateRegion(S);
10157330f729Sjoerg }
10167330f729Sjoerg
VisitCoroutineBodyStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder1017*e038c9c4Sjoerg void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
1018*e038c9c4Sjoerg extendRegion(S);
1019*e038c9c4Sjoerg Visit(S->getBody());
1020*e038c9c4Sjoerg }
1021*e038c9c4Sjoerg
VisitCoreturnStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder1022*e038c9c4Sjoerg void VisitCoreturnStmt(const CoreturnStmt *S) {
1023*e038c9c4Sjoerg extendRegion(S);
1024*e038c9c4Sjoerg if (S->getOperand())
1025*e038c9c4Sjoerg Visit(S->getOperand());
1026*e038c9c4Sjoerg terminateRegion(S);
1027*e038c9c4Sjoerg }
1028*e038c9c4Sjoerg
VisitCXXThrowExpr__anon8c3eb65b0211::CounterCoverageMappingBuilder10297330f729Sjoerg void VisitCXXThrowExpr(const CXXThrowExpr *E) {
10307330f729Sjoerg extendRegion(E);
10317330f729Sjoerg if (E->getSubExpr())
10327330f729Sjoerg Visit(E->getSubExpr());
10337330f729Sjoerg terminateRegion(E);
10347330f729Sjoerg }
10357330f729Sjoerg
VisitGotoStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder10367330f729Sjoerg void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); }
10377330f729Sjoerg
VisitLabelStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder10387330f729Sjoerg void VisitLabelStmt(const LabelStmt *S) {
10397330f729Sjoerg Counter LabelCount = getRegionCounter(S);
10407330f729Sjoerg SourceLocation Start = getStart(S);
10417330f729Sjoerg // We can't extendRegion here or we risk overlapping with our new region.
10427330f729Sjoerg handleFileExit(Start);
10437330f729Sjoerg pushRegion(LabelCount, Start);
10447330f729Sjoerg Visit(S->getSubStmt());
10457330f729Sjoerg }
10467330f729Sjoerg
VisitBreakStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder10477330f729Sjoerg void VisitBreakStmt(const BreakStmt *S) {
10487330f729Sjoerg assert(!BreakContinueStack.empty() && "break not in a loop or switch!");
10497330f729Sjoerg BreakContinueStack.back().BreakCount = addCounters(
10507330f729Sjoerg BreakContinueStack.back().BreakCount, getRegion().getCounter());
10517330f729Sjoerg // FIXME: a break in a switch should terminate regions for all preceding
10527330f729Sjoerg // case statements, not just the most recent one.
10537330f729Sjoerg terminateRegion(S);
10547330f729Sjoerg }
10557330f729Sjoerg
VisitContinueStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder10567330f729Sjoerg void VisitContinueStmt(const ContinueStmt *S) {
10577330f729Sjoerg assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
10587330f729Sjoerg BreakContinueStack.back().ContinueCount = addCounters(
10597330f729Sjoerg BreakContinueStack.back().ContinueCount, getRegion().getCounter());
10607330f729Sjoerg terminateRegion(S);
10617330f729Sjoerg }
10627330f729Sjoerg
VisitCallExpr__anon8c3eb65b0211::CounterCoverageMappingBuilder10637330f729Sjoerg void VisitCallExpr(const CallExpr *E) {
10647330f729Sjoerg VisitStmt(E);
10657330f729Sjoerg
10667330f729Sjoerg // Terminate the region when we hit a noreturn function.
10677330f729Sjoerg // (This is helpful dealing with switch statements.)
10687330f729Sjoerg QualType CalleeType = E->getCallee()->getType();
10697330f729Sjoerg if (getFunctionExtInfo(*CalleeType).getNoReturn())
10707330f729Sjoerg terminateRegion(E);
10717330f729Sjoerg }
10727330f729Sjoerg
VisitWhileStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder10737330f729Sjoerg void VisitWhileStmt(const WhileStmt *S) {
10747330f729Sjoerg extendRegion(S);
10757330f729Sjoerg
10767330f729Sjoerg Counter ParentCount = getRegion().getCounter();
10777330f729Sjoerg Counter BodyCount = getRegionCounter(S);
10787330f729Sjoerg
10797330f729Sjoerg // Handle the body first so that we can get the backedge count.
10807330f729Sjoerg BreakContinueStack.push_back(BreakContinue());
10817330f729Sjoerg extendRegion(S->getBody());
10827330f729Sjoerg Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
10837330f729Sjoerg BreakContinue BC = BreakContinueStack.pop_back_val();
10847330f729Sjoerg
1085*e038c9c4Sjoerg bool BodyHasTerminateStmt = HasTerminateStmt;
1086*e038c9c4Sjoerg HasTerminateStmt = false;
1087*e038c9c4Sjoerg
10887330f729Sjoerg // Go back to handle the condition.
10897330f729Sjoerg Counter CondCount =
10907330f729Sjoerg addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
10917330f729Sjoerg propagateCounts(CondCount, S->getCond());
10927330f729Sjoerg adjustForOutOfOrderTraversal(getEnd(S));
10937330f729Sjoerg
10947330f729Sjoerg // The body count applies to the area immediately after the increment.
1095*e038c9c4Sjoerg auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
10967330f729Sjoerg if (Gap)
10977330f729Sjoerg fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
10987330f729Sjoerg
10997330f729Sjoerg Counter OutCount =
11007330f729Sjoerg addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1101*e038c9c4Sjoerg if (OutCount != ParentCount) {
11027330f729Sjoerg pushRegion(OutCount);
1103*e038c9c4Sjoerg GapRegionCounter = OutCount;
1104*e038c9c4Sjoerg if (BodyHasTerminateStmt)
1105*e038c9c4Sjoerg HasTerminateStmt = true;
1106*e038c9c4Sjoerg }
1107*e038c9c4Sjoerg
1108*e038c9c4Sjoerg // Create Branch Region around condition.
1109*e038c9c4Sjoerg createBranchRegion(S->getCond(), BodyCount,
1110*e038c9c4Sjoerg subtractCounters(CondCount, BodyCount));
11117330f729Sjoerg }
11127330f729Sjoerg
VisitDoStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder11137330f729Sjoerg void VisitDoStmt(const DoStmt *S) {
11147330f729Sjoerg extendRegion(S);
11157330f729Sjoerg
11167330f729Sjoerg Counter ParentCount = getRegion().getCounter();
11177330f729Sjoerg Counter BodyCount = getRegionCounter(S);
11187330f729Sjoerg
11197330f729Sjoerg BreakContinueStack.push_back(BreakContinue());
11207330f729Sjoerg extendRegion(S->getBody());
11217330f729Sjoerg Counter BackedgeCount =
11227330f729Sjoerg propagateCounts(addCounters(ParentCount, BodyCount), S->getBody());
11237330f729Sjoerg BreakContinue BC = BreakContinueStack.pop_back_val();
11247330f729Sjoerg
1125*e038c9c4Sjoerg bool BodyHasTerminateStmt = HasTerminateStmt;
1126*e038c9c4Sjoerg HasTerminateStmt = false;
1127*e038c9c4Sjoerg
11287330f729Sjoerg Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount);
11297330f729Sjoerg propagateCounts(CondCount, S->getCond());
11307330f729Sjoerg
11317330f729Sjoerg Counter OutCount =
11327330f729Sjoerg addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
1133*e038c9c4Sjoerg if (OutCount != ParentCount) {
11347330f729Sjoerg pushRegion(OutCount);
1135*e038c9c4Sjoerg GapRegionCounter = OutCount;
1136*e038c9c4Sjoerg }
1137*e038c9c4Sjoerg
1138*e038c9c4Sjoerg // Create Branch Region around condition.
1139*e038c9c4Sjoerg createBranchRegion(S->getCond(), BodyCount,
1140*e038c9c4Sjoerg subtractCounters(CondCount, BodyCount));
1141*e038c9c4Sjoerg
1142*e038c9c4Sjoerg if (BodyHasTerminateStmt)
1143*e038c9c4Sjoerg HasTerminateStmt = true;
11447330f729Sjoerg }
11457330f729Sjoerg
VisitForStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder11467330f729Sjoerg void VisitForStmt(const ForStmt *S) {
11477330f729Sjoerg extendRegion(S);
11487330f729Sjoerg if (S->getInit())
11497330f729Sjoerg Visit(S->getInit());
11507330f729Sjoerg
11517330f729Sjoerg Counter ParentCount = getRegion().getCounter();
11527330f729Sjoerg Counter BodyCount = getRegionCounter(S);
11537330f729Sjoerg
11547330f729Sjoerg // The loop increment may contain a break or continue.
11557330f729Sjoerg if (S->getInc())
11567330f729Sjoerg BreakContinueStack.emplace_back();
11577330f729Sjoerg
11587330f729Sjoerg // Handle the body first so that we can get the backedge count.
11597330f729Sjoerg BreakContinueStack.emplace_back();
11607330f729Sjoerg extendRegion(S->getBody());
11617330f729Sjoerg Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
11627330f729Sjoerg BreakContinue BodyBC = BreakContinueStack.pop_back_val();
11637330f729Sjoerg
1164*e038c9c4Sjoerg bool BodyHasTerminateStmt = HasTerminateStmt;
1165*e038c9c4Sjoerg HasTerminateStmt = false;
1166*e038c9c4Sjoerg
11677330f729Sjoerg // The increment is essentially part of the body but it needs to include
11687330f729Sjoerg // the count for all the continue statements.
11697330f729Sjoerg BreakContinue IncrementBC;
11707330f729Sjoerg if (const Stmt *Inc = S->getInc()) {
11717330f729Sjoerg propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc);
11727330f729Sjoerg IncrementBC = BreakContinueStack.pop_back_val();
11737330f729Sjoerg }
11747330f729Sjoerg
11757330f729Sjoerg // Go back to handle the condition.
11767330f729Sjoerg Counter CondCount = addCounters(
11777330f729Sjoerg addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount),
11787330f729Sjoerg IncrementBC.ContinueCount);
11797330f729Sjoerg if (const Expr *Cond = S->getCond()) {
11807330f729Sjoerg propagateCounts(CondCount, Cond);
11817330f729Sjoerg adjustForOutOfOrderTraversal(getEnd(S));
11827330f729Sjoerg }
11837330f729Sjoerg
11847330f729Sjoerg // The body count applies to the area immediately after the increment.
1185*e038c9c4Sjoerg auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
11867330f729Sjoerg if (Gap)
11877330f729Sjoerg fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
11887330f729Sjoerg
11897330f729Sjoerg Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
11907330f729Sjoerg subtractCounters(CondCount, BodyCount));
1191*e038c9c4Sjoerg if (OutCount != ParentCount) {
11927330f729Sjoerg pushRegion(OutCount);
1193*e038c9c4Sjoerg GapRegionCounter = OutCount;
1194*e038c9c4Sjoerg if (BodyHasTerminateStmt)
1195*e038c9c4Sjoerg HasTerminateStmt = true;
1196*e038c9c4Sjoerg }
1197*e038c9c4Sjoerg
1198*e038c9c4Sjoerg // Create Branch Region around condition.
1199*e038c9c4Sjoerg createBranchRegion(S->getCond(), BodyCount,
1200*e038c9c4Sjoerg subtractCounters(CondCount, BodyCount));
12017330f729Sjoerg }
12027330f729Sjoerg
VisitCXXForRangeStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder12037330f729Sjoerg void VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
12047330f729Sjoerg extendRegion(S);
12057330f729Sjoerg if (S->getInit())
12067330f729Sjoerg Visit(S->getInit());
12077330f729Sjoerg Visit(S->getLoopVarStmt());
12087330f729Sjoerg Visit(S->getRangeStmt());
12097330f729Sjoerg
12107330f729Sjoerg Counter ParentCount = getRegion().getCounter();
12117330f729Sjoerg Counter BodyCount = getRegionCounter(S);
12127330f729Sjoerg
12137330f729Sjoerg BreakContinueStack.push_back(BreakContinue());
12147330f729Sjoerg extendRegion(S->getBody());
12157330f729Sjoerg Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
12167330f729Sjoerg BreakContinue BC = BreakContinueStack.pop_back_val();
12177330f729Sjoerg
1218*e038c9c4Sjoerg bool BodyHasTerminateStmt = HasTerminateStmt;
1219*e038c9c4Sjoerg HasTerminateStmt = false;
1220*e038c9c4Sjoerg
12217330f729Sjoerg // The body count applies to the area immediately after the range.
1222*e038c9c4Sjoerg auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
12237330f729Sjoerg if (Gap)
12247330f729Sjoerg fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
12257330f729Sjoerg
12267330f729Sjoerg Counter LoopCount =
12277330f729Sjoerg addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
12287330f729Sjoerg Counter OutCount =
12297330f729Sjoerg addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1230*e038c9c4Sjoerg if (OutCount != ParentCount) {
12317330f729Sjoerg pushRegion(OutCount);
1232*e038c9c4Sjoerg GapRegionCounter = OutCount;
1233*e038c9c4Sjoerg if (BodyHasTerminateStmt)
1234*e038c9c4Sjoerg HasTerminateStmt = true;
1235*e038c9c4Sjoerg }
1236*e038c9c4Sjoerg
1237*e038c9c4Sjoerg // Create Branch Region around condition.
1238*e038c9c4Sjoerg createBranchRegion(S->getCond(), BodyCount,
1239*e038c9c4Sjoerg subtractCounters(LoopCount, BodyCount));
12407330f729Sjoerg }
12417330f729Sjoerg
VisitObjCForCollectionStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder12427330f729Sjoerg void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
12437330f729Sjoerg extendRegion(S);
12447330f729Sjoerg Visit(S->getElement());
12457330f729Sjoerg
12467330f729Sjoerg Counter ParentCount = getRegion().getCounter();
12477330f729Sjoerg Counter BodyCount = getRegionCounter(S);
12487330f729Sjoerg
12497330f729Sjoerg BreakContinueStack.push_back(BreakContinue());
12507330f729Sjoerg extendRegion(S->getBody());
12517330f729Sjoerg Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());
12527330f729Sjoerg BreakContinue BC = BreakContinueStack.pop_back_val();
12537330f729Sjoerg
12547330f729Sjoerg // The body count applies to the area immediately after the collection.
1255*e038c9c4Sjoerg auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody()));
12567330f729Sjoerg if (Gap)
12577330f729Sjoerg fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount);
12587330f729Sjoerg
12597330f729Sjoerg Counter LoopCount =
12607330f729Sjoerg addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
12617330f729Sjoerg Counter OutCount =
12627330f729Sjoerg addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
1263*e038c9c4Sjoerg if (OutCount != ParentCount) {
12647330f729Sjoerg pushRegion(OutCount);
1265*e038c9c4Sjoerg GapRegionCounter = OutCount;
1266*e038c9c4Sjoerg }
12677330f729Sjoerg }
12687330f729Sjoerg
VisitSwitchStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder12697330f729Sjoerg void VisitSwitchStmt(const SwitchStmt *S) {
12707330f729Sjoerg extendRegion(S);
12717330f729Sjoerg if (S->getInit())
12727330f729Sjoerg Visit(S->getInit());
12737330f729Sjoerg Visit(S->getCond());
12747330f729Sjoerg
12757330f729Sjoerg BreakContinueStack.push_back(BreakContinue());
12767330f729Sjoerg
12777330f729Sjoerg const Stmt *Body = S->getBody();
12787330f729Sjoerg extendRegion(Body);
12797330f729Sjoerg if (const auto *CS = dyn_cast<CompoundStmt>(Body)) {
12807330f729Sjoerg if (!CS->body_empty()) {
12817330f729Sjoerg // Make a region for the body of the switch. If the body starts with
12827330f729Sjoerg // a case, that case will reuse this region; otherwise, this covers
12837330f729Sjoerg // the unreachable code at the beginning of the switch body.
1284*e038c9c4Sjoerg size_t Index = pushRegion(Counter::getZero(), getStart(CS));
1285*e038c9c4Sjoerg getRegion().setGap(true);
1286*e038c9c4Sjoerg Visit(Body);
12877330f729Sjoerg
12887330f729Sjoerg // Set the end for the body of the switch, if it isn't already set.
12897330f729Sjoerg for (size_t i = RegionStack.size(); i != Index; --i) {
12907330f729Sjoerg if (!RegionStack[i - 1].hasEndLoc())
12917330f729Sjoerg RegionStack[i - 1].setEndLoc(getEnd(CS->body_back()));
12927330f729Sjoerg }
12937330f729Sjoerg
12947330f729Sjoerg popRegions(Index);
12957330f729Sjoerg }
12967330f729Sjoerg } else
12977330f729Sjoerg propagateCounts(Counter::getZero(), Body);
12987330f729Sjoerg BreakContinue BC = BreakContinueStack.pop_back_val();
12997330f729Sjoerg
13007330f729Sjoerg if (!BreakContinueStack.empty())
13017330f729Sjoerg BreakContinueStack.back().ContinueCount = addCounters(
13027330f729Sjoerg BreakContinueStack.back().ContinueCount, BC.ContinueCount);
13037330f729Sjoerg
1304*e038c9c4Sjoerg Counter ParentCount = getRegion().getCounter();
13057330f729Sjoerg Counter ExitCount = getRegionCounter(S);
13067330f729Sjoerg SourceLocation ExitLoc = getEnd(S);
13077330f729Sjoerg pushRegion(ExitCount);
1308*e038c9c4Sjoerg GapRegionCounter = ExitCount;
13097330f729Sjoerg
13107330f729Sjoerg // Ensure that handleFileExit recognizes when the end location is located
13117330f729Sjoerg // in a different file.
13127330f729Sjoerg MostRecentLocation = getStart(S);
13137330f729Sjoerg handleFileExit(ExitLoc);
1314*e038c9c4Sjoerg
1315*e038c9c4Sjoerg // Create a Branch Region around each Case. Subtract the case's
1316*e038c9c4Sjoerg // counter from the Parent counter to track the "False" branch count.
1317*e038c9c4Sjoerg Counter CaseCountSum;
1318*e038c9c4Sjoerg bool HasDefaultCase = false;
1319*e038c9c4Sjoerg const SwitchCase *Case = S->getSwitchCaseList();
1320*e038c9c4Sjoerg for (; Case; Case = Case->getNextSwitchCase()) {
1321*e038c9c4Sjoerg HasDefaultCase = HasDefaultCase || isa<DefaultStmt>(Case);
1322*e038c9c4Sjoerg CaseCountSum = addCounters(CaseCountSum, getRegionCounter(Case));
1323*e038c9c4Sjoerg createSwitchCaseRegion(
1324*e038c9c4Sjoerg Case, getRegionCounter(Case),
1325*e038c9c4Sjoerg subtractCounters(ParentCount, getRegionCounter(Case)));
1326*e038c9c4Sjoerg }
1327*e038c9c4Sjoerg
1328*e038c9c4Sjoerg // If no explicit default case exists, create a branch region to represent
1329*e038c9c4Sjoerg // the hidden branch, which will be added later by the CodeGen. This region
1330*e038c9c4Sjoerg // will be associated with the switch statement's condition.
1331*e038c9c4Sjoerg if (!HasDefaultCase) {
1332*e038c9c4Sjoerg Counter DefaultTrue = subtractCounters(ParentCount, CaseCountSum);
1333*e038c9c4Sjoerg Counter DefaultFalse = subtractCounters(ParentCount, DefaultTrue);
1334*e038c9c4Sjoerg createBranchRegion(S->getCond(), DefaultTrue, DefaultFalse);
1335*e038c9c4Sjoerg }
13367330f729Sjoerg }
13377330f729Sjoerg
VisitSwitchCase__anon8c3eb65b0211::CounterCoverageMappingBuilder13387330f729Sjoerg void VisitSwitchCase(const SwitchCase *S) {
13397330f729Sjoerg extendRegion(S);
13407330f729Sjoerg
13417330f729Sjoerg SourceMappingRegion &Parent = getRegion();
13427330f729Sjoerg
13437330f729Sjoerg Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S));
13447330f729Sjoerg // Reuse the existing region if it starts at our label. This is typical of
13457330f729Sjoerg // the first case in a switch.
13467330f729Sjoerg if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S))
13477330f729Sjoerg Parent.setCounter(Count);
13487330f729Sjoerg else
13497330f729Sjoerg pushRegion(Count, getStart(S));
13507330f729Sjoerg
1351*e038c9c4Sjoerg GapRegionCounter = Count;
1352*e038c9c4Sjoerg
13537330f729Sjoerg if (const auto *CS = dyn_cast<CaseStmt>(S)) {
13547330f729Sjoerg Visit(CS->getLHS());
13557330f729Sjoerg if (const Expr *RHS = CS->getRHS())
13567330f729Sjoerg Visit(RHS);
13577330f729Sjoerg }
13587330f729Sjoerg Visit(S->getSubStmt());
13597330f729Sjoerg }
13607330f729Sjoerg
VisitIfStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder13617330f729Sjoerg void VisitIfStmt(const IfStmt *S) {
13627330f729Sjoerg extendRegion(S);
13637330f729Sjoerg if (S->getInit())
13647330f729Sjoerg Visit(S->getInit());
13657330f729Sjoerg
13667330f729Sjoerg // Extend into the condition before we propagate through it below - this is
13677330f729Sjoerg // needed to handle macros that generate the "if" but not the condition.
13687330f729Sjoerg extendRegion(S->getCond());
13697330f729Sjoerg
13707330f729Sjoerg Counter ParentCount = getRegion().getCounter();
13717330f729Sjoerg Counter ThenCount = getRegionCounter(S);
13727330f729Sjoerg
13737330f729Sjoerg // Emitting a counter for the condition makes it easier to interpret the
13747330f729Sjoerg // counter for the body when looking at the coverage.
13757330f729Sjoerg propagateCounts(ParentCount, S->getCond());
13767330f729Sjoerg
13777330f729Sjoerg // The 'then' count applies to the area immediately after the condition.
1378*e038c9c4Sjoerg auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getThen()));
13797330f729Sjoerg if (Gap)
13807330f729Sjoerg fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount);
13817330f729Sjoerg
13827330f729Sjoerg extendRegion(S->getThen());
13837330f729Sjoerg Counter OutCount = propagateCounts(ThenCount, S->getThen());
13847330f729Sjoerg
13857330f729Sjoerg Counter ElseCount = subtractCounters(ParentCount, ThenCount);
13867330f729Sjoerg if (const Stmt *Else = S->getElse()) {
1387*e038c9c4Sjoerg bool ThenHasTerminateStmt = HasTerminateStmt;
1388*e038c9c4Sjoerg HasTerminateStmt = false;
1389*e038c9c4Sjoerg
13907330f729Sjoerg // The 'else' count applies to the area immediately after the 'then'.
1391*e038c9c4Sjoerg Gap = findGapAreaBetween(getEnd(S->getThen()), getStart(Else));
13927330f729Sjoerg if (Gap)
13937330f729Sjoerg fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount);
13947330f729Sjoerg extendRegion(Else);
13957330f729Sjoerg OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else));
1396*e038c9c4Sjoerg
1397*e038c9c4Sjoerg if (ThenHasTerminateStmt)
1398*e038c9c4Sjoerg HasTerminateStmt = true;
13997330f729Sjoerg } else
14007330f729Sjoerg OutCount = addCounters(OutCount, ElseCount);
14017330f729Sjoerg
1402*e038c9c4Sjoerg if (OutCount != ParentCount) {
14037330f729Sjoerg pushRegion(OutCount);
1404*e038c9c4Sjoerg GapRegionCounter = OutCount;
1405*e038c9c4Sjoerg }
1406*e038c9c4Sjoerg
1407*e038c9c4Sjoerg // Create Branch Region around condition.
1408*e038c9c4Sjoerg createBranchRegion(S->getCond(), ThenCount,
1409*e038c9c4Sjoerg subtractCounters(ParentCount, ThenCount));
14107330f729Sjoerg }
14117330f729Sjoerg
VisitCXXTryStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder14127330f729Sjoerg void VisitCXXTryStmt(const CXXTryStmt *S) {
14137330f729Sjoerg extendRegion(S);
14147330f729Sjoerg // Handle macros that generate the "try" but not the rest.
14157330f729Sjoerg extendRegion(S->getTryBlock());
14167330f729Sjoerg
14177330f729Sjoerg Counter ParentCount = getRegion().getCounter();
14187330f729Sjoerg propagateCounts(ParentCount, S->getTryBlock());
14197330f729Sjoerg
14207330f729Sjoerg for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
14217330f729Sjoerg Visit(S->getHandler(I));
14227330f729Sjoerg
14237330f729Sjoerg Counter ExitCount = getRegionCounter(S);
14247330f729Sjoerg pushRegion(ExitCount);
14257330f729Sjoerg }
14267330f729Sjoerg
VisitCXXCatchStmt__anon8c3eb65b0211::CounterCoverageMappingBuilder14277330f729Sjoerg void VisitCXXCatchStmt(const CXXCatchStmt *S) {
14287330f729Sjoerg propagateCounts(getRegionCounter(S), S->getHandlerBlock());
14297330f729Sjoerg }
14307330f729Sjoerg
VisitAbstractConditionalOperator__anon8c3eb65b0211::CounterCoverageMappingBuilder14317330f729Sjoerg void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) {
14327330f729Sjoerg extendRegion(E);
14337330f729Sjoerg
14347330f729Sjoerg Counter ParentCount = getRegion().getCounter();
14357330f729Sjoerg Counter TrueCount = getRegionCounter(E);
14367330f729Sjoerg
1437*e038c9c4Sjoerg propagateCounts(ParentCount, E->getCond());
14387330f729Sjoerg
14397330f729Sjoerg if (!isa<BinaryConditionalOperator>(E)) {
14407330f729Sjoerg // The 'then' count applies to the area immediately after the condition.
14417330f729Sjoerg auto Gap =
14427330f729Sjoerg findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr()));
14437330f729Sjoerg if (Gap)
14447330f729Sjoerg fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount);
14457330f729Sjoerg
14467330f729Sjoerg extendRegion(E->getTrueExpr());
14477330f729Sjoerg propagateCounts(TrueCount, E->getTrueExpr());
14487330f729Sjoerg }
14497330f729Sjoerg
14507330f729Sjoerg extendRegion(E->getFalseExpr());
14517330f729Sjoerg propagateCounts(subtractCounters(ParentCount, TrueCount),
14527330f729Sjoerg E->getFalseExpr());
1453*e038c9c4Sjoerg
1454*e038c9c4Sjoerg // Create Branch Region around condition.
1455*e038c9c4Sjoerg createBranchRegion(E->getCond(), TrueCount,
1456*e038c9c4Sjoerg subtractCounters(ParentCount, TrueCount));
14577330f729Sjoerg }
14587330f729Sjoerg
VisitBinLAnd__anon8c3eb65b0211::CounterCoverageMappingBuilder14597330f729Sjoerg void VisitBinLAnd(const BinaryOperator *E) {
14607330f729Sjoerg extendRegion(E->getLHS());
14617330f729Sjoerg propagateCounts(getRegion().getCounter(), E->getLHS());
14627330f729Sjoerg handleFileExit(getEnd(E->getLHS()));
14637330f729Sjoerg
1464*e038c9c4Sjoerg // Counter tracks the right hand side of a logical and operator.
14657330f729Sjoerg extendRegion(E->getRHS());
14667330f729Sjoerg propagateCounts(getRegionCounter(E), E->getRHS());
1467*e038c9c4Sjoerg
1468*e038c9c4Sjoerg // Extract the RHS's Execution Counter.
1469*e038c9c4Sjoerg Counter RHSExecCnt = getRegionCounter(E);
1470*e038c9c4Sjoerg
1471*e038c9c4Sjoerg // Extract the RHS's "True" Instance Counter.
1472*e038c9c4Sjoerg Counter RHSTrueCnt = getRegionCounter(E->getRHS());
1473*e038c9c4Sjoerg
1474*e038c9c4Sjoerg // Extract the Parent Region Counter.
1475*e038c9c4Sjoerg Counter ParentCnt = getRegion().getCounter();
1476*e038c9c4Sjoerg
1477*e038c9c4Sjoerg // Create Branch Region around LHS condition.
1478*e038c9c4Sjoerg createBranchRegion(E->getLHS(), RHSExecCnt,
1479*e038c9c4Sjoerg subtractCounters(ParentCnt, RHSExecCnt));
1480*e038c9c4Sjoerg
1481*e038c9c4Sjoerg // Create Branch Region around RHS condition.
1482*e038c9c4Sjoerg createBranchRegion(E->getRHS(), RHSTrueCnt,
1483*e038c9c4Sjoerg subtractCounters(RHSExecCnt, RHSTrueCnt));
14847330f729Sjoerg }
14857330f729Sjoerg
VisitBinLOr__anon8c3eb65b0211::CounterCoverageMappingBuilder14867330f729Sjoerg void VisitBinLOr(const BinaryOperator *E) {
14877330f729Sjoerg extendRegion(E->getLHS());
14887330f729Sjoerg propagateCounts(getRegion().getCounter(), E->getLHS());
14897330f729Sjoerg handleFileExit(getEnd(E->getLHS()));
14907330f729Sjoerg
1491*e038c9c4Sjoerg // Counter tracks the right hand side of a logical or operator.
14927330f729Sjoerg extendRegion(E->getRHS());
14937330f729Sjoerg propagateCounts(getRegionCounter(E), E->getRHS());
1494*e038c9c4Sjoerg
1495*e038c9c4Sjoerg // Extract the RHS's Execution Counter.
1496*e038c9c4Sjoerg Counter RHSExecCnt = getRegionCounter(E);
1497*e038c9c4Sjoerg
1498*e038c9c4Sjoerg // Extract the RHS's "False" Instance Counter.
1499*e038c9c4Sjoerg Counter RHSFalseCnt = getRegionCounter(E->getRHS());
1500*e038c9c4Sjoerg
1501*e038c9c4Sjoerg // Extract the Parent Region Counter.
1502*e038c9c4Sjoerg Counter ParentCnt = getRegion().getCounter();
1503*e038c9c4Sjoerg
1504*e038c9c4Sjoerg // Create Branch Region around LHS condition.
1505*e038c9c4Sjoerg createBranchRegion(E->getLHS(), subtractCounters(ParentCnt, RHSExecCnt),
1506*e038c9c4Sjoerg RHSExecCnt);
1507*e038c9c4Sjoerg
1508*e038c9c4Sjoerg // Create Branch Region around RHS condition.
1509*e038c9c4Sjoerg createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
1510*e038c9c4Sjoerg RHSFalseCnt);
15117330f729Sjoerg }
15127330f729Sjoerg
VisitLambdaExpr__anon8c3eb65b0211::CounterCoverageMappingBuilder15137330f729Sjoerg void VisitLambdaExpr(const LambdaExpr *LE) {
15147330f729Sjoerg // Lambdas are treated as their own functions for now, so we shouldn't
15157330f729Sjoerg // propagate counts into them.
15167330f729Sjoerg }
15177330f729Sjoerg };
15187330f729Sjoerg
15197330f729Sjoerg } // end anonymous namespace
15207330f729Sjoerg
dump(llvm::raw_ostream & OS,StringRef FunctionName,ArrayRef<CounterExpression> Expressions,ArrayRef<CounterMappingRegion> Regions)15217330f729Sjoerg static void dump(llvm::raw_ostream &OS, StringRef FunctionName,
15227330f729Sjoerg ArrayRef<CounterExpression> Expressions,
15237330f729Sjoerg ArrayRef<CounterMappingRegion> Regions) {
15247330f729Sjoerg OS << FunctionName << ":\n";
15257330f729Sjoerg CounterMappingContext Ctx(Expressions);
15267330f729Sjoerg for (const auto &R : Regions) {
15277330f729Sjoerg OS.indent(2);
15287330f729Sjoerg switch (R.Kind) {
15297330f729Sjoerg case CounterMappingRegion::CodeRegion:
15307330f729Sjoerg break;
15317330f729Sjoerg case CounterMappingRegion::ExpansionRegion:
15327330f729Sjoerg OS << "Expansion,";
15337330f729Sjoerg break;
15347330f729Sjoerg case CounterMappingRegion::SkippedRegion:
15357330f729Sjoerg OS << "Skipped,";
15367330f729Sjoerg break;
15377330f729Sjoerg case CounterMappingRegion::GapRegion:
15387330f729Sjoerg OS << "Gap,";
15397330f729Sjoerg break;
1540*e038c9c4Sjoerg case CounterMappingRegion::BranchRegion:
1541*e038c9c4Sjoerg OS << "Branch,";
1542*e038c9c4Sjoerg break;
15437330f729Sjoerg }
15447330f729Sjoerg
15457330f729Sjoerg OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart
15467330f729Sjoerg << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = ";
15477330f729Sjoerg Ctx.dump(R.Count, OS);
1548*e038c9c4Sjoerg
1549*e038c9c4Sjoerg if (R.Kind == CounterMappingRegion::BranchRegion) {
1550*e038c9c4Sjoerg OS << ", ";
1551*e038c9c4Sjoerg Ctx.dump(R.FalseCount, OS);
1552*e038c9c4Sjoerg }
1553*e038c9c4Sjoerg
15547330f729Sjoerg if (R.Kind == CounterMappingRegion::ExpansionRegion)
15557330f729Sjoerg OS << " (Expanded file = " << R.ExpandedFileID << ")";
15567330f729Sjoerg OS << "\n";
15577330f729Sjoerg }
15587330f729Sjoerg }
15597330f729Sjoerg
CoverageMappingModuleGen(CodeGenModule & CGM,CoverageSourceInfo & SourceInfo)1560*e038c9c4Sjoerg CoverageMappingModuleGen::CoverageMappingModuleGen(
1561*e038c9c4Sjoerg CodeGenModule &CGM, CoverageSourceInfo &SourceInfo)
1562*e038c9c4Sjoerg : CGM(CGM), SourceInfo(SourceInfo) {
1563*e038c9c4Sjoerg CoveragePrefixMap = CGM.getCodeGenOpts().CoveragePrefixMap;
1564*e038c9c4Sjoerg }
1565*e038c9c4Sjoerg
getCurrentDirname()1566*e038c9c4Sjoerg std::string CoverageMappingModuleGen::getCurrentDirname() {
1567*e038c9c4Sjoerg if (!CGM.getCodeGenOpts().CoverageCompilationDir.empty())
1568*e038c9c4Sjoerg return CGM.getCodeGenOpts().CoverageCompilationDir;
1569*e038c9c4Sjoerg
1570*e038c9c4Sjoerg SmallString<256> CWD;
1571*e038c9c4Sjoerg llvm::sys::fs::current_path(CWD);
1572*e038c9c4Sjoerg return CWD.str().str();
1573*e038c9c4Sjoerg }
1574*e038c9c4Sjoerg
normalizeFilename(StringRef Filename)1575*e038c9c4Sjoerg std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
1576*e038c9c4Sjoerg llvm::SmallString<256> Path(Filename);
1577*e038c9c4Sjoerg llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
1578*e038c9c4Sjoerg for (const auto &Entry : CoveragePrefixMap) {
1579*e038c9c4Sjoerg if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
1580*e038c9c4Sjoerg break;
1581*e038c9c4Sjoerg }
1582*e038c9c4Sjoerg return Path.str().str();
1583*e038c9c4Sjoerg }
1584*e038c9c4Sjoerg
getInstrProfSection(const CodeGenModule & CGM,llvm::InstrProfSectKind SK)1585*e038c9c4Sjoerg static std::string getInstrProfSection(const CodeGenModule &CGM,
1586*e038c9c4Sjoerg llvm::InstrProfSectKind SK) {
1587*e038c9c4Sjoerg return llvm::getInstrProfSectionName(
1588*e038c9c4Sjoerg SK, CGM.getContext().getTargetInfo().getTriple().getObjectFormat());
1589*e038c9c4Sjoerg }
1590*e038c9c4Sjoerg
emitFunctionMappingRecord(const FunctionInfo & Info,uint64_t FilenamesRef)1591*e038c9c4Sjoerg void CoverageMappingModuleGen::emitFunctionMappingRecord(
1592*e038c9c4Sjoerg const FunctionInfo &Info, uint64_t FilenamesRef) {
15937330f729Sjoerg llvm::LLVMContext &Ctx = CGM.getLLVMContext();
1594*e038c9c4Sjoerg
1595*e038c9c4Sjoerg // Assign a name to the function record. This is used to merge duplicates.
1596*e038c9c4Sjoerg std::string FuncRecordName = "__covrec_" + llvm::utohexstr(Info.NameHash);
1597*e038c9c4Sjoerg
1598*e038c9c4Sjoerg // A dummy description for a function included-but-not-used in a TU can be
1599*e038c9c4Sjoerg // replaced by full description provided by a different TU. The two kinds of
1600*e038c9c4Sjoerg // descriptions play distinct roles: therefore, assign them different names
1601*e038c9c4Sjoerg // to prevent `linkonce_odr` merging.
1602*e038c9c4Sjoerg if (Info.IsUsed)
1603*e038c9c4Sjoerg FuncRecordName += "u";
1604*e038c9c4Sjoerg
1605*e038c9c4Sjoerg // Create the function record type.
1606*e038c9c4Sjoerg const uint64_t NameHash = Info.NameHash;
1607*e038c9c4Sjoerg const uint64_t FuncHash = Info.FuncHash;
1608*e038c9c4Sjoerg const std::string &CoverageMapping = Info.CoverageMapping;
16097330f729Sjoerg #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType,
16107330f729Sjoerg llvm::Type *FunctionRecordTypes[] = {
16117330f729Sjoerg #include "llvm/ProfileData/InstrProfData.inc"
16127330f729Sjoerg };
1613*e038c9c4Sjoerg auto *FunctionRecordTy =
16147330f729Sjoerg llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes),
16157330f729Sjoerg /*isPacked=*/true);
16167330f729Sjoerg
1617*e038c9c4Sjoerg // Create the function record constant.
16187330f729Sjoerg #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init,
16197330f729Sjoerg llvm::Constant *FunctionRecordVals[] = {
16207330f729Sjoerg #include "llvm/ProfileData/InstrProfData.inc"
16217330f729Sjoerg };
1622*e038c9c4Sjoerg auto *FuncRecordConstant = llvm::ConstantStruct::get(
1623*e038c9c4Sjoerg FunctionRecordTy, makeArrayRef(FunctionRecordVals));
1624*e038c9c4Sjoerg
1625*e038c9c4Sjoerg // Create the function record global.
1626*e038c9c4Sjoerg auto *FuncRecord = new llvm::GlobalVariable(
1627*e038c9c4Sjoerg CGM.getModule(), FunctionRecordTy, /*isConstant=*/true,
1628*e038c9c4Sjoerg llvm::GlobalValue::LinkOnceODRLinkage, FuncRecordConstant,
1629*e038c9c4Sjoerg FuncRecordName);
1630*e038c9c4Sjoerg FuncRecord->setVisibility(llvm::GlobalValue::HiddenVisibility);
1631*e038c9c4Sjoerg FuncRecord->setSection(getInstrProfSection(CGM, llvm::IPSK_covfun));
1632*e038c9c4Sjoerg FuncRecord->setAlignment(llvm::Align(8));
1633*e038c9c4Sjoerg if (CGM.supportsCOMDAT())
1634*e038c9c4Sjoerg FuncRecord->setComdat(CGM.getModule().getOrInsertComdat(FuncRecordName));
1635*e038c9c4Sjoerg
1636*e038c9c4Sjoerg // Make sure the data doesn't get deleted.
1637*e038c9c4Sjoerg CGM.addUsedGlobal(FuncRecord);
1638*e038c9c4Sjoerg }
1639*e038c9c4Sjoerg
addFunctionMappingRecord(llvm::GlobalVariable * NamePtr,StringRef NameValue,uint64_t FuncHash,const std::string & CoverageMapping,bool IsUsed)1640*e038c9c4Sjoerg void CoverageMappingModuleGen::addFunctionMappingRecord(
1641*e038c9c4Sjoerg llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash,
1642*e038c9c4Sjoerg const std::string &CoverageMapping, bool IsUsed) {
1643*e038c9c4Sjoerg llvm::LLVMContext &Ctx = CGM.getLLVMContext();
1644*e038c9c4Sjoerg const uint64_t NameHash = llvm::IndexedInstrProf::ComputeHash(NameValue);
1645*e038c9c4Sjoerg FunctionRecords.push_back({NameHash, FuncHash, CoverageMapping, IsUsed});
1646*e038c9c4Sjoerg
16477330f729Sjoerg if (!IsUsed)
16487330f729Sjoerg FunctionNames.push_back(
16497330f729Sjoerg llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx)));
16507330f729Sjoerg
16517330f729Sjoerg if (CGM.getCodeGenOpts().DumpCoverageMapping) {
16527330f729Sjoerg // Dump the coverage mapping data for this function by decoding the
16537330f729Sjoerg // encoded data. This allows us to dump the mapping regions which were
16547330f729Sjoerg // also processed by the CoverageMappingWriter which performs
16557330f729Sjoerg // additional minimization operations such as reducing the number of
16567330f729Sjoerg // expressions.
1657*e038c9c4Sjoerg llvm::SmallVector<std::string, 16> FilenameStrs;
16587330f729Sjoerg std::vector<StringRef> Filenames;
16597330f729Sjoerg std::vector<CounterExpression> Expressions;
16607330f729Sjoerg std::vector<CounterMappingRegion> Regions;
1661*e038c9c4Sjoerg FilenameStrs.resize(FileEntries.size() + 1);
1662*e038c9c4Sjoerg FilenameStrs[0] = normalizeFilename(getCurrentDirname());
16637330f729Sjoerg for (const auto &Entry : FileEntries) {
16647330f729Sjoerg auto I = Entry.second;
16657330f729Sjoerg FilenameStrs[I] = normalizeFilename(Entry.first->getName());
16667330f729Sjoerg }
1667*e038c9c4Sjoerg ArrayRef<std::string> FilenameRefs = llvm::makeArrayRef(FilenameStrs);
16687330f729Sjoerg RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
16697330f729Sjoerg Expressions, Regions);
16707330f729Sjoerg if (Reader.read())
16717330f729Sjoerg return;
16727330f729Sjoerg dump(llvm::outs(), NameValue, Expressions, Regions);
16737330f729Sjoerg }
16747330f729Sjoerg }
16757330f729Sjoerg
emit()16767330f729Sjoerg void CoverageMappingModuleGen::emit() {
16777330f729Sjoerg if (FunctionRecords.empty())
16787330f729Sjoerg return;
16797330f729Sjoerg llvm::LLVMContext &Ctx = CGM.getLLVMContext();
16807330f729Sjoerg auto *Int32Ty = llvm::Type::getInt32Ty(Ctx);
16817330f729Sjoerg
16827330f729Sjoerg // Create the filenames and merge them with coverage mappings
16837330f729Sjoerg llvm::SmallVector<std::string, 16> FilenameStrs;
1684*e038c9c4Sjoerg FilenameStrs.resize(FileEntries.size() + 1);
1685*e038c9c4Sjoerg // The first filename is the current working directory.
1686*e038c9c4Sjoerg FilenameStrs[0] = normalizeFilename(getCurrentDirname());
16877330f729Sjoerg for (const auto &Entry : FileEntries) {
16887330f729Sjoerg auto I = Entry.second;
16897330f729Sjoerg FilenameStrs[I] = normalizeFilename(Entry.first->getName());
16907330f729Sjoerg }
16917330f729Sjoerg
1692*e038c9c4Sjoerg std::string Filenames;
1693*e038c9c4Sjoerg {
1694*e038c9c4Sjoerg llvm::raw_string_ostream OS(Filenames);
1695*e038c9c4Sjoerg CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
16967330f729Sjoerg }
1697*e038c9c4Sjoerg auto *FilenamesVal =
1698*e038c9c4Sjoerg llvm::ConstantDataArray::getString(Ctx, Filenames, false);
1699*e038c9c4Sjoerg const int64_t FilenamesRef = llvm::IndexedInstrProf::ComputeHash(Filenames);
17007330f729Sjoerg
1701*e038c9c4Sjoerg // Emit the function records.
1702*e038c9c4Sjoerg for (const FunctionInfo &Info : FunctionRecords)
1703*e038c9c4Sjoerg emitFunctionMappingRecord(Info, FilenamesRef);
17047330f729Sjoerg
1705*e038c9c4Sjoerg const unsigned NRecords = 0;
1706*e038c9c4Sjoerg const size_t FilenamesSize = Filenames.size();
1707*e038c9c4Sjoerg const unsigned CoverageMappingSize = 0;
17087330f729Sjoerg llvm::Type *CovDataHeaderTypes[] = {
17097330f729Sjoerg #define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType,
17107330f729Sjoerg #include "llvm/ProfileData/InstrProfData.inc"
17117330f729Sjoerg };
17127330f729Sjoerg auto CovDataHeaderTy =
17137330f729Sjoerg llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes));
17147330f729Sjoerg llvm::Constant *CovDataHeaderVals[] = {
17157330f729Sjoerg #define COVMAP_HEADER(Type, LLVMType, Name, Init) Init,
17167330f729Sjoerg #include "llvm/ProfileData/InstrProfData.inc"
17177330f729Sjoerg };
17187330f729Sjoerg auto CovDataHeaderVal = llvm::ConstantStruct::get(
17197330f729Sjoerg CovDataHeaderTy, makeArrayRef(CovDataHeaderVals));
17207330f729Sjoerg
17217330f729Sjoerg // Create the coverage data record
1722*e038c9c4Sjoerg llvm::Type *CovDataTypes[] = {CovDataHeaderTy, FilenamesVal->getType()};
17237330f729Sjoerg auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes));
1724*e038c9c4Sjoerg llvm::Constant *TUDataVals[] = {CovDataHeaderVal, FilenamesVal};
17257330f729Sjoerg auto CovDataVal =
17267330f729Sjoerg llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals));
17277330f729Sjoerg auto CovData = new llvm::GlobalVariable(
1728*e038c9c4Sjoerg CGM.getModule(), CovDataTy, true, llvm::GlobalValue::PrivateLinkage,
17297330f729Sjoerg CovDataVal, llvm::getCoverageMappingVarName());
17307330f729Sjoerg
1731*e038c9c4Sjoerg CovData->setSection(getInstrProfSection(CGM, llvm::IPSK_covmap));
17327330f729Sjoerg CovData->setAlignment(llvm::Align(8));
17337330f729Sjoerg
17347330f729Sjoerg // Make sure the data doesn't get deleted.
17357330f729Sjoerg CGM.addUsedGlobal(CovData);
17367330f729Sjoerg // Create the deferred function records array
17377330f729Sjoerg if (!FunctionNames.empty()) {
17387330f729Sjoerg auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx),
17397330f729Sjoerg FunctionNames.size());
17407330f729Sjoerg auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames);
17417330f729Sjoerg // This variable will *NOT* be emitted to the object file. It is used
17427330f729Sjoerg // to pass the list of names referenced to codegen.
17437330f729Sjoerg new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true,
17447330f729Sjoerg llvm::GlobalValue::InternalLinkage, NamesArrVal,
17457330f729Sjoerg llvm::getCoverageUnusedNamesVarName());
17467330f729Sjoerg }
17477330f729Sjoerg }
17487330f729Sjoerg
getFileID(const FileEntry * File)17497330f729Sjoerg unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
17507330f729Sjoerg auto It = FileEntries.find(File);
17517330f729Sjoerg if (It != FileEntries.end())
17527330f729Sjoerg return It->second;
1753*e038c9c4Sjoerg unsigned FileID = FileEntries.size() + 1;
17547330f729Sjoerg FileEntries.insert(std::make_pair(File, FileID));
17557330f729Sjoerg return FileID;
17567330f729Sjoerg }
17577330f729Sjoerg
emitCounterMapping(const Decl * D,llvm::raw_ostream & OS)17587330f729Sjoerg void CoverageMappingGen::emitCounterMapping(const Decl *D,
17597330f729Sjoerg llvm::raw_ostream &OS) {
17607330f729Sjoerg assert(CounterMap);
17617330f729Sjoerg CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, LangOpts);
17627330f729Sjoerg Walker.VisitDecl(D);
17637330f729Sjoerg Walker.write(OS);
17647330f729Sjoerg }
17657330f729Sjoerg
emitEmptyMapping(const Decl * D,llvm::raw_ostream & OS)17667330f729Sjoerg void CoverageMappingGen::emitEmptyMapping(const Decl *D,
17677330f729Sjoerg llvm::raw_ostream &OS) {
17687330f729Sjoerg EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts);
17697330f729Sjoerg Walker.VisitDecl(D);
17707330f729Sjoerg Walker.write(OS);
17717330f729Sjoerg }
1772