[llvm-cov] Separate presentation logic from formatting logic, NFC

This makes it easier to add renderers for new kinds of output formats.

- Define and document a pure-virtual coverage rendering interface.
- Move the text-based rendering logic into its a new file.
- Re-work the API to better reflect the presentation/formatting split.

llvm-svn: 273767
This commit is contained in:
Vedant Kumar 2016-06-25 02:58:30 +00:00
parent cc676c47a3
commit f9151b9372
6 changed files with 364 additions and 202 deletions

View File

@ -8,5 +8,6 @@ add_llvm_tool(llvm-cov
CoverageReport.cpp
CoverageSummaryInfo.cpp
SourceCoverageView.cpp
SourceCoverageViewText.cpp
TestingSupport.cpp
)

View File

@ -132,9 +132,9 @@ CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View,
continue;
auto SubViewExpansions = ExpansionCoverage.getExpansions();
auto SubView = llvm::make_unique<SourceCoverageView>(
Expansion.Function.Name, SourceBuffer.get(), ViewOpts,
std::move(ExpansionCoverage));
auto SubView =
SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(),
ViewOpts, std::move(ExpansionCoverage));
attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
View.addExpansion(Expansion.Region, std::move(SubView));
}
@ -151,8 +151,8 @@ CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
return nullptr;
auto Expansions = FunctionCoverage.getExpansions();
auto View = llvm::make_unique<SourceCoverageView>(
Function.Name, SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage));
auto View = SourceCoverageView::create(Function.Name, SourceBuffer.get(),
ViewOpts, std::move(FunctionCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
return View;
@ -169,16 +169,16 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
return nullptr;
auto Expansions = FileCoverage.getExpansions();
auto View = llvm::make_unique<SourceCoverageView>(
SourceFile, SourceBuffer.get(), ViewOpts, std::move(FileCoverage));
auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
ViewOpts, std::move(FileCoverage));
attachExpansionSubViews(*View, Expansions, Coverage);
for (auto Function : Coverage.getInstantiations(SourceFile)) {
auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
auto SubViewExpansions = SubViewCoverage.getExpansions();
auto SubView = llvm::make_unique<SourceCoverageView>(
Function->Name, SourceBuffer.get(), ViewOpts,
std::move(SubViewCoverage));
auto SubView =
SourceCoverageView::create(Function->Name, SourceBuffer.get(), ViewOpts,
std::move(SubViewCoverage));
attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
if (SubView) {
@ -428,8 +428,7 @@ int CodeCoverageTool::show(int argc, const char **argv,
<< "\n";
continue;
}
mainView->renderSourceName(outs());
mainView->render(outs(), /*WholeFile=*/false);
mainView->print(outs(), /*WholeFile=*/false, /*ShowSourceName=*/true);
outs() << "\n";
}
return 0;
@ -452,10 +451,7 @@ int CodeCoverageTool::show(int argc, const char **argv,
continue;
}
if (ShowFilenames)
mainView->renderSourceName(outs());
mainView->render(outs(), /*Wholefile=*/true);
mainView->print(outs(), /*Wholefile=*/true, /*ShowSourceName=*/ShowFilenames);
if (SourceFiles.size() > 1)
outs() << "\n";
}

View File

@ -12,75 +12,14 @@
//===----------------------------------------------------------------------===//
#include "SourceCoverageView.h"
#include "llvm/ADT/Optional.h"
#include "SourceCoverageViewText.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/LineIterator.h"
using namespace llvm;
void SourceCoverageView::renderLine(
raw_ostream &OS, StringRef Line, int64_t LineNumber,
const coverage::CoverageSegment *WrappedSegment,
ArrayRef<const coverage::CoverageSegment *> Segments,
unsigned ExpansionCol) {
Optional<raw_ostream::Colors> Highlight;
SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges;
// The first segment overlaps from a previous line, so we treat it specially.
if (WrappedSegment && WrappedSegment->HasCount && WrappedSegment->Count == 0)
Highlight = raw_ostream::RED;
// Output each segment of the line, possibly highlighted.
unsigned Col = 1;
for (const auto *S : Segments) {
unsigned End = std::min(S->Col, static_cast<unsigned>(Line.size()) + 1);
colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
getOptions().Colors && Highlight, /*Bold=*/false,
/*BG=*/true)
<< Line.substr(Col - 1, End - Col);
if (getOptions().Debug && Highlight)
HighlightedRanges.push_back(std::make_pair(Col, End));
Col = End;
if (Col == ExpansionCol)
Highlight = raw_ostream::CYAN;
else if (S->HasCount && S->Count == 0)
Highlight = raw_ostream::RED;
else
Highlight = None;
}
// Show the rest of the line
colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
getOptions().Colors && Highlight, /*Bold=*/false, /*BG=*/true)
<< Line.substr(Col - 1, Line.size() - Col + 1);
OS << "\n";
if (getOptions().Debug) {
for (const auto &Range : HighlightedRanges)
errs() << "Highlighted line " << LineNumber << ", " << Range.first
<< " -> " << Range.second << "\n";
if (Highlight)
errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n";
}
}
void SourceCoverageView::renderIndent(raw_ostream &OS, unsigned Level) {
for (unsigned I = 0; I < Level; ++I)
OS << " |";
}
void SourceCoverageView::renderViewDivider(unsigned Level, unsigned Length,
raw_ostream &OS) {
assert(Level != 0 && "Cannot render divider at top level");
renderIndent(OS, Level - 1);
OS.indent(2);
for (unsigned I = 0; I < Length; ++I)
OS << "-";
}
/// Format a count using engineering notation with 3 significant digits.
static std::string formatCount(uint64_t N) {
std::string SourceCoverageView::formatCount(uint64_t N) {
std::string Number = utostr(N);
int Len = Number.size();
if (Len <= 3)
@ -95,63 +34,30 @@ static std::string formatCount(uint64_t N) {
return Result;
}
void
SourceCoverageView::renderLineCoverageColumn(raw_ostream &OS,
const LineCoverageStats &Line) {
if (!Line.isMapped()) {
OS.indent(LineCoverageColumnWidth) << '|';
return;
}
std::string C = formatCount(Line.ExecutionCount);
OS.indent(LineCoverageColumnWidth - C.size());
colored_ostream(OS, raw_ostream::MAGENTA,
Line.hasMultipleRegions() && getOptions().Colors)
<< C;
OS << '|';
void SourceCoverageView::addExpansion(
const coverage::CounterMappingRegion &Region,
std::unique_ptr<SourceCoverageView> View) {
ExpansionSubViews.emplace_back(Region, std::move(View));
}
void SourceCoverageView::renderLineNumberColumn(raw_ostream &OS,
unsigned LineNo) {
SmallString<32> Buffer;
raw_svector_ostream BufferOS(Buffer);
BufferOS << LineNo;
auto Str = BufferOS.str();
// Trim and align to the right
Str = Str.substr(0, std::min(Str.size(), (size_t)LineNumberColumnWidth));
OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|';
void SourceCoverageView::addInstantiation(
StringRef FunctionName, unsigned Line,
std::unique_ptr<SourceCoverageView> View) {
InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
}
void SourceCoverageView::renderRegionMarkers(
raw_ostream &OS, ArrayRef<const coverage::CoverageSegment *> Segments) {
unsigned PrevColumn = 1;
for (const auto *S : Segments) {
if (!S->IsRegionEntry)
continue;
// Skip to the new region
if (S->Col > PrevColumn)
OS.indent(S->Col - PrevColumn);
PrevColumn = S->Col + 1;
std::string C = formatCount(S->Count);
PrevColumn += C.size();
OS << '^' << C;
}
OS << "\n";
if (getOptions().Debug)
for (const auto *S : Segments)
errs() << "Marker at " << S->Line << ":" << S->Col << " = "
<< formatCount(S->Count) << (S->IsRegionEntry ? "\n" : " (pop)\n");
std::unique_ptr<SourceCoverageView>
SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File,
const CoverageViewOptions &Options,
coverage::CoverageData &&CoverageInfo) {
return llvm::make_unique<SourceCoverageViewText>(SourceName, File, Options,
std::move(CoverageInfo));
}
void SourceCoverageView::render(raw_ostream &OS, bool WholeFile,
unsigned IndentLevel) {
// The width of the leading columns
unsigned CombinedColumnWidth =
(getOptions().ShowLineStats ? LineCoverageColumnWidth + 1 : 0) +
(getOptions().ShowLineNumbers ? LineNumberColumnWidth + 1 : 0);
// The width of the line that is used to divide between the view and the
// subviews.
unsigned DividerWidth = CombinedColumnWidth + 4;
void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
bool ShowSourceName, unsigned ViewDepth) {
if (ShowSourceName)
renderSourceName(OS);
// We need the expansions and instantiations sorted so we can go through them
// while we iterate lines.
@ -192,10 +98,9 @@ void SourceCoverageView::render(raw_ostream &OS, bool WholeFile,
LineCount.addRegionCount(WrappedSegment->Count);
for (const auto *S : LineSegments)
if (S->HasCount && S->IsRegionEntry)
LineCount.addRegionStartCount(S->Count);
LineCount.addRegionStartCount(S->Count);
// Render the line prefix.
renderIndent(OS, IndentLevel);
renderLinePrefix(OS, ViewDepth);
if (getOptions().ShowLineStats)
renderLineCoverageColumn(OS, LineCount);
if (getOptions().ShowLineNumbers)
@ -208,62 +113,34 @@ void SourceCoverageView::render(raw_ostream &OS, bool WholeFile,
ExpansionColumn = NextESV->getStartCol();
// Display the source code for the current line.
renderLine(OS, *LI, LI.line_number(), WrappedSegment, LineSegments,
ExpansionColumn);
renderLine(OS, {*LI, LI.line_number()}, WrappedSegment, LineSegments,
ExpansionColumn, ViewDepth);
// Show the region markers.
if (getOptions().ShowRegionMarkers &&
(!getOptions().ShowLineStatsOrRegionMarkers ||
LineCount.hasMultipleRegions()) &&
!LineSegments.empty()) {
renderIndent(OS, IndentLevel);
OS.indent(CombinedColumnWidth);
renderRegionMarkers(OS, LineSegments);
renderRegionMarkers(OS, LineSegments, ViewDepth);
}
// Show the expansions and instantiations for this line.
unsigned NestedIndent = IndentLevel + 1;
bool RenderedSubView = false;
for (; NextESV != EndESV && NextESV->getLine() == LI.line_number();
++NextESV) {
renderViewDivider(NestedIndent, DividerWidth, OS);
OS << "\n";
if (RenderedSubView) {
// Re-render the current line and highlight the expansion range for
// this subview.
ExpansionColumn = NextESV->getStartCol();
renderIndent(OS, IndentLevel);
OS.indent(CombinedColumnWidth + (IndentLevel == 0 ? 0 : 1));
renderLine(OS, *LI, LI.line_number(), WrappedSegment, LineSegments,
ExpansionColumn);
renderViewDivider(NestedIndent, DividerWidth, OS);
OS << "\n";
}
// Render the child subview
if (getOptions().Debug)
errs() << "Expansion at line " << NextESV->getLine() << ", "
<< NextESV->getStartCol() << " -> " << NextESV->getEndCol()
<< "\n";
NextESV->View->render(OS, false, NestedIndent);
renderViewDivider(OS, ViewDepth + 1);
ExpansionColumn = renderExpansionView(
OS, *NextESV,
RenderedSubView ? Optional<LineRef>({*LI, LI.line_number()})
: Optional<LineRef>(),
ExpansionColumn, WrappedSegment, LineSegments, ViewDepth);
RenderedSubView = true;
}
for (; NextISV != EndISV && NextISV->Line == LI.line_number(); ++NextISV) {
renderViewDivider(NestedIndent, DividerWidth, OS);
OS << "\n";
renderIndent(OS, NestedIndent);
OS << ' ';
NextISV->View->renderSourceName(OS);
NextISV->View->render(OS, false, NestedIndent);
renderInstantiationView(OS, *NextISV, ViewDepth + 1);
RenderedSubView = true;
}
if (RenderedSubView) {
renderViewDivider(NestedIndent, DividerWidth, OS);
OS << "\n";
}
if (RenderedSubView)
renderViewDivider(OS, ViewDepth + 1);
}
}
void SourceCoverageView::renderSourceName(raw_ostream &OS) {
getOptions().colored_ostream(OS, raw_ostream::CYAN) << getSourceName()
<< ":\n";
}

View File

@ -16,6 +16,7 @@
#include "CoverageViewOptions.h"
#include "llvm/ProfileData/Coverage/CoverageMapping.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/MemoryBuffer.h"
#include <vector>
@ -100,7 +101,6 @@ struct LineCoverageStats {
/// \brief A code coverage view of a specific source file.
/// It can have embedded coverage views.
class SourceCoverageView {
private:
/// A function or file name.
StringRef SourceName;
@ -120,59 +120,93 @@ private:
/// on display.
std::vector<InstantiationView> InstantiationSubViews;
protected:
struct LineRef {
StringRef Line;
int64_t LineNo;
LineRef(StringRef Line, int64_t LineNo) : Line(Line), LineNo(LineNo) {}
};
using CoverageSegmentArray = ArrayRef<const coverage::CoverageSegment *>;
/// @name Rendering Interface
/// @{
/// \brief Render the source name for the view.
virtual void renderSourceName(raw_ostream &OS) = 0;
/// \brief Render the line prefix at the given \p ViewDepth.
virtual void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) = 0;
/// \brief Render a view divider at the given \p ViewDepth.
virtual void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) = 0;
/// \brief Render a source line with highlighting.
void renderLine(raw_ostream &OS, StringRef Line, int64_t LineNumber,
const coverage::CoverageSegment *WrappedSegment,
ArrayRef<const coverage::CoverageSegment *> Segments,
unsigned ExpansionCol);
void renderIndent(raw_ostream &OS, unsigned Level);
void renderViewDivider(unsigned Offset, unsigned Length, raw_ostream &OS);
virtual void renderLine(raw_ostream &OS, LineRef L,
const coverage::CoverageSegment *WrappedSegment,
CoverageSegmentArray Segments, unsigned ExpansionCol,
unsigned ViewDepth) = 0;
/// \brief Render the line's execution count column.
void renderLineCoverageColumn(raw_ostream &OS, const LineCoverageStats &Line);
virtual void renderLineCoverageColumn(raw_ostream &OS,
const LineCoverageStats &Line) = 0;
/// \brief Render the line number column.
void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo);
virtual void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) = 0;
/// \brief Render all the region's execution counts on a line.
void
renderRegionMarkers(raw_ostream &OS,
ArrayRef<const coverage::CoverageSegment *> Segments);
virtual void renderRegionMarkers(raw_ostream &OS,
CoverageSegmentArray Segments,
unsigned ViewDepth) = 0;
static const unsigned LineCoverageColumnWidth = 7;
static const unsigned LineNumberColumnWidth = 5;
/// \brief Render an expansion view. If \p FirstLine is provided, it points
/// to the expansion site, which must be re-rendered for clarity.
virtual unsigned renderExpansionView(
raw_ostream &OS, ExpansionView &ESV, Optional<LineRef> FirstLine,
unsigned ExpansionCol, const coverage::CoverageSegment *WrappedSegment,
CoverageSegmentArray LineSegments, unsigned ViewDepth) = 0;
/// \brief Render an instantiation view.
virtual void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
unsigned ViewDepth) = 0;
/// @}
/// \brief Format a count using engineering notation with 3 significant
/// digits.
static std::string formatCount(uint64_t N);
public:
SourceCoverageView(StringRef SourceName, const MemoryBuffer &File,
const CoverageViewOptions &Options,
coverage::CoverageData &&CoverageInfo)
: SourceName(SourceName), File(File), Options(Options),
CoverageInfo(std::move(CoverageInfo)) {}
public:
static std::unique_ptr<SourceCoverageView>
create(StringRef SourceName, const MemoryBuffer &File,
const CoverageViewOptions &Options,
coverage::CoverageData &&CoverageInfo);
virtual ~SourceCoverageView() {}
StringRef getSourceName() const { return SourceName; }
const CoverageViewOptions &getOptions() const { return Options; }
/// \brief Add an expansion subview to this view.
void addExpansion(const coverage::CounterMappingRegion &Region,
std::unique_ptr<SourceCoverageView> View) {
ExpansionSubViews.emplace_back(Region, std::move(View));
}
std::unique_ptr<SourceCoverageView> View);
/// \brief Add a function instantiation subview to this view.
void addInstantiation(StringRef FunctionName, unsigned Line,
std::unique_ptr<SourceCoverageView> View) {
InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
}
std::unique_ptr<SourceCoverageView> View);
/// \brief Print the code coverage information for a specific
/// portion of a source file to the output stream.
void render(raw_ostream &OS, bool WholeFile, unsigned IndentLevel = 0);
/// \brief Print the source name corresponding to this view.
void renderSourceName(raw_ostream &OS);
/// \brief Print the code coverage information for a specific portion of a
/// source file to the output stream.
void print(raw_ostream &OS, bool WholeFile, bool ShowSourceName,
unsigned ViewDepth = 0);
};
} // namespace llvm

