diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp index f3587c768ded..fcc1c6b7d0b3 100644 --- a/llvm/tools/llvm-cov/CodeCoverage.cpp +++ b/llvm/tools/llvm-cov/CodeCoverage.cpp @@ -282,8 +282,8 @@ void CodeCoverageTool::createExpansionSubView( getSourceFile(Function.Filenames[ExpandedRegion.ExpandedFileID]); if (!SourceBuffer) return; - auto SubView = llvm::make_unique( - SourceBuffer.get(), Parent.getOptions(), ExpandedRegion); + auto SubView = llvm::make_unique(SourceBuffer.get(), + Parent.getOptions()); SourceCoverageDataManager RegionManager; for (const auto &CR : Function.CountedRegions) { if (CR.FileID == ExpandedRegion.ExpandedFileID) @@ -291,7 +291,7 @@ void CodeCoverageTool::createExpansionSubView( } SubView->load(RegionManager); createExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID, Function); - Parent.addChild(std::move(SubView)); + Parent.addExpansion(ExpandedRegion, std::move(SubView)); } void CodeCoverageTool::createExpansionSubViews( @@ -362,10 +362,18 @@ bool CodeCoverageTool::createSourceFileView( if (InstantiationSet.second.size() < 2) continue; for (auto Function : InstantiationSet.second) { - auto SubView = - llvm::make_unique(View, Function->Name); + unsigned FileID = Function->CountedRegions.front().FileID; + unsigned Line = 0; + for (const auto &CR : Function->CountedRegions) + if (CR.FileID == FileID) + Line = std::max(CR.LineEnd, Line); + auto SourceBuffer = getSourceFile(Function->Filenames[FileID]); + if (!SourceBuffer) + continue; + auto SubView = llvm::make_unique(SourceBuffer.get(), + View.getOptions()); createInstantiationSubView(SourceFile, *Function, *SubView); - View.addChild(std::move(SubView)); + View.addInstantiation(Function->Name, Line, std::move(SubView)); } } return false; diff --git a/llvm/tools/llvm-cov/SourceCoverageView.cpp b/llvm/tools/llvm-cov/SourceCoverageView.cpp index 8c1e6fdc33e4..f18f0f680d1d 100644 --- a/llvm/tools/llvm-cov/SourceCoverageView.cpp +++ b/llvm/tools/llvm-cov/SourceCoverageView.cpp @@ -140,10 +140,12 @@ void SourceCoverageView::renderRegionMarkers(raw_ostream &OS, /// \brief Insert a new highlighting range into the line's highlighting ranges /// Return line's new highlighting ranges in result. -static void insertHighlightRange( +static void insertExpansionHighlightRange( ArrayRef Ranges, - SourceCoverageView::HighlightRange RangeToInsert, + unsigned Line, unsigned StartCol, unsigned EndCol, SmallVectorImpl &Result) { + auto RangeToInsert = SourceCoverageView::HighlightRange( + Line, StartCol, EndCol, SourceCoverageView::HighlightRange::Expanded); Result.clear(); size_t I = 0; auto E = Ranges.size(); @@ -189,22 +191,6 @@ static void insertHighlightRange( Result.push_back(Ranges[I]); } -void SourceCoverageView::sortChildren() { - for (auto &I : Children) - I->sortChildren(); - std::sort(Children.begin(), Children.end(), - [](const std::unique_ptr &LHS, - const std::unique_ptr &RHS) { - return LHS->ExpansionRegion < RHS->ExpansionRegion; - }); -} - -SourceCoverageView::HighlightRange -SourceCoverageView::getExpansionHighlightRange() const { - return HighlightRange(ExpansionRegion.LineStart, ExpansionRegion.ColumnStart, - ExpansionRegion.ColumnEnd, HighlightRange::Expanded); -} - template ArrayRef gatherLineItems(size_t &CurrentIdx, const std::vector &Items, unsigned LineNo) { @@ -215,24 +201,8 @@ ArrayRef gatherLineItems(size_t &CurrentIdx, const std::vector &Items, return ArrayRef(Items.data() + PrevIdx, CurrentIdx - PrevIdx); } -ArrayRef> -gatherLineSubViews(size_t &CurrentIdx, - ArrayRef> Items, - unsigned LineNo) { - auto PrevIdx = CurrentIdx; - auto E = Items.size(); - while (CurrentIdx < E && - Items[CurrentIdx]->getSubViewsExpansionLine() == LineNo) - ++CurrentIdx; - return Items.slice(PrevIdx, CurrentIdx - PrevIdx); -} - void SourceCoverageView::render(raw_ostream &OS, unsigned IndentLevel) { - // Make sure that the children are in sorted order. - sortChildren(); - SmallVector AdjustedLineHighlightRanges; - size_t CurrentChild = 0; size_t CurrentHighlightRange = 0; size_t CurrentRegionMarker = 0; @@ -249,12 +219,18 @@ void SourceCoverageView::render(raw_ostream &OS, unsigned IndentLevel) { // subviews. unsigned DividerWidth = CombinedColumnWidth + 4; + // We need the expansions and instantiations sorted so we can go through them + // while we iterate lines. + std::sort(ExpansionSubViews.begin(), ExpansionSubViews.end()); + std::sort(InstantiationSubViews.begin(), InstantiationSubViews.end()); + auto NextESV = ExpansionSubViews.begin(); + auto EndESV = ExpansionSubViews.end(); + auto NextISV = InstantiationSubViews.begin(); + auto EndISV = InstantiationSubViews.end(); + for (size_t I = 0, E = LineStats.size(); I < E; ++I) { unsigned LineNo = I + LineOffset; - // Gather the child subviews that are visible on this line. - auto LineSubViews = gatherLineSubViews(CurrentChild, Children, LineNo); - renderIndent(OS, IndentLevel); if (Options.ShowLineStats) renderLineCoverageColumn(OS, LineStats[I]); @@ -267,11 +243,10 @@ void SourceCoverageView::render(raw_ostream &OS, unsigned IndentLevel) { auto LineRanges = LineHighlightRanges; // Highlight the expansion range if there is an expansion subview on this // line. - if (!LineSubViews.empty() && LineSubViews.front()->isExpansionSubView() && - Options.Colors) { - insertHighlightRange(LineHighlightRanges, - LineSubViews.front()->getExpansionHighlightRange(), - AdjustedLineHighlightRanges); + if (NextESV != EndESV && NextESV->getLine() == LineNo && Options.Colors) { + insertExpansionHighlightRange( + LineHighlightRanges, NextESV->getLine(), NextESV->getStartCol(), + NextESV->getEndCol(), AdjustedLineHighlightRanges); LineRanges = AdjustedLineHighlightRanges; } @@ -294,40 +269,40 @@ void SourceCoverageView::render(raw_ostream &OS, unsigned IndentLevel) { renderRegionMarkers(OS, LineMarkers); } - // Show the line's expanded child subviews. - bool FirstChildExpansion = true; - if (LineSubViews.empty()) - continue; + // Show the expansions and instantiations for this line. unsigned NestedIndent = IndentLevel + 1; - renderViewDivider(NestedIndent, DividerWidth, OS); - OS << "\n"; - for (const auto &Child : LineSubViews) { - // If this subview shows a function instantiation, render the function's - // name. - if (Child->isInstantiationSubView()) { - renderIndent(OS, NestedIndent); - OS << ' '; - Options.colored_ostream(OS, raw_ostream::CYAN) << Child->FunctionName - << ":"; + bool RenderedSubView = false; + for (; NextESV != EndESV && NextESV->getLine() == LineNo; ++NextESV) { + renderViewDivider(NestedIndent, DividerWidth, OS); + OS << "\n"; + if (RenderedSubView) { + // Re-render the current line and highlight the expansion range for + // this subview. + insertExpansionHighlightRange( + LineHighlightRanges, NextESV->getLine(), NextESV->getStartCol(), + NextESV->getEndCol(), AdjustedLineHighlightRanges); + renderIndent(OS, IndentLevel); + OS.indent(CombinedColumnWidth + (IndentLevel == 0 ? 0 : 1)); + renderLine(OS, Line, AdjustedLineHighlightRanges); + renderViewDivider(NestedIndent, DividerWidth, OS); OS << "\n"; - } else { - if (!FirstChildExpansion) { - // Re-render the current line and highlight the expansion range for - // this - // subview. - insertHighlightRange(LineHighlightRanges, - Child->getExpansionHighlightRange(), - AdjustedLineHighlightRanges); - renderIndent(OS, IndentLevel); - OS.indent(CombinedColumnWidth + (IndentLevel == 0 ? 0 : 1)); - renderLine(OS, Line, AdjustedLineHighlightRanges); - renderViewDivider(NestedIndent, DividerWidth, OS); - OS << "\n"; - } else - FirstChildExpansion = false; } // Render the child subview - Child->render(OS, NestedIndent); + NextESV->View->render(OS, NestedIndent); + RenderedSubView = true; + } + for (; NextISV != EndISV && NextISV->Line == LineNo; ++NextISV) { + renderViewDivider(NestedIndent, DividerWidth, OS); + OS << "\n"; + renderIndent(OS, NestedIndent); + OS << ' '; + Options.colored_ostream(OS, raw_ostream::CYAN) << NextISV->FunctionName + << ":"; + OS << "\n"; + NextISV->View->render(OS, NestedIndent); + RenderedSubView = true; + } + if (RenderedSubView) { renderViewDivider(NestedIndent, DividerWidth, OS); OS << "\n"; } diff --git a/llvm/tools/llvm-cov/SourceCoverageView.h b/llvm/tools/llvm-cov/SourceCoverageView.h index 0777c23a855a..af44085cffcd 100644 --- a/llvm/tools/llvm-cov/SourceCoverageView.h +++ b/llvm/tools/llvm-cov/SourceCoverageView.h @@ -22,12 +22,46 @@ namespace llvm { +class SourceCoverageView; + +/// \brief A view that represents a macro or include expansion +struct ExpansionView { + coverage::CounterMappingRegion Region; + std::unique_ptr View; + + ExpansionView(const coverage::CounterMappingRegion &Region, + std::unique_ptr View) + : Region(Region), View(std::move(View)) {} + + unsigned getLine() const { return Region.LineStart; } + unsigned getStartCol() const { return Region.ColumnStart; } + unsigned getEndCol() const { return Region.ColumnEnd; } + + friend bool operator<(const ExpansionView &LHS, const ExpansionView &RHS) { + return LHS.Region.startLoc() < RHS.Region.startLoc(); + } +}; + +/// \brief A view that represents a function instantiation +struct InstantiationView { + StringRef FunctionName; + unsigned Line; + std::unique_ptr View; + + InstantiationView(StringRef FunctionName, unsigned Line, + std::unique_ptr View) + : FunctionName(FunctionName), Line(Line), View(std::move(View)) {} + + friend bool operator<(const InstantiationView &LHS, + const InstantiationView &RHS) { + return LHS.Line < RHS.Line; + } +}; + /// \brief A code coverage view of a specific source file. /// It can have embedded coverage views. class SourceCoverageView { public: - enum SubViewKind { View, ExpansionView, InstantiationView }; - /// \brief Coverage information for a single line. struct LineCoverageInfo { uint64_t ExecutionCount; @@ -111,13 +145,11 @@ private: const MemoryBuffer &File; const CoverageViewOptions &Options; unsigned LineOffset; - SubViewKind Kind; - coverage::CounterMappingRegion ExpansionRegion; - std::vector> Children; + std::vector ExpansionSubViews; + std::vector InstantiationSubViews; std::vector LineStats; std::vector HighlightRanges; std::vector Markers; - StringRef FunctionName; /// \brief Initialize the visible source range for this view. void setUpVisibleRange(SourceCoverageDataManager &Data); @@ -131,12 +163,6 @@ private: /// \brief Create the region markers using the coverage data. void createRegionMarkers(SourceCoverageDataManager &Data); - /// \brief Sort children by the starting location. - void sortChildren(); - - /// \brief Return a highlight range for the expansion region of this view. - HighlightRange getExpansionHighlightRange() const; - /// \brief Render a source line with highlighting. void renderLine(raw_ostream &OS, StringRef Line, ArrayRef Ranges); @@ -160,34 +186,20 @@ private: public: SourceCoverageView(const MemoryBuffer &File, const CoverageViewOptions &Options) - : File(File), Options(Options), LineOffset(0), Kind(View), - ExpansionRegion(coverage::Counter(), 0, 0, 0, 0, 0) {} - - SourceCoverageView(SourceCoverageView &Parent, StringRef FunctionName) - : File(Parent.File), Options(Parent.Options), LineOffset(0), - Kind(InstantiationView), - ExpansionRegion(coverage::Counter(), 0, 0, 0, 0, 0), - FunctionName(FunctionName) {} - - SourceCoverageView(const MemoryBuffer &File, - const CoverageViewOptions &Options, - const coverage::CounterMappingRegion &ExpansionRegion) - : File(File), Options(Options), LineOffset(0), Kind(ExpansionView), - ExpansionRegion(ExpansionRegion) {} + : File(File), Options(Options), LineOffset(0) {} const CoverageViewOptions &getOptions() const { return Options; } - bool isExpansionSubView() const { return Kind == ExpansionView; } - - bool isInstantiationSubView() const { return Kind == InstantiationView; } - - /// \brief Return the line number after which the subview expansion is shown. - unsigned getSubViewsExpansionLine() const { - return ExpansionRegion.LineStart; + /// \brief Add an expansion subview to this view. + void addExpansion(const coverage::CounterMappingRegion &Region, + std::unique_ptr View) { + ExpansionSubViews.emplace_back(Region, std::move(View)); } - void addChild(std::unique_ptr View) { - Children.push_back(std::move(View)); + /// \brief Add a function instantiation subview to this view. + void addInstantiation(StringRef FunctionName, unsigned Line, + std::unique_ptr View) { + InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View)); } /// \brief Print the code coverage information for a specific