diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp')
| -rw-r--r-- | contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp | 1260 | 
1 files changed, 571 insertions, 689 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp index 6f159d47375e..9ad5d14edfdc 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -15,6 +15,7 @@  #include "CodeGenFunction.h"  #include "clang/AST/StmtVisitor.h"  #include "clang/Lex/Lexer.h" +#include "llvm/ADT/Optional.h"  #include "llvm/ProfileData/CoverageMapping.h"  #include "llvm/ProfileData/CoverageMappingReader.h"  #include "llvm/ProfileData/CoverageMappingWriter.h" @@ -33,87 +34,50 @@ namespace {  /// \brief A region of source code that can be mapped to a counter.  class SourceMappingRegion { -public: -  enum RegionFlags { -    /// \brief This region won't be emitted if it wasn't extended. -    /// This is useful so that we won't emit source ranges for single tokens -    /// that we don't really care that much about, like: -    ///   the '(' token in #define MACRO ( -    IgnoreIfNotExtended = 0x0001, -  }; - -private: -  FileID File, MacroArgumentFile; -    Counter Count; -  /// \brief A statement that initiated the count of Zero. -  /// -  /// This initiator statement is useful to prevent merging of unreachable -  /// regions with different statements that caused the counter to become -  /// unreachable. -  const Stmt *UnreachableInitiator; - -  /// \brief A statement that separates certain mapping regions into groups. -  /// -  /// The group statement is sometimes useful when we are emitting the source -  /// regions not in their correct lexical order, e.g. the regions for the -  /// incrementation expression in the 'for' construct. By marking the regions -  /// in the incrementation expression with the group statement, we avoid the -  /// merging of the regions from the incrementation expression and the loop's -  /// body. -  const Stmt *Group; -    /// \brief The region's starting location. -  SourceLocation LocStart; +  Optional<SourceLocation> LocStart;    /// \brief The region's ending location. -  SourceLocation LocEnd, AlternativeLocEnd; -  unsigned Flags; +  Optional<SourceLocation> LocEnd;  public: -  SourceMappingRegion(FileID File, FileID MacroArgumentFile, Counter Count, -                      const Stmt *UnreachableInitiator, const Stmt *Group, -                      SourceLocation LocStart, SourceLocation LocEnd, -                      unsigned Flags = 0) -      : File(File), MacroArgumentFile(MacroArgumentFile), Count(Count), -        UnreachableInitiator(UnreachableInitiator), Group(Group), -        LocStart(LocStart), LocEnd(LocEnd), AlternativeLocEnd(LocStart), -        Flags(Flags) {} +  SourceMappingRegion(Counter Count, Optional<SourceLocation> LocStart, +                      Optional<SourceLocation> LocEnd) +      : Count(Count), LocStart(LocStart), LocEnd(LocEnd) {} + +  SourceMappingRegion(SourceMappingRegion &&Region) +      : Count(std::move(Region.Count)), LocStart(std::move(Region.LocStart)), +        LocEnd(std::move(Region.LocEnd)) {} -  const FileID &getFile() const { return File; } +  SourceMappingRegion &operator=(SourceMappingRegion &&RHS) { +    Count = std::move(RHS.Count); +    LocStart = std::move(RHS.LocStart); +    LocEnd = std::move(RHS.LocEnd); +    return *this; +  }    const Counter &getCounter() const { return Count; } -  const SourceLocation &getStartLoc() const { return LocStart; } +  void setCounter(Counter C) { Count = C; } -  const SourceLocation &getEndLoc(const SourceManager &SM) const { -    if (SM.getFileID(LocEnd) != File) -      return AlternativeLocEnd; -    return LocEnd; -  } +  bool hasStartLoc() const { return LocStart.hasValue(); } -  bool hasFlag(RegionFlags Flag) const { return (Flags & Flag) != 0; } +  void setStartLoc(SourceLocation Loc) { LocStart = Loc; } -  void setFlag(RegionFlags Flag) { Flags |= Flag; } +  const SourceLocation &getStartLoc() const { +    assert(LocStart && "Region has no start location"); +    return *LocStart; +  } -  void clearFlag(RegionFlags Flag) { Flags &= ~Flag; } +  bool hasEndLoc() const { return LocEnd.hasValue(); } -  /// \brief Return true if two regions can be merged together. -  bool isMergeable(SourceMappingRegion &R) { -    // FIXME: We allow merging regions with a gap in between them. Should we? -    return File == R.File && MacroArgumentFile == R.MacroArgumentFile && -           Count == R.Count && UnreachableInitiator == R.UnreachableInitiator && -           Group == R.Group; -  } +  void setEndLoc(SourceLocation Loc) { LocEnd = Loc; } -  /// \brief A comparison that sorts such that mergeable regions are adjacent. -  friend bool operator<(const SourceMappingRegion &LHS, -                        const SourceMappingRegion &RHS) { -    return std::tie(LHS.File, LHS.MacroArgumentFile, LHS.Count, -                    LHS.UnreachableInitiator, LHS.Group) < -           std::tie(RHS.File, RHS.MacroArgumentFile, RHS.Count, -                    RHS.UnreachableInitiator, RHS.Group); +  const SourceLocation &getEndLoc() const { +    assert(LocEnd && "Region has no end location"); +    return *LocEnd;    }  }; @@ -126,26 +90,11 @@ public:    const LangOptions &LangOpts;  private: -  struct FileInfo { -    /// \brief The file id that will be used by the coverage mapping system. -    unsigned CovMappingFileID; -    const FileEntry *Entry; - -    FileInfo(unsigned CovMappingFileID, const FileEntry *Entry) -        : CovMappingFileID(CovMappingFileID), Entry(Entry) {} -  }; - -  /// \brief This mapping maps clang's FileIDs to file ids used -  /// by the coverage mapping system and clang's file entries. -  llvm::SmallDenseMap<FileID, FileInfo, 8> FileIDMapping; +  /// \brief Map of clang's FileIDs to IDs used for coverage mapping. +  llvm::SmallDenseMap<FileID, std::pair<unsigned, SourceLocation>, 8> +      FileIDMapping;  public: -  /// \brief The statement that corresponds to the current source group. -  const Stmt *CurrentSourceGroup; - -  /// \brief The statement the initiated the current unreachable region. -  const Stmt *CurrentUnreachableRegionInitiator; -    /// \brief The coverage mapping regions for this function    llvm::SmallVector<CounterMappingRegion, 32> MappingRegions;    /// \brief The source mapping regions for this function. @@ -153,60 +102,104 @@ public:    CoverageMappingBuilder(CoverageMappingModuleGen &CVM, SourceManager &SM,                           const LangOptions &LangOpts) -      : CVM(CVM), SM(SM), LangOpts(LangOpts), -        CurrentSourceGroup(nullptr), -        CurrentUnreachableRegionInitiator(nullptr) {} +      : CVM(CVM), SM(SM), LangOpts(LangOpts) {}    /// \brief Return the precise end location for the given token.    SourceLocation getPreciseTokenLocEnd(SourceLocation Loc) { -    return Lexer::getLocForEndOfToken(SM.getSpellingLoc(Loc), 0, SM, LangOpts); +    // 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);    } -  /// \brief Create the mapping that maps from the function's file ids to -  /// the indices for the translation unit's filenames. -  void createFileIDMapping(SmallVectorImpl<unsigned> &Mapping) { -    Mapping.resize(FileIDMapping.size(), 0); -    for (const auto &I : FileIDMapping) -      Mapping[I.second.CovMappingFileID] = CVM.getFileID(I.second.Entry); +  /// \brief 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));    } -  /// \brief Get the coverage mapping file id that corresponds to the given -  /// clang file id. If such file id doesn't exist, it gets added to the -  /// mapping that maps from clang's file ids to coverage mapping file ids. -  /// Return true if there was an error getting the coverage mapping file id. -  /// An example of an when this function fails is when the region tries -  /// to get a coverage file id for a location in a built-in macro. -  bool getCoverageFileID(SourceLocation LocStart, FileID File, -                         FileID SpellingFile, unsigned &Result) { -    auto Mapping = FileIDMapping.find(File); -    if (Mapping != FileIDMapping.end()) { -      Result = Mapping->second.CovMappingFileID; -      return false; -    } +  /// \brief 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)); +  } + +  /// \brief Find out where the current file is included or macro is expanded. +  SourceLocation getIncludeOrExpansionLoc(SourceLocation Loc) { +    return Loc.isMacroID() ? SM.getImmediateExpansionRange(Loc).first +                           : SM.getIncludeLoc(SM.getFileID(Loc)); +  } + +  /// \brief Return true if \c Loc is a location in a built-in macro. +  bool isInBuiltin(SourceLocation Loc) { +    return strcmp(SM.getBufferName(SM.getSpellingLoc(Loc)), "<built-in>") == 0; +  } -    auto Entry = SM.getFileEntryForID(SpellingFile); -    if (!Entry) -      return true; +  /// \brief Get the start of \c S ignoring macro arguments and builtin macros. +  SourceLocation getStart(const Stmt *S) { +    SourceLocation Loc = S->getLocStart(); +    while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc)) +      Loc = SM.getImmediateExpansionRange(Loc).first; +    return Loc; +  } -    Result = FileIDMapping.size(); -    FileIDMapping.insert(std::make_pair(File, FileInfo(Result, Entry))); -    createFileExpansionRegion(LocStart, File); -    return false; +  /// \brief Get the end of \c S ignoring macro arguments and builtin macros. +  SourceLocation getEnd(const Stmt *S) { +    SourceLocation Loc = S->getLocEnd(); +    while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc)) +      Loc = SM.getImmediateExpansionRange(Loc).first; +    return getPreciseTokenLocEnd(Loc);    } -  /// \brief Get the coverage mapping file id that corresponds to the given -  /// clang file id. -  /// Return true if there was an error getting the coverage mapping file id. -  bool getExistingCoverageFileID(FileID File, unsigned &Result) { -    // Make sure that the file is valid. -    if (File.isInvalid()) -      return true; -    auto Mapping = FileIDMapping.find(File); -    if (Mapping != FileIDMapping.end()) { -      Result = Mapping->second.CovMappingFileID; -      return false; +  /// \brief 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(); + +    SmallVector<FileID, 8> Visited; +    SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs; +    for (const auto &Region : SourceRegions) { +      SourceLocation Loc = Region.getStartLoc(); +      FileID File = SM.getFileID(Loc); +      if (std::find(Visited.begin(), Visited.end(), File) != Visited.end()) +        continue; +      Visited.push_back(File); + +      unsigned Depth = 0; +      for (SourceLocation Parent = getIncludeOrExpansionLoc(Loc); +           !Parent.isInvalid(); Parent = getIncludeOrExpansionLoc(Parent)) +        ++Depth; +      FileLocs.push_back(std::make_pair(Loc, Depth));      } -    return true; +    std::stable_sort(FileLocs.begin(), FileLocs.end(), 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)); +    } +  } + +  /// \brief 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;    }    /// \brief Return true if the given clang's file id has a corresponding @@ -235,154 +228,83 @@ public:      for (const auto &I : SkippedRanges) {        auto LocStart = I.getBegin();        auto LocEnd = I.getEnd(); -      auto FileStart = SM.getFileID(LocStart); -      if (!hasExistingCoverageFileID(FileStart)) -        continue; -      auto ActualFileStart = SM.getDecomposedSpellingLoc(LocStart).first; -      if (ActualFileStart != SM.getDecomposedSpellingLoc(LocEnd).first) -        // Ignore regions that span across multiple files. -        continue; +      assert(SM.isWrittenInSameFile(LocStart, LocEnd) && +             "region spans multiple files"); -      unsigned CovFileID; -      if (getCoverageFileID(LocStart, FileStart, ActualFileStart, CovFileID)) +      auto CovFileID = getCoverageFileID(LocStart); +      if (!CovFileID)          continue;        unsigned LineStart = SM.getSpellingLineNumber(LocStart);        unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart);        unsigned LineEnd = SM.getSpellingLineNumber(LocEnd);        unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd); -      CounterMappingRegion Region(Counter(), CovFileID, LineStart, ColumnStart, -                                  LineEnd, ColumnEnd, false, -                                  CounterMappingRegion::SkippedRegion); +      auto Region = CounterMappingRegion::makeSkipped( +          *CovFileID, LineStart, ColumnStart, LineEnd, ColumnEnd);        // Make sure that we only collect the regions that are inside        // the souce code of this function. -      if (Region.LineStart >= FileLineRanges[CovFileID].first && -          Region.LineEnd <= FileLineRanges[CovFileID].second) +      if (Region.LineStart >= FileLineRanges[*CovFileID].first && +          Region.LineEnd <= FileLineRanges[*CovFileID].second)          MappingRegions.push_back(Region);      }    } -  /// \brief Create a mapping region that correponds to an expansion of -  /// a macro or an embedded include. -  void createFileExpansionRegion(SourceLocation Loc, FileID ExpandedFile) { -    SourceLocation LocStart; -    if (Loc.isMacroID()) -      LocStart = SM.getImmediateExpansionRange(Loc).first; -    else { -      LocStart = SM.getIncludeLoc(ExpandedFile); -      if (LocStart.isInvalid()) -        return; // This file has no expansion region. -    } - -    auto File = SM.getFileID(LocStart); -    auto SpellingFile = SM.getDecomposedSpellingLoc(LocStart).first; -    unsigned CovFileID, ExpandedFileID; -    if (getExistingCoverageFileID(ExpandedFile, ExpandedFileID)) -      return; -    if (getCoverageFileID(LocStart, File, SpellingFile, CovFileID)) -      return; -    unsigned LineStart = SM.getSpellingLineNumber(LocStart); -    unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart); -    unsigned LineEnd = LineStart; -    // Compute the end column manually as Lexer::getLocForEndOfToken doesn't -    // give the correct result in all cases. -    unsigned ColumnEnd = -        ColumnStart + -        Lexer::MeasureTokenLength(SM.getSpellingLoc(LocStart), SM, LangOpts); - -    MappingRegions.push_back(CounterMappingRegion( -        Counter(), CovFileID, LineStart, ColumnStart, LineEnd, ColumnEnd, -        false, CounterMappingRegion::ExpansionRegion)); -    MappingRegions.back().ExpandedFileID = ExpandedFileID; -  } - -  /// \brief Enter a source region group that is identified by the given -  /// statement. -  /// It's not possible to enter a group when there is already -  /// another group present. -  void beginSourceRegionGroup(const Stmt *Group) { -    assert(!CurrentSourceGroup); -    CurrentSourceGroup = Group; -  } - -  /// \brief Exit the current source region group. -  void endSourceRegionGroup() { CurrentSourceGroup = nullptr; } - -  /// \brief Associate a counter with a given source code range. -  void mapSourceCodeRange(SourceLocation LocStart, SourceLocation LocEnd, -                          Counter Count, const Stmt *UnreachableInitiator, -                          const Stmt *SourceGroup, unsigned Flags = 0, -                          FileID MacroArgumentFile = FileID()) { -    if (SM.isMacroArgExpansion(LocStart)) { -      // Map the code range with the macro argument's value. -      mapSourceCodeRange(SM.getImmediateSpellingLoc(LocStart), -                         SM.getImmediateSpellingLoc(LocEnd), Count, -                         UnreachableInitiator, SourceGroup, Flags, -                         SM.getFileID(LocStart)); -      // Map the code range where the macro argument is referenced. -      SourceLocation RefLocStart(SM.getImmediateExpansionRange(LocStart).first); -      SourceLocation RefLocEnd(RefLocStart); -      if (SM.isMacroArgExpansion(RefLocStart)) -        mapSourceCodeRange(RefLocStart, RefLocEnd, Count, UnreachableInitiator, -                           SourceGroup, 0, SM.getFileID(RefLocStart)); -      else -        mapSourceCodeRange(RefLocStart, RefLocEnd, Count, UnreachableInitiator, -                           SourceGroup); -      return; -    } -    auto File = SM.getFileID(LocStart); -    // Make sure that the file id is valid. -    if (File.isInvalid()) -      return; -    SourceRegions.emplace_back(File, MacroArgumentFile, Count, -                               UnreachableInitiator, SourceGroup, LocStart, -                               LocEnd, Flags); -  } - -  void mapSourceCodeRange(SourceLocation LocStart, SourceLocation LocEnd, -                          Counter Count, unsigned Flags = 0) { -    mapSourceCodeRange(LocStart, LocEnd, Count, -                       CurrentUnreachableRegionInitiator, CurrentSourceGroup, -                       Flags); -  } -    /// \brief Generate the coverage counter mapping regions from collected    /// source regions.    void emitSourceRegions() { -    std::sort(SourceRegions.begin(), SourceRegions.end()); - -    for (auto I = SourceRegions.begin(), E = SourceRegions.end(); I != E; ++I) { -      // Keep the original start location of this region. -      SourceLocation LocStart = I->getStartLoc(); -      SourceLocation LocEnd = I->getEndLoc(SM); - -      bool Ignore = I->hasFlag(SourceMappingRegion::IgnoreIfNotExtended); -      // We need to handle mergeable regions together. -      for (auto Next = I + 1; Next != E && Next->isMergeable(*I); ++Next) { -        ++I; -        LocStart = std::min(LocStart, I->getStartLoc()); -        LocEnd = std::max(LocEnd, I->getEndLoc(SM)); -        // FIXME: Should we && together the Ignore flag of multiple regions? -        Ignore = false; -      } -      if (Ignore) +    for (const auto &Region : SourceRegions) { +      assert(Region.hasEndLoc() && "incomplete region"); + +      SourceLocation LocStart = Region.getStartLoc(); +      assert(!SM.getFileID(LocStart).isInvalid() && "region in invalid file"); + +      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"); +        // Find the spilling locations for the mapping region. -      LocEnd = getPreciseTokenLocEnd(LocEnd);        unsigned LineStart = SM.getSpellingLineNumber(LocStart);        unsigned ColumnStart = SM.getSpellingColumnNumber(LocStart);        unsigned LineEnd = SM.getSpellingLineNumber(LocEnd);        unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd); -      auto SpellingFile = SM.getDecomposedSpellingLoc(LocStart).first; -      unsigned CovFileID; -      if (getCoverageFileID(LocStart, I->getFile(), SpellingFile, CovFileID)) +      assert(LineStart <= LineEnd && "region start and end out of order"); +      MappingRegions.push_back(CounterMappingRegion::makeRegion( +          Region.getCounter(), *CovFileID, LineStart, ColumnStart, LineEnd, +          ColumnEnd)); +    } +  } + +  /// \brief Generate expansion regions for each virtual file we've seen. +  void emitExpansionRegions() { +    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"); -      assert(LineStart <= LineEnd); -      MappingRegions.push_back(CounterMappingRegion( -          I->getCounter(), CovFileID, LineStart, ColumnStart, LineEnd, -          ColumnEnd, false, CounterMappingRegion::CodeRegion)); +      unsigned LineStart = SM.getSpellingLineNumber(ParentLoc); +      unsigned ColumnStart = SM.getSpellingColumnNumber(ParentLoc); +      unsigned LineEnd = SM.getSpellingLineNumber(LocEnd); +      unsigned ColumnEnd = SM.getSpellingColumnNumber(LocEnd); + +      MappingRegions.push_back(CounterMappingRegion::makeExpansion( +          *ParentFileID, *ExpandedFileID, LineStart, ColumnStart, LineEnd, +          ColumnEnd));      }    }  }; @@ -398,14 +320,14 @@ struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder {      if (!D->hasBody())        return;      auto Body = D->getBody(); -    mapSourceCodeRange(Body->getLocStart(), Body->getLocEnd(), Counter()); +    SourceRegions.emplace_back(Counter(), getStart(Body), getEnd(Body));    }    /// \brief Write the mapping data to the output stream    void write(llvm::raw_ostream &OS) { -    emitSourceRegions();      SmallVector<unsigned, 16> FileIDMapping; -    createFileIDMapping(FileIDMapping); +    gatherFileIDs(FileIDMapping); +    emitSourceRegions();      CoverageMappingWriter Writer(FileIDMapping, None, MappingRegions);      Writer.write(OS); @@ -420,136 +342,215 @@ struct CounterCoverageMappingBuilder    /// \brief The map of statements to count values.    llvm::DenseMap<const Stmt *, unsigned> &CounterMap; -  Counter CurrentRegionCount; +  /// \brief A stack of currently live regions. +  std::vector<SourceMappingRegion> RegionStack;    CounterExpressionBuilder Builder; -  /// \brief Return a counter that represents the -  /// expression that subracts rhs from lhs. +  /// \brief 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; + +  /// \brief Return a counter for the subtraction of \c RHS from \c LHS    Counter subtractCounters(Counter LHS, Counter RHS) {      return Builder.subtract(LHS, RHS);    } -  /// \brief Return a counter that represents the -  /// the exression that adds lhs and rhs. +  /// \brief 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); +  } + +  Counter addCounters(Counter C1, Counter C2, Counter C3, Counter C4) { +    return addCounters(addCounters(C1, C2, C3), C4); +  } +    /// \brief Return the region counter for the given statement. +  ///    /// This should only be called on statements that have a dedicated counter. -  unsigned getRegionCounter(const Stmt *S) { return CounterMap[S]; } +  Counter getRegionCounter(const Stmt *S) { +    return Counter::getCounter(CounterMap[S]); +  } + +  /// \brief 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; +    RegionStack.emplace_back(Count, StartLoc, EndLoc); -  /// \brief Return the region count for the counter at the given index. -  Counter getRegionCount(unsigned CounterId) { -    return Counter::getCounter(CounterId); +    return RegionStack.size() - 1;    } -  /// \brief Return the counter value of the current region. -  Counter getCurrentRegionCount() { return CurrentRegionCount; } +  /// \brief 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"); +    while (RegionStack.size() > ParentIndex) { +      SourceMappingRegion &Region = RegionStack.back(); +      if (Region.hasStartLoc()) { +        SourceLocation StartLoc = Region.getStartLoc(); +        SourceLocation EndLoc = Region.hasEndLoc() +                                    ? Region.getEndLoc() +                                    : RegionStack[ParentIndex].getEndLoc(); +        while (!SM.isWrittenInSameFile(StartLoc, EndLoc)) { +          // 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)); + +          SourceRegions.emplace_back(Region.getCounter(), NestedLoc, EndLoc); + +          EndLoc = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(EndLoc)); +          assert(!EndLoc.isInvalid() && +                 "File exit was not handled before popRegions"); +        } +        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.getStartLoc(), EndLoc)); +        SourceRegions.push_back(std::move(Region)); +      } +      RegionStack.pop_back(); +    } +  } -  /// \brief Set the counter value for the current region. -  /// This is used to keep track of changes to the most recent counter -  /// from control flow and non-local exits. -  void setCurrentRegionCount(Counter Count) { -    CurrentRegionCount = Count; -    CurrentUnreachableRegionInitiator = nullptr; +  /// \brief Return the currently active region. +  SourceMappingRegion &getRegion() { +    assert(!RegionStack.empty() && "statement has no region"); +    return RegionStack.back();    } -  /// \brief Indicate that the current region is never reached, -  /// and thus should have a counter value of zero. -  /// This is important so that subsequent regions can correctly track -  /// their parent counts. -  void setCurrentRegionUnreachable(const Stmt *Initiator) { -    CurrentRegionCount = Counter::getZero(); -    CurrentUnreachableRegionInitiator = Initiator; +  /// \brief Propagate counts through the children of \c S. +  Counter propagateCounts(Counter TopCount, const Stmt *S) { +    size_t Index = pushRegion(TopCount, getStart(S), getEnd(S)); +    Visit(S); +    Counter ExitCount = getRegion().getCounter(); +    popRegions(Index); +    return ExitCount;    } -  /// \brief A counter for a particular region. -  /// This is the primary interface through -  /// which the coverage mapping builder manages counters and their values. -  class RegionMapper { -    CounterCoverageMappingBuilder &Mapping; -    Counter Count; -    Counter ParentCount; -    Counter RegionCount; -    Counter Adjust; - -  public: -    RegionMapper(CounterCoverageMappingBuilder *Mapper, const Stmt *S) -        : Mapping(*Mapper), -          Count(Mapper->getRegionCount(Mapper->getRegionCounter(S))), -          ParentCount(Mapper->getCurrentRegionCount()) {} - -    /// Get the value of the counter. In most cases this is the number of times -    /// the region of the counter was entered, but for switch labels it's the -    /// number of direct jumps to that label. -    Counter getCount() const { return Count; } - -    /// Get the value of the counter with adjustments applied. Adjustments occur -    /// when control enters or leaves the region abnormally; i.e., if there is a -    /// jump to a label within the region, or if the function can return from -    /// within the region. The adjusted count, then, is the value of the counter -    /// at the end of the region. -    Counter getAdjustedCount() const { -      return Mapping.addCounters(Count, Adjust); -    } +  /// \brief 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; +    // Avoid adding duplicate regions if we have a completed region on the top +    // of the stack and are adjusting to the end of a virtual file. +    if (getRegion().hasEndLoc() && +        MostRecentLocation == getEndOfFileOrMacro(MostRecentLocation)) +      MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation); +  } + +  /// \brief 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 value of the counter in this region's parent, i.e., the region -    /// that was active when this region began. This is useful for deriving -    /// counts in implicitly counted regions, like the false case of a condition -    /// or the normal exits of a loop. -    Counter getParentCount() const { return ParentCount; } - -    /// Activate the counter by emitting an increment and starting to track -    /// adjustments. If AddIncomingFallThrough is true, the current region count -    /// will be added to the counter for the purposes of tracking the region. -    void beginRegion(bool AddIncomingFallThrough = false) { -      RegionCount = Count; -      if (AddIncomingFallThrough) -        RegionCount = -            Mapping.addCounters(RegionCount, Mapping.getCurrentRegionCount()); -      Mapping.setCurrentRegionCount(RegionCount); -    } +  /// \brief 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 (SM.isWrittenInSameFile(MostRecentLocation, NewLoc)) +      return; -    /// For counters on boolean branches, begins tracking adjustments for the -    /// uncounted path. -    void beginElseRegion() { -      RegionCount = Mapping.subtractCounters(ParentCount, Count); -      Mapping.setCurrentRegionCount(RegionCount); +    // 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);      } -    /// Reset the current region count. -    void setCurrentRegionCount(Counter CurrentCount) { -      RegionCount = CurrentCount; -      Mapping.setCurrentRegionCount(RegionCount); -    } +    llvm::SmallSet<SourceLocation, 8> StartLocs; +    Optional<Counter> ParentCounter; +    for (auto I = RegionStack.rbegin(), E = RegionStack.rend(); I != E; ++I) { +      if (!I->hasStartLoc()) +        continue; +      SourceLocation Loc = I->getStartLoc(); +      if (!isNestedIn(Loc, ParentFile)) { +        ParentCounter = I->getCounter(); +        break; +      } -    /// Adjust for non-local control flow after emitting a subexpression or -    /// substatement. This must be called to account for constructs such as -    /// gotos, -    /// labels, and returns, so that we can ensure that our region's count is -    /// correct in the code that follows. -    void adjustForControlFlow() { -      Adjust = Mapping.addCounters( -          Adjust, Mapping.subtractCounters(Mapping.getCurrentRegionCount(), -                                           RegionCount)); -      // Reset the region count in case this is called again later. -      RegionCount = Mapping.getCurrentRegionCount(); +      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));      } -    /// Commit all adjustments to the current region. If the region is a loop, -    /// the LoopAdjust value should be the count of all the breaks and continues -    /// from the loop, to compensate for those counts being deducted from the -    /// adjustments for the body of the loop. -    void applyAdjustmentsToRegion() { -      Mapping.setCurrentRegionCount(Mapping.addCounters(ParentCount, Adjust)); -    } -    void applyAdjustmentsToRegion(Counter LoopAdjust) { -      Mapping.setCurrentRegionCount(Mapping.addCounters( -          Mapping.addCounters(ParentCount, Adjust), LoopAdjust)); +    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)); +        Loc = getIncludeOrExpansionLoc(Loc); +      }      } -  }; + +    MostRecentLocation = NewLoc; +  } + +  /// \brief 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); +  } + +  /// \brief Mark \c S as a terminator, starting a zero region. +  void terminateRegion(const Stmt *S) { +    extendRegion(S); +    SourceMappingRegion &Region = getRegion(); +    if (!Region.hasEndLoc()) +      Region.setEndLoc(getEnd(S)); +    pushRegion(Counter::getZero()); +  }    /// \brief Keep counts of breaks and continues inside loops.    struct BreakContinue { @@ -566,437 +567,321 @@ struct CounterCoverageMappingBuilder    /// \brief Write the mapping data to the output stream    void write(llvm::raw_ostream &OS) { -    emitSourceRegions();      llvm::SmallVector<unsigned, 8> VirtualFileMapping; -    createFileIDMapping(VirtualFileMapping); +    gatherFileIDs(VirtualFileMapping); +    emitSourceRegions(); +    emitExpansionRegions();      gatherSkippedRegions(); -    CoverageMappingWriter Writer( -        VirtualFileMapping, Builder.getExpressions(), MappingRegions); +    CoverageMappingWriter Writer(VirtualFileMapping, Builder.getExpressions(), +                                 MappingRegions);      Writer.write(OS);    } -  /// \brief Associate the source code range with the current region count. -  void mapSourceCodeRange(SourceLocation LocStart, SourceLocation LocEnd, -                          unsigned Flags = 0) { -    CoverageMappingBuilder::mapSourceCodeRange(LocStart, LocEnd, -                                               CurrentRegionCount, Flags); -  } - -  void mapSourceCodeRange(SourceLocation LocStart) { -    CoverageMappingBuilder::mapSourceCodeRange(LocStart, LocStart, -                                               CurrentRegionCount); -  } - -  /// \brief Associate the source range of a token with the current region -  /// count. -  /// Ignore the source range for this token if it produces a distinct -  /// mapping region with no other source ranges. -  void mapToken(SourceLocation LocStart) { -    CoverageMappingBuilder::mapSourceCodeRange( -        LocStart, LocStart, CurrentRegionCount, -        SourceMappingRegion::IgnoreIfNotExtended); -  } -    void VisitStmt(const Stmt *S) { -    mapSourceCodeRange(S->getLocStart()); +    if (!S->getLocStart().isInvalid()) +      extendRegion(S);      for (Stmt::const_child_range I = S->children(); I; ++I) {        if (*I)          this->Visit(*I);      } +    handleFileExit(getEnd(S));    }    void VisitDecl(const Decl *D) { -    if (!D->hasBody()) -      return; -    // Counter tracks entry to the function body. -    auto Body = D->getBody(); -    RegionMapper Cnt(this, Body); -    Cnt.beginRegion(); -    Visit(Body); -  } - -  void VisitDeclStmt(const DeclStmt *S) { -    mapSourceCodeRange(S->getLocStart()); -    for (Stmt::const_child_range I = static_cast<const Stmt *>(S)->children(); -         I; ++I) { -      if (*I) -        this->Visit(*I); -    } -  } - -  void VisitCompoundStmt(const CompoundStmt *S) { -    mapSourceCodeRange(S->getLBracLoc()); -    mapSourceCodeRange(S->getRBracLoc()); -    for (Stmt::const_child_range I = S->children(); I; ++I) { -      if (*I) -        this->Visit(*I); -    } +    Stmt *Body = D->getBody(); +    propagateCounts(getRegionCounter(Body), Body);    }    void VisitReturnStmt(const ReturnStmt *S) { -    mapSourceCodeRange(S->getLocStart()); +    extendRegion(S);      if (S->getRetValue())        Visit(S->getRetValue()); -    setCurrentRegionUnreachable(S); +    terminateRegion(S);    } -  void VisitGotoStmt(const GotoStmt *S) { -    mapSourceCodeRange(S->getLocStart()); -    mapToken(S->getLabelLoc()); -    setCurrentRegionUnreachable(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 tracks the block following the label. -    RegionMapper Cnt(this, S); -    Cnt.beginRegion(); -    mapSourceCodeRange(S->getLocStart()); -    // Can't map the ':' token as its location isn't known. +    SourceLocation Start = getStart(S); +    // We can't extendRegion here or we risk overlapping with our new region. +    handleFileExit(Start); +    pushRegion(getRegionCounter(S), Start);      Visit(S->getSubStmt());    }    void VisitBreakStmt(const BreakStmt *S) { -    mapSourceCodeRange(S->getLocStart());      assert(!BreakContinueStack.empty() && "break not in a loop or switch!");      BreakContinueStack.back().BreakCount = addCounters( -        BreakContinueStack.back().BreakCount, getCurrentRegionCount()); -    setCurrentRegionUnreachable(S); +        BreakContinueStack.back().BreakCount, getRegion().getCounter()); +    terminateRegion(S);    }    void VisitContinueStmt(const ContinueStmt *S) { -    mapSourceCodeRange(S->getLocStart());      assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");      BreakContinueStack.back().ContinueCount = addCounters( -        BreakContinueStack.back().ContinueCount, getCurrentRegionCount()); -    setCurrentRegionUnreachable(S); +        BreakContinueStack.back().ContinueCount, getRegion().getCounter()); +    terminateRegion(S);    }    void VisitWhileStmt(const WhileStmt *S) { -    mapSourceCodeRange(S->getLocStart()); -    // Counter tracks the body of the loop. -    RegionMapper Cnt(this, 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()); -    // Visit the body region first so the break/continue adjustments can be -    // included when visiting the condition. -    Cnt.beginRegion(); -    Visit(S->getBody()); -    Cnt.adjustForControlFlow(); - -    // ...then go back and propagate counts through the condition. The count -    // at the start of the condition is the sum of the incoming edges, -    // the backedge from the end of the loop body, and the edges from -    // continue statements. +    extendRegion(S->getBody()); +    Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());      BreakContinue BC = BreakContinueStack.pop_back_val(); -    Cnt.setCurrentRegionCount( -        addCounters(Cnt.getParentCount(), -                    addCounters(Cnt.getAdjustedCount(), BC.ContinueCount))); -    beginSourceRegionGroup(S->getCond()); -    Visit(S->getCond()); -    endSourceRegionGroup(); -    Cnt.adjustForControlFlow(); -    Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, BC.ContinueCount)); + +    // Go back to handle the condition. +    Counter CondCount = +        addCounters(ParentCount, BackedgeCount, BC.ContinueCount); +    propagateCounts(CondCount, S->getCond()); +    adjustForOutOfOrderTraversal(getEnd(S)); + +    Counter OutCount = +        addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); +    if (OutCount != ParentCount) +      pushRegion(OutCount);    }    void VisitDoStmt(const DoStmt *S) { -    mapSourceCodeRange(S->getLocStart()); -    // Counter tracks the body of the loop. -    RegionMapper Cnt(this, S); -    BreakContinueStack.push_back(BreakContinue()); -    Cnt.beginRegion(/*AddIncomingFallThrough=*/true); -    Visit(S->getBody()); -    Cnt.adjustForControlFlow(); +    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(); -    // The count at the start of the condition is equal to the count at the -    // end of the body. The adjusted count does not include either the -    // fall-through count coming into the loop or the continue count, so add -    // both of those separately. This is coincidentally the same equation as -    // with while loops but for different reasons. -    Cnt.setCurrentRegionCount( -        addCounters(Cnt.getParentCount(), -                    addCounters(Cnt.getAdjustedCount(), BC.ContinueCount))); -    Visit(S->getCond()); -    Cnt.adjustForControlFlow(); -    Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, BC.ContinueCount)); + +    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) { -    mapSourceCodeRange(S->getLocStart()); +    extendRegion(S);      if (S->getInit())        Visit(S->getInit()); -    // Counter tracks the body of the loop. -    RegionMapper Cnt(this, 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()); -    // Visit the body region first. (This is basically the same as a while -    // loop; see further comments in VisitWhileStmt.) -    Cnt.beginRegion(); -    Visit(S->getBody()); -    Cnt.adjustForControlFlow(); +    extendRegion(S->getBody()); +    Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); +    BreakContinue BC = BreakContinueStack.pop_back_val();      // The increment is essentially part of the body but it needs to include      // the count for all the continue statements. -    if (S->getInc()) { -      Cnt.setCurrentRegionCount(addCounters( -          getCurrentRegionCount(), BreakContinueStack.back().ContinueCount)); -      beginSourceRegionGroup(S->getInc()); -      Visit(S->getInc()); -      endSourceRegionGroup(); -      Cnt.adjustForControlFlow(); +    if (const Stmt *Inc = S->getInc()) +      propagateCounts(addCounters(BackedgeCount, BC.ContinueCount), Inc); + +    // Go back to handle the condition. +    Counter CondCount = +        addCounters(ParentCount, BackedgeCount, BC.ContinueCount); +    if (const Expr *Cond = S->getCond()) { +      propagateCounts(CondCount, Cond); +      adjustForOutOfOrderTraversal(getEnd(S));      } -    BreakContinue BC = BreakContinueStack.pop_back_val(); - -    // ...then go back and propagate counts through the condition. -    if (S->getCond()) { -      Cnt.setCurrentRegionCount( -          addCounters(addCounters(Cnt.getParentCount(), Cnt.getAdjustedCount()), -                      BC.ContinueCount)); -      beginSourceRegionGroup(S->getCond()); -      Visit(S->getCond()); -      endSourceRegionGroup(); -      Cnt.adjustForControlFlow(); -    } -    Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, BC.ContinueCount)); +    Counter OutCount = +        addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount)); +    if (OutCount != ParentCount) +      pushRegion(OutCount);    }    void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { -    mapSourceCodeRange(S->getLocStart()); +    extendRegion(S); +    Visit(S->getLoopVarStmt());      Visit(S->getRangeStmt()); -    Visit(S->getBeginEndStmt()); -    // Counter tracks the body of the loop. -    RegionMapper Cnt(this, S); + +    Counter ParentCount = getRegion().getCounter(); +    Counter BodyCount = getRegionCounter(S); +      BreakContinueStack.push_back(BreakContinue()); -    // Visit the body region first. (This is basically the same as a while -    // loop; see further comments in VisitWhileStmt.) -    Cnt.beginRegion(); -    Visit(S->getBody()); -    Cnt.adjustForControlFlow(); +    extendRegion(S->getBody()); +    Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());      BreakContinue BC = BreakContinueStack.pop_back_val(); -    Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, BC.ContinueCount)); + +    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) { -    mapSourceCodeRange(S->getLocStart()); +    extendRegion(S);      Visit(S->getElement()); -    // Counter tracks the body of the loop. -    RegionMapper Cnt(this, S); + +    Counter ParentCount = getRegion().getCounter(); +    Counter BodyCount = getRegionCounter(S); +      BreakContinueStack.push_back(BreakContinue()); -    Cnt.beginRegion(); -    Visit(S->getBody()); +    extendRegion(S->getBody()); +    Counter BackedgeCount = propagateCounts(BodyCount, S->getBody());      BreakContinue BC = BreakContinueStack.pop_back_val(); -    Cnt.adjustForControlFlow(); -    Cnt.applyAdjustmentsToRegion(addCounters(BC.BreakCount, BC.ContinueCount)); + +    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) { -    mapSourceCodeRange(S->getLocStart()); +    extendRegion(S);      Visit(S->getCond()); +      BreakContinueStack.push_back(BreakContinue()); -    // Map the '}' for the body to have the same count as the regions after -    // the switch. -    SourceLocation RBracLoc; -    if (const auto *CS = dyn_cast<CompoundStmt>(S->getBody())) { -      mapSourceCodeRange(CS->getLBracLoc()); -      setCurrentRegionUnreachable(S); -      for (Stmt::const_child_range I = CS->children(); I; ++I) { -        if (*I) -          this->Visit(*I); + +    const Stmt *Body = S->getBody(); +    extendRegion(Body); +    if (const auto *CS = dyn_cast<CompoundStmt>(Body)) { +      if (!CS->body_empty()) { +        // The body of the switch needs a zero region so that fallthrough counts +        // behave correctly, but it would be misleading to include the braces of +        // the compound statement in the zeroed area, so we need to handle this +        // specially. +        size_t Index = +            pushRegion(Counter::getZero(), getStart(CS->body_front()), +                       getEnd(CS->body_back())); +        for (const auto *Child : CS->children()) +          Visit(Child); +        popRegions(Index);        } -      RBracLoc = CS->getRBracLoc(); -    } else { -      setCurrentRegionUnreachable(S); -      Visit(S->getBody()); -    } -    // If the switch is inside a loop, add the continue counts. +    } else +      propagateCounts(Counter::getZero(), Body);      BreakContinue BC = BreakContinueStack.pop_back_val(); +      if (!BreakContinueStack.empty())        BreakContinueStack.back().ContinueCount = addCounters(            BreakContinueStack.back().ContinueCount, BC.ContinueCount); -    // Counter tracks the exit block of the switch. -    RegionMapper ExitCnt(this, S); -    ExitCnt.beginRegion(); -    if (RBracLoc.isValid()) -      mapSourceCodeRange(RBracLoc); -  } -  void VisitCaseStmt(const CaseStmt *S) { -    // Counter for this particular case. This counts only jumps from the -    // switch header and does not include fallthrough from the case before -    // this one. -    RegionMapper Cnt(this, S); -    Cnt.beginRegion(/*AddIncomingFallThrough=*/true); -    mapSourceCodeRange(S->getLocStart()); -    mapToken(S->getColonLoc()); -    Visit(S->getSubStmt()); +    Counter ExitCount = getRegionCounter(S); +    pushRegion(ExitCount);    } -  void VisitDefaultStmt(const DefaultStmt *S) { -    // Counter for this default case. This does not include fallthrough from -    // the previous case. -    RegionMapper Cnt(this, S); -    Cnt.beginRegion(/*AddIncomingFallThrough=*/true); -    mapSourceCodeRange(S->getLocStart()); -    mapToken(S->getColonLoc()); +  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.getStartLoc() == getStart(S)) +      Parent.setCounter(Count); +    else +      pushRegion(Count, getStart(S)); + +    if (const CaseStmt *CS = dyn_cast<CaseStmt>(S)) { +      Visit(CS->getLHS()); +      if (const Expr *RHS = CS->getRHS()) +        Visit(RHS); +    }      Visit(S->getSubStmt());    }    void VisitIfStmt(const IfStmt *S) { -    mapSourceCodeRange(S->getLocStart()); -    Visit(S->getCond()); -    mapToken(S->getElseLoc()); - -    // Counter tracks the "then" part of an if statement. The count for -    // the "else" part, if it exists, will be calculated from this counter. -    RegionMapper Cnt(this, S); -    Cnt.beginRegion(); -    Visit(S->getThen()); -    Cnt.adjustForControlFlow(); - -    if (S->getElse()) { -      Cnt.beginElseRegion(); -      Visit(S->getElse()); -      Cnt.adjustForControlFlow(); -    } -    Cnt.applyAdjustmentsToRegion(); +    extendRegion(S); +    // 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()); + +    extendRegion(S->getThen()); +    Counter OutCount = propagateCounts(ThenCount, S->getThen()); + +    Counter ElseCount = subtractCounters(ParentCount, ThenCount); +    if (const Stmt *Else = S->getElse()) { +      extendRegion(S->getElse()); +      OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else)); +    } else +      OutCount = addCounters(OutCount, ElseCount); + +    if (OutCount != ParentCount) +      pushRegion(OutCount);    }    void VisitCXXTryStmt(const CXXTryStmt *S) { -    mapSourceCodeRange(S->getLocStart()); +    extendRegion(S);      Visit(S->getTryBlock());      for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)        Visit(S->getHandler(I)); -    // Counter tracks the continuation block of the try statement. -    RegionMapper Cnt(this, S); -    Cnt.beginRegion(); + +    Counter ExitCount = getRegionCounter(S); +    pushRegion(ExitCount);    }    void VisitCXXCatchStmt(const CXXCatchStmt *S) { -    mapSourceCodeRange(S->getLocStart()); -    // Counter tracks the catch statement's handler block. -    RegionMapper Cnt(this, S); -    Cnt.beginRegion(); -    Visit(S->getHandlerBlock()); +    extendRegion(S); +    propagateCounts(getRegionCounter(S), S->getHandlerBlock());    }    void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { -    Visit(E->getCond()); -    mapToken(E->getQuestionLoc()); -    mapToken(E->getColonLoc()); +    extendRegion(E); -    // Counter tracks the "true" part of a conditional operator. The -    // count in the "false" part will be calculated from this counter. -    RegionMapper Cnt(this, E); -    Cnt.beginRegion(); -    Visit(E->getTrueExpr()); -    Cnt.adjustForControlFlow(); +    Counter ParentCount = getRegion().getCounter(); +    Counter TrueCount = getRegionCounter(E); -    Cnt.beginElseRegion(); -    Visit(E->getFalseExpr()); -    Cnt.adjustForControlFlow(); +    Visit(E->getCond()); -    Cnt.applyAdjustmentsToRegion(); +    if (!isa<BinaryConditionalOperator>(E)) { +      extendRegion(E->getTrueExpr()); +      propagateCounts(TrueCount, E->getTrueExpr()); +    } +    extendRegion(E->getFalseExpr()); +    propagateCounts(subtractCounters(ParentCount, TrueCount), +                    E->getFalseExpr());    }    void VisitBinLAnd(const BinaryOperator *E) { +    extendRegion(E);      Visit(E->getLHS()); -    mapToken(E->getOperatorLoc()); -    // Counter tracks the right hand side of a logical and operator. -    RegionMapper Cnt(this, E); -    Cnt.beginRegion(); -    Visit(E->getRHS()); -    Cnt.adjustForControlFlow(); -    Cnt.applyAdjustmentsToRegion(); -  } - -  void VisitBinLOr(const BinaryOperator *E) { -    Visit(E->getLHS()); -    mapToken(E->getOperatorLoc()); -    // Counter tracks the right hand side of a logical or operator. -    RegionMapper Cnt(this, E); -    Cnt.beginRegion(); -    Visit(E->getRHS()); -    Cnt.adjustForControlFlow(); -    Cnt.applyAdjustmentsToRegion(); -  } -  void VisitParenExpr(const ParenExpr *E) { -    mapToken(E->getLParen()); -    Visit(E->getSubExpr()); -    mapToken(E->getRParen()); +    extendRegion(E->getRHS()); +    propagateCounts(getRegionCounter(E), E->getRHS());    } -  void VisitBinaryOperator(const BinaryOperator *E) { -    Visit(E->getLHS()); -    mapToken(E->getOperatorLoc()); -    Visit(E->getRHS()); -  } - -  void VisitUnaryOperator(const UnaryOperator *E) { -    bool Postfix = E->isPostfix(); -    if (!Postfix) -      mapToken(E->getOperatorLoc()); -    Visit(E->getSubExpr()); -    if (Postfix) -      mapToken(E->getOperatorLoc()); -  } - -  void VisitMemberExpr(const MemberExpr *E) { -    Visit(E->getBase()); -    mapToken(E->getMemberLoc()); -  } - -  void VisitCallExpr(const CallExpr *E) { -    Visit(E->getCallee()); -    for (const auto &Arg : E->arguments()) -      Visit(Arg); -    mapToken(E->getRParenLoc()); -  } - -  void VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { +  void VisitBinLOr(const BinaryOperator *E) { +    extendRegion(E);      Visit(E->getLHS()); -    Visit(E->getRHS()); -    mapToken(E->getRBracketLoc()); -  } - -  void VisitCStyleCastExpr(const CStyleCastExpr *E) { -    mapToken(E->getLParenLoc()); -    mapToken(E->getRParenLoc()); -    Visit(E->getSubExpr()); -  } - -  // Map literals as tokens so that the macros like #define PI 3.14 -  // won't generate coverage mapping regions. -  void VisitIntegerLiteral(const IntegerLiteral *E) { -    mapToken(E->getLocStart()); +    extendRegion(E->getRHS()); +    propagateCounts(getRegionCounter(E), E->getRHS());    } -  void VisitFloatingLiteral(const FloatingLiteral *E) { -    mapToken(E->getLocStart()); -  } - -  void VisitCharacterLiteral(const CharacterLiteral *E) { -    mapToken(E->getLocStart()); -  } - -  void VisitStringLiteral(const StringLiteral *E) { -    mapToken(E->getLocStart()); -  } - -  void VisitImaginaryLiteral(const ImaginaryLiteral *E) { -    mapToken(E->getLocStart()); -  } - -  void VisitObjCMessageExpr(const ObjCMessageExpr *E) { -    mapToken(E->getLeftLoc()); -    for (Stmt::const_child_range I = static_cast<const Stmt*>(E)->children(); I; -         ++I) { -      if (*I) -        this->Visit(*I); -    } -    mapToken(E->getRightLoc()); +  void VisitLambdaExpr(const LambdaExpr *LE) { +    // Lambdas are treated as their own functions for now, so we shouldn't +    // propagate counts into them.    }  };  } @@ -1009,10 +894,12 @@ static StringRef getCoverageSection(const CodeGenModule &CGM) {    return isMachO(CGM) ? "__DATA,__llvm_covmap" : "__llvm_covmap";  } -static void dump(llvm::raw_ostream &OS, const CoverageMappingRecord &Function) { -  OS << Function.FunctionName << ":\n"; -  CounterMappingContext Ctx(Function.Expressions); -  for (const auto &R : Function.MappingRegions) { +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: @@ -1025,15 +912,12 @@ static void dump(llvm::raw_ostream &OS, const CoverageMappingRecord &Function) {        break;      } -    OS << "File " << R.FileID << ", " << R.LineStart << ":" -           << R.ColumnStart << " -> " << R.LineEnd << ":" << R.ColumnEnd -           << " = "; -    Ctx.dump(R.Count); -    OS << " (HasCodeBefore = " << R.HasCodeBefore; +    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"; +      OS << " (Expanded file = " << R.ExpandedFileID << ")"; +    OS << "\n";    }  } @@ -1072,13 +956,11 @@ void CoverageMappingModuleGen::addFunctionMappingRecord(      FilenameRefs.resize(FileEntries.size());      for (const auto &Entry : FileEntries)        FilenameRefs[Entry.second] = Entry.first->getName(); -    RawCoverageMappingReader Reader(FunctionNameValue, CoverageMapping, -                                    FilenameRefs, -                                    Filenames, Expressions, Regions); -    CoverageMappingRecord FunctionRecord; -    if (Reader.read(FunctionRecord)) +    RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames, +                                    Expressions, Regions); +    if (Reader.read())        return; -    dump(llvm::outs(), FunctionRecord); +    dump(llvm::outs(), FunctionNameValue, Expressions, Regions);    }  } @@ -1098,7 +980,7 @@ void CoverageMappingModuleGen::emit() {      llvm::sys::fs::make_absolute(Path);      auto I = Entry.second; -    FilenameStrs[I] = std::move(std::string(Path.begin(), Path.end())); +    FilenameStrs[I] = std::string(Path.begin(), Path.end());      FilenameRefs[I] = FilenameStrs[I];    }  | 
