diff options
Diffstat (limited to 'lib/CodeGen/CoverageMappingGen.cpp')
-rw-r--r-- | lib/CodeGen/CoverageMappingGen.cpp | 107 |
1 files changed, 76 insertions, 31 deletions
diff --git a/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp index 2d84464635942..35962c73d9a82 100644 --- a/lib/CodeGen/CoverageMappingGen.cpp +++ b/lib/CodeGen/CoverageMappingGen.cpp @@ -67,7 +67,7 @@ public: void setStartLoc(SourceLocation Loc) { LocStart = Loc; } - SourceLocation getStartLoc() const { + SourceLocation getBeginLoc() const { assert(LocStart && "Region has no start location"); return *LocStart; } @@ -116,7 +116,7 @@ struct SpellingRegion { } SpellingRegion(SourceManager &SM, SourceMappingRegion &R) - : SpellingRegion(SM, R.getStartLoc(), R.getEndLoc()) {} + : SpellingRegion(SM, R.getBeginLoc(), R.getEndLoc()) {} /// Check if the start and end locations appear in source order, i.e /// top->bottom, left->right. @@ -204,7 +204,7 @@ public: /// Get the start of \c S ignoring macro arguments and builtin macros. SourceLocation getStart(const Stmt *S) { - SourceLocation Loc = S->getLocStart(); + SourceLocation Loc = S->getBeginLoc(); while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc)) Loc = SM.getImmediateExpansionRange(Loc).getBegin(); return Loc; @@ -212,7 +212,7 @@ public: /// Get the end of \c S ignoring macro arguments and builtin macros. SourceLocation getEnd(const Stmt *S) { - SourceLocation Loc = S->getLocEnd(); + SourceLocation Loc = S->getEndLoc(); while (SM.isMacroArgExpansion(Loc) || isInBuiltin(Loc)) Loc = SM.getImmediateExpansionRange(Loc).getBegin(); return getPreciseTokenLocEnd(Loc); @@ -229,7 +229,7 @@ public: llvm::SmallSet<FileID, 8> Visited; SmallVector<std::pair<SourceLocation, unsigned>, 8> FileLocs; for (const auto &Region : SourceRegions) { - SourceLocation Loc = Region.getStartLoc(); + SourceLocation Loc = Region.getBeginLoc(); FileID File = SM.getFileID(Loc); if (!Visited.insert(File).second) continue; @@ -311,7 +311,7 @@ public: for (const auto &Region : SourceRegions) { assert(Region.hasEndLoc() && "incomplete region"); - SourceLocation LocStart = Region.getStartLoc(); + SourceLocation LocStart = Region.getBeginLoc(); assert(SM.getFileID(LocStart).isValid() && "region in invalid file"); // Ignore regions from system headers. @@ -502,7 +502,7 @@ struct CounterCoverageMappingBuilder DeferredRegion = None; // If the region ends in an expansion, find the expansion site. - FileID StartFile = SM.getFileID(DR.getStartLoc()); + FileID StartFile = SM.getFileID(DR.getBeginLoc()); if (SM.getFileID(DeferredEndLoc) != StartFile) { if (isNestedIn(DeferredEndLoc, StartFile)) { do { @@ -515,12 +515,12 @@ struct CounterCoverageMappingBuilder // The parent of this deferred region ends where the containing decl ends, // so the region isn't useful. - if (DR.getStartLoc() == DeferredEndLoc) + 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.getStartLoc(), DeferredEndLoc).isInSourceOrder()) + if (!SpellingRegion(SM, DR.getBeginLoc(), DeferredEndLoc).isInSourceOrder()) return Index; DR.setGap(true); @@ -552,6 +552,15 @@ struct CounterCoverageMappingBuilder 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 @@ -562,23 +571,45 @@ struct CounterCoverageMappingBuilder while (RegionStack.size() > ParentIndex) { SourceMappingRegion &Region = RegionStack.back(); if (Region.hasStartLoc()) { - SourceLocation StartLoc = Region.getStartLoc(); + 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)) { - // 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"); + 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; @@ -588,7 +619,7 @@ struct CounterCoverageMappingBuilder EndLoc == getEndOfFileOrMacro(EndLoc)) MostRecentLocation = getIncludeOrExpansionLoc(EndLoc); - assert(SM.isWrittenInSameFile(Region.getStartLoc(), EndLoc)); + assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc)); assert(SpellingRegion(SM, Region).isInSourceOrder()); SourceRegions.push_back(Region); @@ -625,18 +656,21 @@ struct CounterCoverageMappingBuilder return RegionStack.back(); } - /// Propagate counts through the children of \c S. - Counter propagateCounts(Counter TopCount, const Stmt *S) { + /// 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); - Visit(S); + 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->getLocStart())) + if (SM.isBeforeInTranslationUnit(StartLoc, S->getBeginLoc())) MostRecentLocation = EndLoc; return ExitCount; @@ -648,7 +682,7 @@ struct CounterCoverageMappingBuilder return SourceRegions.rend() != std::find_if(SourceRegions.rbegin(), SourceRegions.rend(), [&](const SourceMappingRegion &Region) { - return Region.getStartLoc() == StartLoc && + return Region.getBeginLoc() == StartLoc && Region.getEndLoc() == EndLoc; }); } @@ -700,7 +734,7 @@ struct CounterCoverageMappingBuilder for (SourceMappingRegion &I : llvm::reverse(RegionStack)) { if (!I.hasStartLoc()) continue; - SourceLocation Loc = I.getStartLoc(); + SourceLocation Loc = I.getBeginLoc(); if (!isNestedIn(Loc, ParentFile)) { ParentCounter = I.getCounter(); break; @@ -826,7 +860,7 @@ struct CounterCoverageMappingBuilder } void VisitStmt(const Stmt *S) { - if (S->getLocStart().isValid()) + if (S->getBeginLoc().isValid()) extendRegion(S); for (const Stmt *Child : S->children()) if (Child) @@ -843,7 +877,16 @@ struct CounterCoverageMappingBuilder if (Body && SM.isInSystemHeader(SM.getSpellingLoc(getStart(Body)))) return; - propagateCounts(getRegionCounter(Body), Body); + // 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. @@ -1004,6 +1047,8 @@ struct CounterCoverageMappingBuilder void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { extendRegion(S); + if (S->getInit()) + Visit(S->getInit()); Visit(S->getLoopVarStmt()); Visit(S->getRangeStmt()); @@ -1109,7 +1154,7 @@ struct CounterCoverageMappingBuilder 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)) + if (Parent.hasStartLoc() && Parent.getBeginLoc() == getStart(S)) Parent.setCounter(Count); else pushRegion(Count, getStart(S)); |