View File

@ -0,0 +1,193 @@
//===- SourceCoverageViewText.cpp - A text-based code coverage view -------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the text-based coverage renderer.
//
//===----------------------------------------------------------------------===//
#include "SourceCoverageViewText.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
using namespace llvm;
namespace {
constexpr unsigned LineCoverageColumnWidth = 7;
constexpr unsigned LineNumberColumnWidth = 5;
/// \brief Get the width of the leading columns.
unsigned getCombinedColumnWidth(const CoverageViewOptions &Opts) {
return (Opts.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) +
(Opts.ShowLineNumbers ? LineNumberColumnWidth + 1 : 0);
}
/// \brief The width of the line that is used to divide between the view and
/// the subviews.
unsigned getDividerWidth(const CoverageViewOptions &Opts) {
return getCombinedColumnWidth(Opts) + 4;
}
} // anonymous namespace
void SourceCoverageViewText::renderSourceName(raw_ostream &OS) {
getOptions().colored_ostream(OS, raw_ostream::CYAN) << getSourceName()
<< ":\n";
}
void SourceCoverageViewText::renderLinePrefix(raw_ostream &OS,
unsigned ViewDepth) {
for (unsigned I = 0; I < ViewDepth; ++I)
OS << " |";
}
void SourceCoverageViewText::renderViewDivider(raw_ostream &OS,
unsigned ViewDepth) {
assert(ViewDepth != 0 && "Cannot render divider at top level");
renderLinePrefix(OS, ViewDepth - 1);
OS.indent(2);
unsigned Length = getDividerWidth(getOptions());
for (unsigned I = 0; I < Length; ++I)
OS << '-';
OS << '\n';
}
void SourceCoverageViewText::renderLine(
raw_ostream &OS, LineRef L,
const coverage::CoverageSegment *WrappedSegment,
CoverageSegmentArray Segments, unsigned ExpansionCol, unsigned ViewDepth) {
StringRef Line = L.Line;
unsigned LineNumber = L.LineNo;
Optional<raw_ostream::Colors> Highlight;
SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges;
// The first segment overlaps from a previous line, so we treat it specially.
if (WrappedSegment && WrappedSegment->HasCount && WrappedSegment->Count == 0)
Highlight = raw_ostream::RED;
// Output each segment of the line, possibly highlighted.
unsigned Col = 1;
for (const auto *S : Segments) {
unsigned End = std::min(S->Col, static_cast<unsigned>(Line.size()) + 1);
colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
getOptions().Colors && Highlight, /*Bold=*/false,
/*BG=*/true)
<< Line.substr(Col - 1, End - Col);
if (getOptions().Debug && Highlight)
HighlightedRanges.push_back(std::make_pair(Col, End));
Col = End;
if (Col == ExpansionCol)
Highlight = raw_ostream::CYAN;
else if (S->HasCount && S->Count == 0)
Highlight = raw_ostream::RED;
else
Highlight = None;
}
// Show the rest of the line.
colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
getOptions().Colors && Highlight, /*Bold=*/false, /*BG=*/true)
<< Line.substr(Col - 1, Line.size() - Col + 1);
OS << '\n';
if (getOptions().Debug) {
for (const auto &Range : HighlightedRanges)
errs() << "Highlighted line " << LineNumber << ", " << Range.first
<< " -> " << Range.second << '\n';
if (Highlight)
errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n";
}
}
void SourceCoverageViewText::renderLineCoverageColumn(
raw_ostream &OS, const LineCoverageStats &Line) {
if (!Line.isMapped()) {
OS.indent(LineCoverageColumnWidth) << '|';
return;
}
std::string C = formatCount(Line.ExecutionCount);
OS.indent(LineCoverageColumnWidth - C.size());
colored_ostream(OS, raw_ostream::MAGENTA,
Line.hasMultipleRegions() && getOptions().Colors)
<< C;
OS << '|';
}
void SourceCoverageViewText::renderLineNumberColumn(raw_ostream &OS,
unsigned LineNo) {
SmallString<32> Buffer;
raw_svector_ostream BufferOS(Buffer);
BufferOS << LineNo;
auto Str = BufferOS.str();
// Trim and align to the right.
Str = Str.substr(0, std::min(Str.size(), (size_t)LineNumberColumnWidth));
OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|';
}
void SourceCoverageViewText::renderRegionMarkers(
raw_ostream &OS, CoverageSegmentArray Segments, unsigned ViewDepth) {
renderLinePrefix(OS, ViewDepth);
OS.indent(getCombinedColumnWidth(getOptions()));
unsigned PrevColumn = 1;
for (const auto *S : Segments) {
if (!S->IsRegionEntry)
continue;
// Skip to the new region.
if (S->Col > PrevColumn)
OS.indent(S->Col - PrevColumn);
PrevColumn = S->Col + 1;
std::string C = formatCount(S->Count);
PrevColumn += C.size();
OS << '^' << C;
}
OS << '\n';
if (getOptions().Debug)
for (const auto *S : Segments)
errs() << "Marker at " << S->Line << ":" << S->Col << " = "
<< formatCount(S->Count) << (S->IsRegionEntry ? "\n" : " (pop)\n");
}
unsigned SourceCoverageViewText::renderExpansionView(
raw_ostream &OS, ExpansionView &ESV, Optional<LineRef> FirstLine,
unsigned ExpansionCol, const coverage::CoverageSegment *WrappedSegment,
CoverageSegmentArray LineSegments, unsigned ViewDepth) {
unsigned NextExpansionCol = ExpansionCol;
if (FirstLine.hasValue()) {
// Re-render the current line and highlight the expansion range for
// this subview.
NextExpansionCol = ESV.getStartCol();
renderLinePrefix(OS, ViewDepth);
OS.indent(getCombinedColumnWidth(getOptions()) + (ViewDepth == 0 ? 0 : 1));
renderLine(OS, *FirstLine, WrappedSegment, LineSegments, ExpansionCol,
ViewDepth);
renderViewDivider(OS, ViewDepth + 1);
}
// Render the child subview.
if (getOptions().Debug)
errs() << "Expansion at line " << ESV.getLine() << ", " << ESV.getStartCol()
<< " -> " << ESV.getEndCol() << '\n';
ESV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/false,
ViewDepth + 1);
return NextExpansionCol;
}
void SourceCoverageViewText::renderInstantiationView(raw_ostream &OS,
InstantiationView &ISV,
unsigned ViewDepth) {
renderViewDivider(OS, ViewDepth);
renderLinePrefix(OS, ViewDepth);
OS << ' ';
ISV.View->print(OS, /*WholeFile=*/false, /*ShowSourceName=*/true, ViewDepth);
}

