diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-12-20 19:53:05 +0000 | 
| commit | 0b57cec536236d46e3dba9bd041533462f33dbb7 (patch) | |
| tree | 56229dbdbbf76d18580f72f789003db17246c8d9 /contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp | |
| parent | 718ef55ec7785aae63f98f8ca05dc07ed399c16d (diff) | |
Notes
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp')
| -rw-r--r-- | contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp | 1484 | 
1 files changed, 0 insertions, 1484 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp deleted file mode 100644 index 6d18027f16a8..000000000000 --- a/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp +++ /dev/null @@ -1,1484 +0,0 @@ -//===--- CoverageMappingGen.cpp - Coverage mapping generation ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Instrumentation-based code coverage mapping generator -// -//===----------------------------------------------------------------------===// - -#include "CoverageMappingGen.h" -#include "CodeGenFunction.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/Lex/Lexer.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ProfileData/Coverage/CoverageMapping.h" -#include "llvm/ProfileData/Coverage/CoverageMappingReader.h" -#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" -#include "llvm/ProfileData/InstrProfReader.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" - -using namespace clang; -using namespace CodeGen; -using namespace llvm::coverage; - -void CoverageSourceInfo::SourceRangeSkipped(SourceRange Range, SourceLocation) { -  SkippedRanges.push_back(Range); -} - -namespace { - -/// A region of source code that can be mapped to a counter. -class SourceMappingRegion { -  Counter Count; - -  /// The region's starting location. -  Optional<SourceLocation> LocStart; - -  /// The region's ending location. -  Optional<SourceLocation> LocEnd; - -  /// Whether this region should be emitted after its parent is emitted. -  bool DeferRegion; - -  /// Whether this region is a gap region. The count from a gap region is set -  /// as the line execution count if there are no other regions on the line. -  bool GapRegion; - -public: -  SourceMappingRegion(Counter Count, Optional<SourceLocation> LocStart, -                      Optional<SourceLocation> LocEnd, bool DeferRegion = false, -                      bool GapRegion = false) -      : Count(Count), LocStart(LocStart), LocEnd(LocEnd), -        DeferRegion(DeferRegion), GapRegion(GapRegion) {} - -  const Counter &getCounter() const { return Count; } - -  void setCounter(Counter C) { Count = C; } - -  bool hasStartLoc() const { return LocStart.hasValue(); } - -  void setStartLoc(SourceLocation Loc) { LocStart = Loc; } - -  SourceLocation getBeginLoc() const { -    assert(LocStart && "Region has no start location"); -    return *LocStart; -  } - -  bool hasEndLoc() const { return LocEnd.hasValue(); } - -  void setEndLoc(SourceLocation Loc) { -    assert(Loc.isValid() && "Setting an invalid end location"); -    LocEnd = Loc; -  } - -  SourceLocation getEndLoc() const { -    assert(LocEnd && "Region has no end location"); -    return *LocEnd; -  } - -  bool isDeferred() const { return DeferRegion; } - -  void setDeferred(bool Deferred) { DeferRegion = Deferred; } - -  bool isGap() const { return GapRegion; } - -  void setGap(bool Gap) { GapRegion = Gap; } -}; - -/// Spelling locations for the start and end of a source region. -struct SpellingRegion { -  /// The line where the region starts. -  unsigned LineStart; - -  /// The column where the region starts. -  unsigned ColumnStart; - -  /// The line where the region ends. -  unsigned LineEnd; - -  /// The column where the region ends. -  unsigned ColumnEnd; - -  SpellingRegion(SourceManager &SM, SourceLocation LocStart, -                 SourceLocation LocEnd) { -    LineStart = SM.getSpellingLineNumber(LocStart); -    ColumnStart = SM.getSpellingColumnNumber(LocStart); -    LineEnd = SM.getSpellingLineNumber(LocEnd); -    ColumnEnd = SM.getSpellingColumnNumber(LocEnd); -  } - -  SpellingRegion(SourceManager &SM, SourceMappingRegion &R) -      : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {} - -  /// Check if the start and end locations appear in source order, i.e -  /// top->bottom, left->right. -  bool isInSourceOrder() const { -    return (LineStart < LineEnd) || -           (LineStart == LineEnd && ColumnStart <= ColumnEnd); -  } -}; - -/// Provides the common functionality for the different -/// coverage mapping region builders. -class CoverageMappingBuilder { -public: -  CoverageMappingModuleGen &CVM; -  SourceManager &SM; -  const LangOptions &LangOpts; - -private: -  /// Map of clang's FileIDs to IDs used for coverage mapping. -  llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8> -      FileIDMapping; - -public: -  /// The coverage mapping regions for this function -  llvm::SmallVector<CounterMappingRegion, 32> MappingRegions; -  /// The source mapping regions for this function. -  std::vector<SourceMappingRegion> SourceRegions; - -  /// A set of regions which can be used as a filter. -  /// -  /// It is produced by emitExpansionRegions() and is used in -  /// emitSourceRegions() to suppress producing code regions if -  /// the same area is covered by expansion regions. -  typedef llvm::SmallSet<std::pair<SourceLocation, SourceLocation>, 8> -      SourceRegionFilter; - -  CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM, -                         const LangOptions &LangOpts) -      : CVM(CVM), SM(SM), LangOpts(LangOpts) {} - -  /// Return the precise end location for the given token. -  SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) { -    // We avoid getLocForEndOfToken here, because it doesn't do what we want for -    // macro locations, which we just treat as expanded files. -    unsigned TokLen = -        Lexer::MeasureTokenLength(SM.getSpellingLoc(Loc), SM, LangOpts); -    return Loc.getLocWithOffset(TokLen); -  } - -  /// Return the start location of an included file or expanded macro. -  SourceLocation getStartOfFileOrMacro(SourceLocation Loc) { -    if (Loc.isMacroID()) -      return Loc.getLocWithOffset(-SM.getFileOffset(Loc)); -    return SM.getLocForStartOfFile(SM.getFileID(Loc)); -  } - -  /// Return the end location of an included file or expanded macro. -  SourceLocation getEndOfFileOrMacro(SourceLocation Loc) { -    if (Loc.isMacroID()) -      return Loc.getLocWithOffset(SM.getFileIDSize(SM.getFileID(Loc)) - -                                  SM.getFileOffset(Loc)); -    return SM.getLocForEndOfFile(SM.getFileID(Loc)); -  } - -  /// Find out where the current file is included or macro is expanded. -  SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) { -    return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).getBegin() -                           : SM.getIncludeLoc(SM.getFileID(Loc)); -  } - -  /// Return true if \c Loc is a location in a built-in macro. -  bool isInBuiltin(SourceLocation Loc) { -    return SM.getBufferName(SM.getSpellingLoc(Loc)) == "<built-in>"; -  } - -  /// Check whether \c Loc is included or expanded from \c Parent. -  bool isNestedIn(SourceLocation Loc, FileID Parent) { -    do { -      Loc = getIncludeOrExpansionLoc(Loc); -      if (Loc.isInvalid()) -        return false; -    } while (!SM.isInFileID(Loc, Parent)); -    return true; -  } - -  /// Get the start of \c S ignoring macro arguments and builtin macros. -  SourceLocation getStart(const Stmt *S) { -    SourceLocation Loc = S->getBeginLoc(); -    while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc)) -      Loc = SM.getImmediateExpansionRange(Loc).getBegin(); -    return Loc; -  } - -  /// Get the end of \c S ignoring macro arguments and builtin macros. -  SourceLocation getEnd(const Stmt *S) { -    SourceLocation Loc = S->getEndLoc(); -    while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc)) -      Loc = SM.getImmediateExpansionRange(Loc).getBegin(); -    return getPreciseTokenLocEnd(Loc); -  } - -  /// Find the set of files we have regions for and assign IDs -  /// -  /// Fills \c Mapping with the virtual file mapping needed to write out -  /// coverage and collects the necessary file information to emit source and -  /// expansion regions. -  void gatherFileIDs(SmallVectorImpl<unsigned> &Mapping) { -    FileIDMapping.clear(); - -    llvm::SmallSet<FileID, 8> Visited; -    SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs; -    for (const auto &Region : SourceRegions) { -      SourceLocation Loc = Region.getBeginLoc(); -      FileID File = SM.getFileID(Loc); -      if (!Visited.insert(File).second) -        continue; - -      // Do not map FileID's associated with system headers. -      if (SM.isInSystemHeader(SM.getSpellingLoc(Loc))) -        continue; - -      unsigned Depth = 0; -      for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc); -           Parent.isValid(); Parent = getIncludeOrExpansionLoc(Parent)) -        ++Depth; -      FileLocs.push_back(std::make_pair(Loc, Depth)); -    } -    llvm::stable_sort(FileLocs, llvm::less_second()); - -    for (const auto &FL : FileLocs) { -      SourceLocation Loc = FL.first; -      FileID SpellingFile = SM.getDecomposedSpellingLoc(Loc).first; -      auto Entry = SM.getFileEntryForID(SpellingFile); -      if (!Entry) -        continue; - -      FileIDMapping[SM.getFileID(Loc)] = std::make_pair(Mapping.size(), Loc); -      Mapping.push_back(CVM.getFileID(Entry)); -    } -  } - -  /// Get the coverage mapping file ID for \c Loc. -  /// -  /// If such file id doesn't exist, return None. -  Optional<unsigned> getCoverageFileID(SourceLocation Loc) { -    auto Mapping = FileIDMapping.find(SM.getFileID(Loc)); -    if (Mapping != FileIDMapping.end()) -      return Mapping->second.first; -    return None; -  } - -  /// Gather all the regions that were skipped by the preprocessor -  /// using the constructs like #if. -  void gatherSkippedRegions() { -    /// An array of the minimum lineStarts and the maximum lineEnds -    /// for mapping regions from the appropriate source files. -    llvm::SmallVector<std::pair<unsigned, unsigned>, 8> FileLineRanges; -    FileLineRanges.resize( -        FileIDMapping.size(), -        std::make_pair(std::numeric_limits<unsigned>::max(), 0)); -    for (const auto &R : MappingRegions) { -      FileLineRanges[R.FileID].first = -          std::min(FileLineRanges[R.FileID].first, R.LineStart); -      FileLineRanges[R.FileID].second = -          std::max(FileLineRanges[R.FileID].second, R.LineEnd); -    } - -    auto SkippedRanges = CVM.getSourceInfo().getSkippedRanges(); -    for (const auto &I : SkippedRanges) { -      auto LocStart = I.getBegin(); -      auto LocEnd = I.getEnd(); -      assert(SM.isWrittenInSameFile(LocStart, LocEnd) && -             "region spans multiple files"); - -      auto CovFileID = getCoverageFileID(LocStart); -      if (!CovFileID) -        continue; -      SpellingRegion SR{SM, LocStart, LocEnd}; -      auto Region = CounterMappingRegion::makeSkipped( -          *CovFileID, SR.LineStart, SR.ColumnStart, SR.LineEnd, SR.ColumnEnd); -      // Make sure that we only collect the regions that are inside -      // the source code of this function. -      if (Region.LineStart >= FileLineRanges[*CovFileID].first && -          Region.LineEnd <= FileLineRanges[*CovFileID].second) -        MappingRegions.push_back(Region); -    } -  } - -  /// Generate the coverage counter mapping regions from collected -  /// source regions. -  void emitSourceRegions(const SourceRegionFilter &Filter) { -    for (const auto &Region : SourceRegions) { -      assert(Region.hasEndLoc() && "incomplete region"); - -      SourceLocation LocStart = Region.getBeginLoc(); -      assert(SM.getFileID(LocStart).isValid() && "region in invalid file"); - -      // Ignore regions from system headers. -      if (SM.isInSystemHeader(SM.getSpellingLoc(LocStart))) -        continue; - -      auto CovFileID = getCoverageFileID(LocStart); -      // Ignore regions that don't have a file, such as builtin macros. -      if (!CovFileID) -        continue; - -      SourceLocation LocEnd = Region.getEndLoc(); -      assert(SM.isWrittenInSameFile(LocStart, LocEnd) && -             "region spans multiple files"); - -      // Don't add code regions for the area covered by expansion regions. -      // This not only suppresses redundant regions, but sometimes prevents -      // creating regions with wrong counters if, for example, a statement's -      // body ends at the end of a nested macro. -      if (Filter.count(std::make_pair(LocStart, LocEnd))) -        continue; - -      // Find the spelling locations for the mapping region. -      SpellingRegion SR{SM, LocStart, LocEnd}; -      assert(SR.isInSourceOrder() && "region start and end out of order"); - -      if (Region.isGap()) { -        MappingRegions.push_back(CounterMappingRegion::makeGapRegion( -            Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart, -            SR.LineEnd, SR.ColumnEnd)); -      } else { -        MappingRegions.push_back(CounterMappingRegion::makeRegion( -            Region.getCounter(), *CovFileID, SR.LineStart, SR.ColumnStart, -            SR.LineEnd, SR.ColumnEnd)); -      } -    } -  } - -  /// Generate expansion regions for each virtual file we've seen. -  SourceRegionFilter emitExpansionRegions() { -    SourceRegionFilter Filter; -    for (const auto &FM : FileIDMapping) { -      SourceLocation ExpandedLoc = FM.second.second; -      SourceLocation ParentLoc = getIncludeOrExpansionLoc(ExpandedLoc); -      if (ParentLoc.isInvalid()) -        continue; - -      auto ParentFileID = getCoverageFileID(ParentLoc); -      if (!ParentFileID) -        continue; -      auto ExpandedFileID = getCoverageFileID(ExpandedLoc); -      assert(ExpandedFileID && "expansion in uncovered file"); - -      SourceLocation LocEnd = getPreciseTokenLocEnd(ParentLoc); -      assert(SM.isWrittenInSameFile(ParentLoc, LocEnd) && -             "region spans multiple files"); -      Filter.insert(std::make_pair(ParentLoc, LocEnd)); - -      SpellingRegion SR{SM, ParentLoc, LocEnd}; -      assert(SR.isInSourceOrder() && "region start and end out of order"); -      MappingRegions.push_back(CounterMappingRegion::makeExpansion( -          *ParentFileID, *ExpandedFileID, SR.LineStart, SR.ColumnStart, -          SR.LineEnd, SR.ColumnEnd)); -    } -    return Filter; -  } -}; - -/// Creates unreachable coverage regions for the functions that -/// are not emitted. -struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder { -  EmptyCoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM, -                              const LangOptions &LangOpts) -      : CoverageMappingBuilder(CVM, SM, LangOpts) {} - -  void VisitDecl(const Decl *D) { -    if (!D->hasBody()) -      return; -    auto Body = D->getBody(); -    SourceLocation Start = getStart(Body); -    SourceLocation End = getEnd(Body); -    if (!SM.isWrittenInSameFile(Start, End)) { -      // Walk up to find the common ancestor. -      // Correct the locations accordingly. -      FileID StartFileID = SM.getFileID(Start); -      FileID EndFileID = SM.getFileID(End); -      while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) { -        Start = getIncludeOrExpansionLoc(Start); -        assert(Start.isValid() && -               "Declaration start location not nested within a known region"); -        StartFileID = SM.getFileID(Start); -      } -      while (StartFileID != EndFileID) { -        End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End)); -        assert(End.isValid() && -               "Declaration end location not nested within a known region"); -        EndFileID = SM.getFileID(End); -      } -    } -    SourceRegions.emplace_back(Counter(), Start, End); -  } - -  /// Write the mapping data to the output stream -  void write(llvm::raw_ostream &OS) { -    SmallVector<unsigned, 16> FileIDMapping; -    gatherFileIDs(FileIDMapping); -    emitSourceRegions(SourceRegionFilter()); - -    if (MappingRegions.empty()) -      return; - -    CoverageMappingWriter Writer(FileIDMapping, None, MappingRegions); -    Writer.write(OS); -  } -}; - -/// A StmtVisitor that creates coverage mapping regions which map -/// from the source code locations to the PGO counters. -struct CounterCoverageMappingBuilder -    : public CoverageMappingBuilder, -      public ConstStmtVisitor<CounterCoverageMappingBuilder> { -  /// The map of statements to count values. -  llvm::DenseMap<const Stmt *, unsigned> &CounterMap; - -  /// A stack of currently live regions. -  std::vector<SourceMappingRegion> RegionStack; - -  /// The currently deferred region: its end location and count can be set once -  /// its parent has been popped from the region stack. -  Optional<SourceMappingRegion> DeferredRegion; - -  CounterExpressionBuilder Builder; - -  /// A location in the most recently visited file or macro. -  /// -  /// This is used to adjust the active source regions appropriately when -  /// expressions cross file or macro boundaries. -  SourceLocation MostRecentLocation; - -  /// Location of the last terminated region. -  Optional<std::pair<SourceLocation, size_t>> LastTerminatedRegion; - -  /// Return a counter for the subtraction of \c RHS from \c LHS -  Counter subtractCounters(Counter LHS, Counter RHS) { -    return Builder.subtract(LHS, RHS); -  } - -  /// Return a counter for the sum of \c LHS and \c RHS. -  Counter addCounters(Counter LHS, Counter RHS) { -    return Builder.add(LHS, RHS); -  } - -  Counter addCounters(Counter C1, Counter C2, Counter C3) { -    return addCounters(addCounters(C1, C2), C3); -  } - -  /// Return the region counter for the given statement. -  /// -  /// This should only be called on statements that have a dedicated counter. -  Counter getRegionCounter(const Stmt *S) { -    return Counter::getCounter(CounterMap[S]); -  } - -  /// Push a region onto the stack. -  /// -  /// Returns the index on the stack where the region was pushed. This can be -  /// used with popRegions to exit a "scope", ending the region that was pushed. -  size_t pushRegion(Counter Count, Optional<SourceLocation> StartLoc = None, -                    Optional<SourceLocation> EndLoc = None) { -    if (StartLoc) { -      MostRecentLocation = *StartLoc; -      completeDeferred(Count, MostRecentLocation); -    } -    RegionStack.emplace_back(Count, StartLoc, EndLoc); - -    return RegionStack.size() - 1; -  } - -  /// Complete any pending deferred region by setting its end location and -  /// count, and then pushing it onto the region stack. -  size_t completeDeferred(Counter Count, SourceLocation DeferredEndLoc) { -    size_t Index = RegionStack.size(); -    if (!DeferredRegion) -      return Index; - -    // Consume the pending region. -    SourceMappingRegion DR = DeferredRegion.getValue(); -    DeferredRegion = None; - -    // If the region ends in an expansion, find the expansion site. -    FileID StartFile = SM.getFileID(DR.getBeginLoc()); -    if (SM.getFileID(DeferredEndLoc) != StartFile) { -      if (isNestedIn(DeferredEndLoc, StartFile)) { -        do { -          DeferredEndLoc = getIncludeOrExpansionLoc(DeferredEndLoc); -        } while (StartFile != SM.getFileID(DeferredEndLoc)); -      } else { -        return Index; -      } -    } - -    // The parent of this deferred region ends where the containing decl ends, -    // so the region isn't useful. -    if (DR.getBeginLoc() == DeferredEndLoc) -      return Index; - -    // If we're visiting statements in non-source order (e.g switch cases or -    // a loop condition) we can't construct a sensible deferred region. -    if (!SpellingRegion(SM, DR.getBeginLoc(), DeferredEndLoc).isInSourceOrder()) -      return Index; - -    DR.setGap(true); -    DR.setCounter(Count); -    DR.setEndLoc(DeferredEndLoc); -    handleFileExit(DeferredEndLoc); -    RegionStack.push_back(DR); -    return Index; -  } - -  /// Complete a deferred region created after a terminated region at the -  /// top-level. -  void completeTopLevelDeferredRegion(Counter Count, -                                      SourceLocation DeferredEndLoc) { -    if (DeferredRegion || !LastTerminatedRegion) -      return; - -    if (LastTerminatedRegion->second != RegionStack.size()) -      return; - -    SourceLocation Start = LastTerminatedRegion->first; -    if (SM.getFileID(Start) != SM.getMainFileID()) -      return; - -    SourceMappingRegion DR = RegionStack.back(); -    DR.setStartLoc(Start); -    DR.setDeferred(false); -    DeferredRegion = DR; -    completeDeferred(Count, DeferredEndLoc); -  } - -  size_t locationDepth(SourceLocation Loc) { -    size_t Depth = 0; -    while (Loc.isValid()) { -      Loc = getIncludeOrExpansionLoc(Loc); -      Depth++; -    } -    return Depth; -  } - -  /// Pop regions from the stack into the function's list of regions. -  /// -  /// Adds all regions from \c ParentIndex to the top of the stack to the -  /// function's \c SourceRegions. -  void popRegions(size_t ParentIndex) { -    assert(RegionStack.size() >= ParentIndex && "parent not in stack"); -    bool ParentOfDeferredRegion = false; -    while (RegionStack.size() > ParentIndex) { -      SourceMappingRegion &Region = RegionStack.back(); -      if (Region.hasStartLoc()) { -        SourceLocation StartLoc = Region.getBeginLoc(); -        SourceLocation EndLoc = Region.hasEndLoc() -                                    ? Region.getEndLoc() -                                    : RegionStack[ParentIndex].getEndLoc(); -        size_t StartDepth = locationDepth(StartLoc); -        size_t EndDepth = locationDepth(EndLoc); -        while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) { -          bool UnnestStart = StartDepth >= EndDepth; -          bool UnnestEnd = EndDepth >= StartDepth; -          if (UnnestEnd) { -            // The region ends in a nested file or macro expansion. Create a -            // separate region for each expansion. -            SourceLocation NestedLoc = getStartOfFileOrMacro(EndLoc); -            assert(SM.isWrittenInSameFile(NestedLoc, EndLoc)); - -            if (!isRegionAlreadyAdded(NestedLoc, EndLoc)) -              SourceRegions.emplace_back(Region.getCounter(), NestedLoc, EndLoc); - -            EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc)); -            if (EndLoc.isInvalid()) -              llvm::report_fatal_error("File exit not handled before popRegions"); -            EndDepth--; -          } -          if (UnnestStart) { -            // The region begins in a nested file or macro expansion. Create a -            // separate region for each expansion. -            SourceLocation NestedLoc = getEndOfFileOrMacro(StartLoc); -            assert(SM.isWrittenInSameFile(StartLoc, NestedLoc)); - -            if (!isRegionAlreadyAdded(StartLoc, NestedLoc)) -              SourceRegions.emplace_back(Region.getCounter(), StartLoc, NestedLoc); - -            StartLoc = getIncludeOrExpansionLoc(StartLoc); -            if (StartLoc.isInvalid()) -              llvm::report_fatal_error("File exit not handled before popRegions"); -            StartDepth--; -          } -        } -        Region.setStartLoc(StartLoc); -        Region.setEndLoc(EndLoc); - -        MostRecentLocation = EndLoc; -        // If this region happens to span an entire expansion, we need to make -        // sure we don't overlap the parent region with it. -        if (StartLoc == getStartOfFileOrMacro(StartLoc) && -            EndLoc == getEndOfFileOrMacro(EndLoc)) -          MostRecentLocation = getIncludeOrExpansionLoc(EndLoc); - -        assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc)); -        assert(SpellingRegion(SM, Region).isInSourceOrder()); -        SourceRegions.push_back(Region); - -        if (ParentOfDeferredRegion) { -          ParentOfDeferredRegion = false; - -          // If there's an existing deferred region, keep the old one, because -          // it means there are two consecutive returns (or a similar pattern). -          if (!DeferredRegion.hasValue() && -              // File IDs aren't gathered within macro expansions, so it isn't -              // useful to try and create a deferred region inside of one. -              !EndLoc.isMacroID()) -            DeferredRegion = -                SourceMappingRegion(Counter::getZero(), EndLoc, None); -        } -      } else if (Region.isDeferred()) { -        assert(!ParentOfDeferredRegion && "Consecutive deferred regions"); -        ParentOfDeferredRegion = true; -      } -      RegionStack.pop_back(); - -      // If the zero region pushed after the last terminated region no longer -      // exists, clear its cached information. -      if (LastTerminatedRegion && -          RegionStack.size() < LastTerminatedRegion->second) -        LastTerminatedRegion = None; -    } -    assert(!ParentOfDeferredRegion && "Deferred region with no parent"); -  } - -  /// Return the currently active region. -  SourceMappingRegion &getRegion() { -    assert(!RegionStack.empty() && "statement has no region"); -    return RegionStack.back(); -  } - -  /// Propagate counts through the children of \p S if \p VisitChildren is true. -  /// Otherwise, only emit a count for \p S itself. -  Counter propagateCounts(Counter TopCount, const Stmt *S, -                          bool VisitChildren = true) { -    SourceLocation StartLoc = getStart(S); -    SourceLocation EndLoc = getEnd(S); -    size_t Index = pushRegion(TopCount, StartLoc, EndLoc); -    if (VisitChildren) -      Visit(S); -    Counter ExitCount = getRegion().getCounter(); -    popRegions(Index); - -    // The statement may be spanned by an expansion. Make sure we handle a file -    // exit out of this expansion before moving to the next statement. -    if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc())) -      MostRecentLocation = EndLoc; - -    return ExitCount; -  } - -  /// Check whether a region with bounds \c StartLoc and \c EndLoc -  /// is already added to \c SourceRegions. -  bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc) { -    return SourceRegions.rend() != -           std::find_if(SourceRegions.rbegin(), SourceRegions.rend(), -                        [&](const SourceMappingRegion &Region) { -                          return Region.getBeginLoc() == StartLoc && -                                 Region.getEndLoc() == EndLoc; -                        }); -  } - -  /// Adjust the most recently visited location to \c EndLoc. -  /// -  /// This should be used after visiting any statements in non-source order. -  void adjustForOutOfOrderTraversal(SourceLocation EndLoc) { -    MostRecentLocation = EndLoc; -    // The code region for a whole macro is created in handleFileExit() when -    // it detects exiting of the virtual file of that macro. If we visited -    // statements in non-source order, we might already have such a region -    // added, for example, if a body of a loop is divided among multiple -    // macros. Avoid adding duplicate regions in such case. -    if (getRegion().hasEndLoc() && -        MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation) && -        isRegionAlreadyAdded(getStartOfFileOrMacro(MostRecentLocation), -                             MostRecentLocation)) -      MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation); -  } - -  /// Adjust regions and state when \c NewLoc exits a file. -  /// -  /// If moving from our most recently tracked location to \c NewLoc exits any -  /// files, this adjusts our current region stack and creates the file regions -  /// for the exited file. -  void handleFileExit(SourceLocation NewLoc) { -    if (NewLoc.isInvalid() || -        SM.isWrittenInSameFile(MostRecentLocation, NewLoc)) -      return; - -    // If NewLoc is not in a file that contains MostRecentLocation, walk up to -    // find the common ancestor. -    SourceLocation LCA = NewLoc; -    FileID ParentFile = SM.getFileID(LCA); -    while (!isNestedIn(MostRecentLocation, ParentFile)) { -      LCA = getIncludeOrExpansionLoc(LCA); -      if (LCA.isInvalid() || SM.isWrittenInSameFile(LCA, MostRecentLocation)) { -        // Since there isn't a common ancestor, no file was exited. We just need -        // to adjust our location to the new file. -        MostRecentLocation = NewLoc; -        return; -      } -      ParentFile = SM.getFileID(LCA); -    } - -    llvm::SmallSet<SourceLocation, 8> StartLocs; -    Optional<Counter> ParentCounter; -    for (SourceMappingRegion &I : llvm::reverse(RegionStack)) { -      if (!I.hasStartLoc()) -        continue; -      SourceLocation Loc = I.getBeginLoc(); -      if (!isNestedIn(Loc, ParentFile)) { -        ParentCounter = I.getCounter(); -        break; -      } - -      while (!SM.isInFileID(Loc, ParentFile)) { -        // The most nested region for each start location is the one with the -        // correct count. We avoid creating redundant regions by stopping once -        // we've seen this region. -        if (StartLocs.insert(Loc).second) -          SourceRegions.emplace_back(I.getCounter(), Loc, -                                     getEndOfFileOrMacro(Loc)); -        Loc = getIncludeOrExpansionLoc(Loc); -      } -      I.setStartLoc(getPreciseTokenLocEnd(Loc)); -    } - -    if (ParentCounter) { -      // If the file is contained completely by another region and doesn't -      // immediately start its own region, the whole file gets a region -      // corresponding to the parent. -      SourceLocation Loc = MostRecentLocation; -      while (isNestedIn(Loc, ParentFile)) { -        SourceLocation FileStart = getStartOfFileOrMacro(Loc); -        if (StartLocs.insert(FileStart).second) { -          SourceRegions.emplace_back(*ParentCounter, FileStart, -                                     getEndOfFileOrMacro(Loc)); -          assert(SpellingRegion(SM, SourceRegions.back()).isInSourceOrder()); -        } -        Loc = getIncludeOrExpansionLoc(Loc); -      } -    } - -    MostRecentLocation = NewLoc; -  } - -  /// Ensure that \c S is included in the current region. -  void extendRegion(const Stmt *S) { -    SourceMappingRegion &Region = getRegion(); -    SourceLocation StartLoc = getStart(S); - -    handleFileExit(StartLoc); -    if (!Region.hasStartLoc()) -      Region.setStartLoc(StartLoc); - -    completeDeferred(Region.getCounter(), StartLoc); -  } - -  /// Mark \c S as a terminator, starting a zero region. -  void terminateRegion(const Stmt *S) { -    extendRegion(S); -    SourceMappingRegion &Region = getRegion(); -    SourceLocation EndLoc = getEnd(S); -    if (!Region.hasEndLoc()) -      Region.setEndLoc(EndLoc); -    pushRegion(Counter::getZero()); -    auto &ZeroRegion = getRegion(); -    ZeroRegion.setDeferred(true); -    LastTerminatedRegion = {EndLoc, RegionStack.size()}; -  } - -  /// Find a valid gap range between \p AfterLoc and \p BeforeLoc. -  Optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc, -                                           SourceLocation BeforeLoc) { -    // If the start and end locations of the gap are both within the same macro -    // file, the range may not be in source order. -    if (AfterLoc.isMacroID() || BeforeLoc.isMacroID()) -      return None; -    if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) -      return None; -    return {{AfterLoc, BeforeLoc}}; -  } - -  /// Find the source range after \p AfterStmt and before \p BeforeStmt. -  Optional<SourceRange> findGapAreaBetween(const Stmt *AfterStmt, -                                           const Stmt *BeforeStmt) { -    return findGapAreaBetween(getPreciseTokenLocEnd(getEnd(AfterStmt)), -                              getStart(BeforeStmt)); -  } - -  /// Emit a gap region between \p StartLoc and \p EndLoc with the given count. -  void fillGapAreaWithCount(SourceLocation StartLoc, SourceLocation EndLoc, -                            Counter Count) { -    if (StartLoc == EndLoc) -      return; -    assert(SpellingRegion(SM, StartLoc, EndLoc).isInSourceOrder()); -    handleFileExit(StartLoc); -    size_t Index = pushRegion(Count, StartLoc, EndLoc); -    getRegion().setGap(true); -    handleFileExit(EndLoc); -    popRegions(Index); -  } - -  /// Keep counts of breaks and continues inside loops. -  struct BreakContinue { -    Counter BreakCount; -    Counter ContinueCount; -  }; -  SmallVector<BreakContinue, 8> BreakContinueStack; - -  CounterCoverageMappingBuilder( -      CoverageMappingModuleGen &CVM, -      llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM, -      const LangOptions &LangOpts) -      : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap), -        DeferredRegion(None) {} - -  /// Write the mapping data to the output stream -  void write(llvm::raw_ostream &OS) { -    llvm::SmallVector<unsigned, 8> VirtualFileMapping; -    gatherFileIDs(VirtualFileMapping); -    SourceRegionFilter Filter = emitExpansionRegions(); -    assert(!DeferredRegion && "Deferred region never completed"); -    emitSourceRegions(Filter); -    gatherSkippedRegions(); - -    if (MappingRegions.empty()) -      return; - -    CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(), -                                 MappingRegions); -    Writer.write(OS); -  } - -  void VisitStmt(const Stmt *S) { -    if (S->getBeginLoc().isValid()) -      extendRegion(S); -    for (const Stmt *Child : S->children()) -      if (Child) -        this->Visit(Child); -    handleFileExit(getEnd(S)); -  } - -  void VisitDecl(const Decl *D) { -    assert(!DeferredRegion && "Deferred region never completed"); - -    Stmt *Body = D->getBody(); - -    // Do not propagate region counts into system headers. -    if (Body && SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body)))) -      return; - -    // Do not visit the artificial children nodes of defaulted methods. The -    // lexer may not be able to report back precise token end locations for -    // these children nodes (llvm.org/PR39822), and moreover users will not be -    // able to see coverage for them. -    bool Defaulted = false; -    if (auto *Method = dyn_cast<CXXMethodDecl>(D)) -      Defaulted = Method->isDefaulted(); - -    propagateCounts(getRegionCounter(Body), Body, -                    /*VisitChildren=*/!Defaulted); -    assert(RegionStack.empty() && "Regions entered but never exited"); - -    // Discard the last uncompleted deferred region in a decl, if one exists. -    // This prevents lines at the end of a function containing only whitespace -    // or closing braces from being marked as uncovered. -    DeferredRegion = None; -  } - -  void VisitReturnStmt(const ReturnStmt *S) { -    extendRegion(S); -    if (S->getRetValue()) -      Visit(S->getRetValue()); -    terminateRegion(S); -  } - -  void VisitCXXThrowExpr(const CXXThrowExpr *E) { -    extendRegion(E); -    if (E->getSubExpr()) -      Visit(E->getSubExpr()); -    terminateRegion(E); -  } - -  void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); } - -  void VisitLabelStmt(const LabelStmt *S) { -    Counter LabelCount = getRegionCounter(S); -    SourceLocation Start = getStart(S); -    completeTopLevelDeferredRegion(LabelCount, Start); -    completeDeferred(LabelCount, Start); -    // We can't extendRegion here or we risk overlapping with our new region. -    handleFileExit(Start); -    pushRegion(LabelCount, Start); -    Visit(S->getSubStmt()); -  } - -  void VisitBreakStmt(const BreakStmt *S) { -    assert(!BreakContinueStack.empty() && "break not in a loop or switch!"); -    BreakContinueStack.back().BreakCount = addCounters( -        BreakContinueStack.back().BreakCount, getRegion().getCounter()); -    // FIXME: a break in a switch should terminate regions for all preceding -    // case statements, not just the most recent one. -    terminateRegion(S); -  } - -  void VisitContinueStmt(const ContinueStmt *S) { -    assert(!BreakContinueStack.empty() && "continue stmt not in a loop!"); -    BreakContinueStack.back().ContinueCount = addCounters( -        BreakContinueStack.back().ContinueCount, getRegion().getCounter()); -    terminateRegion(S); -  } - -  void VisitCallExpr(const CallExpr *E) { -    VisitStmt(E); - -    // Terminate the region when we hit a noreturn function. -    // (This is helpful dealing with switch statements.) -    QualType CalleeType = E->getCallee()->getType(); -    if (getFunctionExtInfo(*CalleeType).getNoReturn()) -      terminateRegion(E); -  } - -  void VisitWhileStmt(const WhileStmt *S) { -    extendRegion(S); - -    Counter ParentCount = getRegion().getCounter(); -    Counter BodyCount = getRegionCounter(S); - -    // Handle the body first so that we can get the backedge count. -    BreakContinueStack.push_back(BreakContinue()); -    extendRegion(S->getBody()); -    Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); -    BreakContinue BC = BreakContinueStack.pop_back_val(); - -    // Go back to handle the condition. -    Counter CondCount = -        addCounters(ParentCount, BackedgeCount, BC.ContinueCount); -    propagateCounts(CondCount, S->getCond()); -    adjustForOutOfOrderTraversal(getEnd(S)); - -    // The body count applies to the area immediately after the increment. -    auto Gap = findGapAreaBetween(S->getCond(), S->getBody()); -    if (Gap) -      fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); - -    Counter OutCount = -        addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); -    if (OutCount != ParentCount) -      pushRegion(OutCount); -  } - -  void VisitDoStmt(const DoStmt *S) { -    extendRegion(S); - -    Counter ParentCount = getRegion().getCounter(); -    Counter BodyCount = getRegionCounter(S); - -    BreakContinueStack.push_back(BreakContinue()); -    extendRegion(S->getBody()); -    Counter BackedgeCount = -        propagateCounts(addCounters(ParentCount, BodyCount), S->getBody()); -    BreakContinue BC = BreakContinueStack.pop_back_val(); - -    Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount); -    propagateCounts(CondCount, S->getCond()); - -    Counter OutCount = -        addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); -    if (OutCount != ParentCount) -      pushRegion(OutCount); -  } - -  void VisitForStmt(const ForStmt *S) { -    extendRegion(S); -    if (S->getInit()) -      Visit(S->getInit()); - -    Counter ParentCount = getRegion().getCounter(); -    Counter BodyCount = getRegionCounter(S); - -    // The loop increment may contain a break or continue. -    if (S->getInc()) -      BreakContinueStack.emplace_back(); - -    // Handle the body first so that we can get the backedge count. -    BreakContinueStack.emplace_back(); -    extendRegion(S->getBody()); -    Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); -    BreakContinue BodyBC = BreakContinueStack.pop_back_val(); - -    // The increment is essentially part of the body but it needs to include -    // the count for all the continue statements. -    BreakContinue IncrementBC; -    if (const Stmt *Inc = S->getInc()) { -      propagateCounts(addCounters(BackedgeCount, BodyBC.ContinueCount), Inc); -      IncrementBC = BreakContinueStack.pop_back_val(); -    } - -    // Go back to handle the condition. -    Counter CondCount = addCounters( -        addCounters(ParentCount, BackedgeCount, BodyBC.ContinueCount), -        IncrementBC.ContinueCount); -    if (const Expr *Cond = S->getCond()) { -      propagateCounts(CondCount, Cond); -      adjustForOutOfOrderTraversal(getEnd(S)); -    } - -    // The body count applies to the area immediately after the increment. -    auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->getRParenLoc()), -                                  getStart(S->getBody())); -    if (Gap) -      fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); - -    Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount, -                                   subtractCounters(CondCount, BodyCount)); -    if (OutCount != ParentCount) -      pushRegion(OutCount); -  } - -  void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { -    extendRegion(S); -    if (S->getInit()) -      Visit(S->getInit()); -    Visit(S->getLoopVarStmt()); -    Visit(S->getRangeStmt()); - -    Counter ParentCount = getRegion().getCounter(); -    Counter BodyCount = getRegionCounter(S); - -    BreakContinueStack.push_back(BreakContinue()); -    extendRegion(S->getBody()); -    Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); -    BreakContinue BC = BreakContinueStack.pop_back_val(); - -    // The body count applies to the area immediately after the range. -    auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->getRParenLoc()), -                                  getStart(S->getBody())); -    if (Gap) -      fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); - -    Counter LoopCount = -        addCounters(ParentCount, BackedgeCount, BC.ContinueCount); -    Counter OutCount = -        addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount)); -    if (OutCount != ParentCount) -      pushRegion(OutCount); -  } - -  void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { -    extendRegion(S); -    Visit(S->getElement()); - -    Counter ParentCount = getRegion().getCounter(); -    Counter BodyCount = getRegionCounter(S); - -    BreakContinueStack.push_back(BreakContinue()); -    extendRegion(S->getBody()); -    Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); -    BreakContinue BC = BreakContinueStack.pop_back_val(); - -    // The body count applies to the area immediately after the collection. -    auto Gap = findGapAreaBetween(getPreciseTokenLocEnd(S->getRParenLoc()), -                                  getStart(S->getBody())); -    if (Gap) -      fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), BodyCount); - -    Counter LoopCount = -        addCounters(ParentCount, BackedgeCount, BC.ContinueCount); -    Counter OutCount = -        addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount)); -    if (OutCount != ParentCount) -      pushRegion(OutCount); -  } - -  void VisitSwitchStmt(const SwitchStmt *S) { -    extendRegion(S); -    if (S->getInit()) -      Visit(S->getInit()); -    Visit(S->getCond()); - -    BreakContinueStack.push_back(BreakContinue()); - -    const Stmt *Body = S->getBody(); -    extendRegion(Body); -    if (const auto *CS = dyn_cast<CompoundStmt>(Body)) { -      if (!CS->body_empty()) { -        // Make a region for the body of the switch.  If the body starts with -        // a case, that case will reuse this region; otherwise, this covers -        // the unreachable code at the beginning of the switch body. -        size_t Index = -            pushRegion(Counter::getZero(), getStart(CS->body_front())); -        for (const auto *Child : CS->children()) -          Visit(Child); - -        // Set the end for the body of the switch, if it isn't already set. -        for (size_t i = RegionStack.size(); i != Index; --i) { -          if (!RegionStack[i - 1].hasEndLoc()) -            RegionStack[i - 1].setEndLoc(getEnd(CS->body_back())); -        } - -        popRegions(Index); -      } -    } else -      propagateCounts(Counter::getZero(), Body); -    BreakContinue BC = BreakContinueStack.pop_back_val(); - -    if (!BreakContinueStack.empty()) -      BreakContinueStack.back().ContinueCount = addCounters( -          BreakContinueStack.back().ContinueCount, BC.ContinueCount); - -    Counter ExitCount = getRegionCounter(S); -    SourceLocation ExitLoc = getEnd(S); -    pushRegion(ExitCount); - -    // Ensure that handleFileExit recognizes when the end location is located -    // in a different file. -    MostRecentLocation = getStart(S); -    handleFileExit(ExitLoc); -  } - -  void VisitSwitchCase(const SwitchCase *S) { -    extendRegion(S); - -    SourceMappingRegion &Parent = getRegion(); - -    Counter Count = addCounters(Parent.getCounter(), getRegionCounter(S)); -    // Reuse the existing region if it starts at our label. This is typical of -    // the first case in a switch. -    if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S)) -      Parent.setCounter(Count); -    else -      pushRegion(Count, getStart(S)); - -    if (const auto *CS = dyn_cast<CaseStmt>(S)) { -      Visit(CS->getLHS()); -      if (const Expr *RHS = CS->getRHS()) -        Visit(RHS); -    } -    Visit(S->getSubStmt()); -  } - -  void VisitIfStmt(const IfStmt *S) { -    extendRegion(S); -    if (S->getInit()) -      Visit(S->getInit()); - -    // Extend into the condition before we propagate through it below - this is -    // needed to handle macros that generate the "if" but not the condition. -    extendRegion(S->getCond()); - -    Counter ParentCount = getRegion().getCounter(); -    Counter ThenCount = getRegionCounter(S); - -    // Emitting a counter for the condition makes it easier to interpret the -    // counter for the body when looking at the coverage. -    propagateCounts(ParentCount, S->getCond()); - -    // The 'then' count applies to the area immediately after the condition. -    auto Gap = findGapAreaBetween(S->getCond(), S->getThen()); -    if (Gap) -      fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ThenCount); - -    extendRegion(S->getThen()); -    Counter OutCount = propagateCounts(ThenCount, S->getThen()); - -    Counter ElseCount = subtractCounters(ParentCount, ThenCount); -    if (const Stmt *Else = S->getElse()) { -      // The 'else' count applies to the area immediately after the 'then'. -      Gap = findGapAreaBetween(S->getThen(), Else); -      if (Gap) -        fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount); -      extendRegion(Else); -      OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else)); -    } else -      OutCount = addCounters(OutCount, ElseCount); - -    if (OutCount != ParentCount) -      pushRegion(OutCount); -  } - -  void VisitCXXTryStmt(const CXXTryStmt *S) { -    extendRegion(S); -    // Handle macros that generate the "try" but not the rest. -    extendRegion(S->getTryBlock()); - -    Counter ParentCount = getRegion().getCounter(); -    propagateCounts(ParentCount, S->getTryBlock()); - -    for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I) -      Visit(S->getHandler(I)); - -    Counter ExitCount = getRegionCounter(S); -    pushRegion(ExitCount); -  } - -  void VisitCXXCatchStmt(const CXXCatchStmt *S) { -    propagateCounts(getRegionCounter(S), S->getHandlerBlock()); -  } - -  void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { -    extendRegion(E); - -    Counter ParentCount = getRegion().getCounter(); -    Counter TrueCount = getRegionCounter(E); - -    Visit(E->getCond()); - -    if (!isa<BinaryConditionalOperator>(E)) { -      // The 'then' count applies to the area immediately after the condition. -      auto Gap = -          findGapAreaBetween(E->getQuestionLoc(), getStart(E->getTrueExpr())); -      if (Gap) -        fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), TrueCount); - -      extendRegion(E->getTrueExpr()); -      propagateCounts(TrueCount, E->getTrueExpr()); -    } - -    extendRegion(E->getFalseExpr()); -    propagateCounts(subtractCounters(ParentCount, TrueCount), -                    E->getFalseExpr()); -  } - -  void VisitBinLAnd(const BinaryOperator *E) { -    extendRegion(E->getLHS()); -    propagateCounts(getRegion().getCounter(), E->getLHS()); -    handleFileExit(getEnd(E->getLHS())); - -    extendRegion(E->getRHS()); -    propagateCounts(getRegionCounter(E), E->getRHS()); -  } - -  void VisitBinLOr(const BinaryOperator *E) { -    extendRegion(E->getLHS()); -    propagateCounts(getRegion().getCounter(), E->getLHS()); -    handleFileExit(getEnd(E->getLHS())); - -    extendRegion(E->getRHS()); -    propagateCounts(getRegionCounter(E), E->getRHS()); -  } - -  void VisitLambdaExpr(const LambdaExpr *LE) { -    // Lambdas are treated as their own functions for now, so we shouldn't -    // propagate counts into them. -  } -}; - -std::string getCoverageSection(const CodeGenModule &CGM) { -  return llvm::getInstrProfSectionName( -      llvm::IPSK_covmap, -      CGM.getContext().getTargetInfo().getTriple().getObjectFormat()); -} - -std::string normalizeFilename(StringRef Filename) { -  llvm::SmallString<256> Path(Filename); -  llvm::sys::fs::make_absolute(Path); -  llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); -  return Path.str().str(); -} - -} // end anonymous namespace - -static void dump(llvm::raw_ostream &OS, StringRef FunctionName, -                 ArrayRef<CounterExpression> Expressions, -                 ArrayRef<CounterMappingRegion> Regions) { -  OS << FunctionName << ":\n"; -  CounterMappingContext Ctx(Expressions); -  for (const auto &R : Regions) { -    OS.indent(2); -    switch (R.Kind) { -    case CounterMappingRegion::CodeRegion: -      break; -    case CounterMappingRegion::ExpansionRegion: -      OS << "Expansion,"; -      break; -    case CounterMappingRegion::SkippedRegion: -      OS << "Skipped,"; -      break; -    case CounterMappingRegion::GapRegion: -      OS << "Gap,"; -      break; -    } - -    OS << "File " << R.FileID << ", " << R.LineStart << ":" << R.ColumnStart -       << " -> " << R.LineEnd << ":" << R.ColumnEnd << " = "; -    Ctx.dump(R.Count, OS); -    if (R.Kind == CounterMappingRegion::ExpansionRegion) -      OS << " (Expanded file = " << R.ExpandedFileID << ")"; -    OS << "\n"; -  } -} - -void CoverageMappingModuleGen::addFunctionMappingRecord( -    llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash, -    const std::string &CoverageMapping, bool IsUsed) { -  llvm::LLVMContext &Ctx = CGM.getLLVMContext(); -  if (!FunctionRecordTy) { -#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) LLVMType, -    llvm::Type *FunctionRecordTypes[] = { -      #include "llvm/ProfileData/InstrProfData.inc" -    }; -    FunctionRecordTy = -        llvm::StructType::get(Ctx, makeArrayRef(FunctionRecordTypes), -                              /*isPacked=*/true); -  } - -  #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Init, -  llvm::Constant *FunctionRecordVals[] = { -      #include "llvm/ProfileData/InstrProfData.inc" -  }; -  FunctionRecords.push_back(llvm::ConstantStruct::get( -      FunctionRecordTy, makeArrayRef(FunctionRecordVals))); -  if (!IsUsed) -    FunctionNames.push_back( -        llvm::ConstantExpr::getBitCast(NamePtr, llvm::Type::getInt8PtrTy(Ctx))); -  CoverageMappings.push_back(CoverageMapping); - -  if (CGM.getCodeGenOpts().DumpCoverageMapping) { -    // Dump the coverage mapping data for this function by decoding the -    // encoded data. This allows us to dump the mapping regions which were -    // also processed by the CoverageMappingWriter which performs -    // additional minimization operations such as reducing the number of -    // expressions. -    std::vector<StringRef> Filenames; -    std::vector<CounterExpression> Expressions; -    std::vector<CounterMappingRegion> Regions; -    llvm::SmallVector<std::string, 16> FilenameStrs; -    llvm::SmallVector<StringRef, 16> FilenameRefs; -    FilenameStrs.resize(FileEntries.size()); -    FilenameRefs.resize(FileEntries.size()); -    for (const auto &Entry : FileEntries) { -      auto I = Entry.second; -      FilenameStrs[I] = normalizeFilename(Entry.first->getName()); -      FilenameRefs[I] = FilenameStrs[I]; -    } -    RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames, -                                    Expressions, Regions); -    if (Reader.read()) -      return; -    dump(llvm::outs(), NameValue, Expressions, Regions); -  } -} - -void CoverageMappingModuleGen::emit() { -  if (FunctionRecords.empty()) -    return; -  llvm::LLVMContext &Ctx = CGM.getLLVMContext(); -  auto *Int32Ty = llvm::Type::getInt32Ty(Ctx); - -  // Create the filenames and merge them with coverage mappings -  llvm::SmallVector<std::string, 16> FilenameStrs; -  llvm::SmallVector<StringRef, 16> FilenameRefs; -  FilenameStrs.resize(FileEntries.size()); -  FilenameRefs.resize(FileEntries.size()); -  for (const auto &Entry : FileEntries) { -    auto I = Entry.second; -    FilenameStrs[I] = normalizeFilename(Entry.first->getName()); -    FilenameRefs[I] = FilenameStrs[I]; -  } - -  std::string FilenamesAndCoverageMappings; -  llvm::raw_string_ostream OS(FilenamesAndCoverageMappings); -  CoverageFilenamesSectionWriter(FilenameRefs).write(OS); - -  // Stream the content of CoverageMappings to OS while keeping -  // memory consumption under control. -  size_t CoverageMappingSize = 0; -  for (auto &S : CoverageMappings) { -    CoverageMappingSize += S.size(); -    OS << S; -    S.clear(); -    S.shrink_to_fit(); -  } -  CoverageMappings.clear(); -  CoverageMappings.shrink_to_fit(); - -  size_t FilenamesSize = OS.str().size() - CoverageMappingSize; -  // Append extra zeroes if necessary to ensure that the size of the filenames -  // and coverage mappings is a multiple of 8. -  if (size_t Rem = OS.str().size() % 8) { -    CoverageMappingSize += 8 - Rem; -    OS.write_zeros(8 - Rem); -  } -  auto *FilenamesAndMappingsVal = -      llvm::ConstantDataArray::getString(Ctx, OS.str(), false); - -  // Create the deferred function records array -  auto RecordsTy = -      llvm::ArrayType::get(FunctionRecordTy, FunctionRecords.size()); -  auto RecordsVal = llvm::ConstantArray::get(RecordsTy, FunctionRecords); - -  llvm::Type *CovDataHeaderTypes[] = { -#define COVMAP_HEADER(Type, LLVMType, Name, Init) LLVMType, -#include "llvm/ProfileData/InstrProfData.inc" -  }; -  auto CovDataHeaderTy = -      llvm::StructType::get(Ctx, makeArrayRef(CovDataHeaderTypes)); -  llvm::Constant *CovDataHeaderVals[] = { -#define COVMAP_HEADER(Type, LLVMType, Name, Init) Init, -#include "llvm/ProfileData/InstrProfData.inc" -  }; -  auto CovDataHeaderVal = llvm::ConstantStruct::get( -      CovDataHeaderTy, makeArrayRef(CovDataHeaderVals)); - -  // Create the coverage data record -  llvm::Type *CovDataTypes[] = {CovDataHeaderTy, RecordsTy, -                                FilenamesAndMappingsVal->getType()}; -  auto CovDataTy = llvm::StructType::get(Ctx, makeArrayRef(CovDataTypes)); -  llvm::Constant *TUDataVals[] = {CovDataHeaderVal, RecordsVal, -                                  FilenamesAndMappingsVal}; -  auto CovDataVal = -      llvm::ConstantStruct::get(CovDataTy, makeArrayRef(TUDataVals)); -  auto CovData = new llvm::GlobalVariable( -      CGM.getModule(), CovDataTy, true, llvm::GlobalValue::InternalLinkage, -      CovDataVal, llvm::getCoverageMappingVarName()); - -  CovData->setSection(getCoverageSection(CGM)); -  CovData->setAlignment(8); - -  // Make sure the data doesn't get deleted. -  CGM.addUsedGlobal(CovData); -  // Create the deferred function records array -  if (!FunctionNames.empty()) { -    auto NamesArrTy = llvm::ArrayType::get(llvm::Type::getInt8PtrTy(Ctx), -                                           FunctionNames.size()); -    auto NamesArrVal = llvm::ConstantArray::get(NamesArrTy, FunctionNames); -    // This variable will *NOT* be emitted to the object file. It is used -    // to pass the list of names referenced to codegen. -    new llvm::GlobalVariable(CGM.getModule(), NamesArrTy, true, -                             llvm::GlobalValue::InternalLinkage, NamesArrVal, -                             llvm::getCoverageUnusedNamesVarName()); -  } -} - -unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) { -  auto It = FileEntries.find(File); -  if (It != FileEntries.end()) -    return It->second; -  unsigned FileID = FileEntries.size(); -  FileEntries.insert(std::make_pair(File, FileID)); -  return FileID; -} - -void CoverageMappingGen::emitCounterMapping(const Decl *D, -                                            llvm::raw_ostream &OS) { -  assert(CounterMap); -  CounterCoverageMappingBuilder Walker(CVM, *CounterMap, SM, LangOpts); -  Walker.VisitDecl(D); -  Walker.write(OS); -} - -void CoverageMappingGen::emitEmptyMapping(const Decl *D, -                                          llvm::raw_ostream &OS) { -  EmptyCoverageMappingBuilder Walker(CVM, SM, LangOpts); -  Walker.VisitDecl(D); -  Walker.write(OS); -}  | 