View File

@ -0,0 +1,61 @@
//===- SourceCoverageViewText.h - A text-based code coverage view ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interface to the text-based coverage renderer.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_COV_SOURCECOVERAGEVIEWTEXT_H
#define LLVM_COV_SOURCECOVERAGEVIEWTEXT_H
#include "SourceCoverageView.h"
namespace llvm {
class SourceCoverageViewText : public SourceCoverageView {
void renderSourceName(raw_ostream &OS) override;
void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) override;
void renderViewDivider(raw_ostream &OS, unsigned ViewDepth) override;
void renderLine(raw_ostream &OS, LineRef L,
const coverage::CoverageSegment *WrappedSegment,
CoverageSegmentArray Segments, unsigned ExpansionCol,
unsigned ViewDepth) override;
unsigned renderExpansionView(raw_ostream &OS, ExpansionView &ESV,
Optional<LineRef> FirstLine,
unsigned ExpansionCol,
const coverage::CoverageSegment *WrappedSegment,
CoverageSegmentArray LineSegments,
unsigned ViewDepth) override;
void renderInstantiationView(raw_ostream &OS, InstantiationView &ISV,
unsigned ViewDepth) override;
void renderLineCoverageColumn(raw_ostream &OS,
const LineCoverageStats &Line) override;
void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo) override;
void renderRegionMarkers(raw_ostream &OS, CoverageSegmentArray Segments,
unsigned ViewDepth) override;
public:
SourceCoverageViewText(StringRef SourceName, const MemoryBuffer &File,
const CoverageViewOptions &Options,
coverage::CoverageData &&CoverageInfo)
: SourceCoverageView(SourceName, File, Options, std::move(CoverageInfo)) {
}
};
} // namespace llvm
#endif // LLVM_COV_SOURCECOVERAGEVIEWTEXT_H