Mercurial > hg > CbC > CbC_llvm
diff tools/llvm-cov/SourceCoverageView.cpp @ 120:1172e4bd9c6f
update 4.0.0
author | mir3636 |
---|---|
date | Fri, 25 Nov 2016 19:14:25 +0900 |
parents | afa8332a0e37 |
children | 803732b1fca8 |
line wrap: on
line diff
--- a/tools/llvm-cov/SourceCoverageView.cpp Tue Jan 26 22:56:36 2016 +0900 +++ b/tools/llvm-cov/SourceCoverageView.cpp Fri Nov 25 19:14:25 2016 +0900 @@ -6,80 +6,103 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// -// This class implements rendering for code coverage of source code. -// +/// +/// \file This class implements rendering for code coverage of source code. +/// //===----------------------------------------------------------------------===// #include "SourceCoverageView.h" -#include "llvm/ADT/Optional.h" +#include "SourceCoverageViewHTML.h" +#include "SourceCoverageViewText.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/LineIterator.h" +#include "llvm/Support/Path.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; +void CoveragePrinter::StreamDestructor::operator()(raw_ostream *OS) const { + if (OS == &outs()) + return; + delete OS; +} - // The first segment overlaps from a previous line, so we treat it specially. - if (WrappedSegment && WrappedSegment->HasCount && WrappedSegment->Count == 0) - Highlight = raw_ostream::RED; +std::string CoveragePrinter::getOutputPath(StringRef Path, StringRef Extension, + bool InToplevel, + bool Relative) const { + assert(Extension.size() && "The file extension may not be empty"); + + SmallString<256> FullPath; - // 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, - Options.Colors && Highlight, /*Bold=*/false, /*BG=*/true) - << Line.substr(Col - 1, End - Col); - if (Options.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; - } + if (!Relative) + FullPath.append(Opts.ShowOutputDirectory); + + if (!InToplevel) + sys::path::append(FullPath, getCoverageDir()); - // Show the rest of the line - colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR, - Options.Colors && Highlight, /*Bold=*/false, /*BG=*/true) - << Line.substr(Col - 1, Line.size() - Col + 1); - OS << "\n"; + SmallString<256> ParentPath = sys::path::parent_path(Path); + sys::path::remove_dots(ParentPath, /*remove_dot_dots=*/true); + sys::path::append(FullPath, sys::path::relative_path(ParentPath)); - if (Options.Debug) { - for (const auto &Range : HighlightedRanges) - errs() << "Highlighted line " << LineNumber << ", " << Range.first - << " -> " << Range.second << "\n"; - if (Highlight) - errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n"; - } + auto PathFilename = (sys::path::filename(Path) + "." + Extension).str(); + sys::path::append(FullPath, PathFilename); + sys::path::native(FullPath); + + return FullPath.str(); } -void SourceCoverageView::renderIndent(raw_ostream &OS, unsigned Level) { - for (unsigned I = 0; I < Level; ++I) - OS << " |"; +Expected<CoveragePrinter::OwnedStream> +CoveragePrinter::createOutputStream(StringRef Path, StringRef Extension, + bool InToplevel) const { + if (!Opts.hasOutputDirectory()) + return OwnedStream(&outs()); + + std::string FullPath = getOutputPath(Path, Extension, InToplevel, false); + + auto ParentDir = sys::path::parent_path(FullPath); + if (auto E = sys::fs::create_directories(ParentDir)) + return errorCodeToError(E); + + std::error_code E; + raw_ostream *RawStream = new raw_fd_ostream(FullPath, E, sys::fs::F_RW); + auto OS = CoveragePrinter::OwnedStream(RawStream); + if (E) + return errorCodeToError(E); + return std::move(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 << "-"; +std::unique_ptr<CoveragePrinter> +CoveragePrinter::create(const CoverageViewOptions &Opts) { + switch (Opts.Format) { + case CoverageViewOptions::OutputFormat::Text: + return llvm::make_unique<CoveragePrinterText>(Opts); + case CoverageViewOptions::OutputFormat::HTML: + return llvm::make_unique<CoveragePrinterHTML>(Opts); + } + llvm_unreachable("Unknown coverage output format!"); } -/// Format a count using engineering notation with 3 significant digits. -static std::string formatCount(uint64_t N) { +unsigned SourceCoverageView::getFirstUncoveredLineNo() { + auto CheckIfUncovered = [](const coverage::CoverageSegment &S) { + return S.HasCount && S.Count == 0; + }; + // L is less than R if (1) it's an uncovered segment (has a 0 count), and (2) + // either R is not an uncovered segment, or L has a lower line number than R. + const auto MinSegIt = + std::min_element(CoverageInfo.begin(), CoverageInfo.end(), + [CheckIfUncovered](const coverage::CoverageSegment &L, + const coverage::CoverageSegment &R) { + return (CheckIfUncovered(L) && + (!CheckIfUncovered(R) || (L.Line < R.Line))); + }); + if (CheckIfUncovered(*MinSegIt)) + return (*MinSegIt).Line; + // There is no uncovered line, return zero. + return 0; +} + +std::string SourceCoverageView::formatCount(uint64_t N) { std::string Number = utostr(N); int Len = Number.size(); if (Len <= 3) @@ -94,63 +117,62 @@ return Result; } -void -SourceCoverageView::renderLineCoverageColumn(raw_ostream &OS, - const LineCoverageInfo &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() && Options.Colors) - << C; - OS << '|'; +bool SourceCoverageView::shouldRenderRegionMarkers( + bool LineHasMultipleRegions) const { + return getOptions().ShowRegionMarkers && + (!getOptions().ShowLineStatsOrRegionMarkers || LineHasMultipleRegions); +} + +bool SourceCoverageView::hasSubViews() const { + return !ExpansionSubViews.empty() || !InstantiationSubViews.empty(); } -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 << '|'; +std::unique_ptr<SourceCoverageView> +SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File, + const CoverageViewOptions &Options, + coverage::CoverageData &&CoverageInfo) { + switch (Options.Format) { + case CoverageViewOptions::OutputFormat::Text: + return llvm::make_unique<SourceCoverageViewText>( + SourceName, File, Options, std::move(CoverageInfo)); + case CoverageViewOptions::OutputFormat::HTML: + return llvm::make_unique<SourceCoverageViewHTML>( + SourceName, File, Options, std::move(CoverageInfo)); + } + llvm_unreachable("Unknown coverage output format!"); } -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"; +std::string SourceCoverageView::getSourceName() const { + SmallString<128> SourceText(SourceName); + sys::path::remove_dots(SourceText, /*remove_dot_dots=*/true); + sys::path::native(SourceText); + return SourceText.str(); +} - if (Options.Debug) - for (const auto *S : Segments) - errs() << "Marker at " << S->Line << ":" << S->Col << " = " - << formatCount(S->Count) << (S->IsRegionEntry ? "\n" : " (pop)\n"); +void SourceCoverageView::addExpansion( + const coverage::CounterMappingRegion &Region, + std::unique_ptr<SourceCoverageView> View) { + ExpansionSubViews.emplace_back(Region, std::move(View)); } -void SourceCoverageView::render(raw_ostream &OS, bool WholeFile, - unsigned IndentLevel) { - // The width of the leading columns - unsigned CombinedColumnWidth = - (Options.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) + - (Options.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::addInstantiation( + StringRef FunctionName, unsigned Line, + std::unique_ptr<SourceCoverageView> View) { + InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View)); +} + +void SourceCoverageView::print(raw_ostream &OS, bool WholeFile, + bool ShowSourceName, unsigned ViewDepth) { + if (WholeFile && getOptions().hasOutputDirectory()) + renderTitle(OS, "Coverage Report"); + + renderViewHeader(OS); + + if (ShowSourceName) + renderSourceName(OS, WholeFile); + + renderTableHeader(OS, (ViewDepth > 0) ? 0 : getFirstUncoveredLineNo(), + ViewDepth); // We need the expansions and instantiations sorted so we can go through them // while we iterate lines. @@ -186,79 +208,60 @@ LineSegments.push_back(&*NextSegment++); // Calculate a count to be for the line as a whole. - LineCoverageInfo LineCount; + LineCoverageStats LineCount; if (WrappedSegment && WrappedSegment->HasCount) 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); - if (Options.ShowLineStats) + renderLinePrefix(OS, ViewDepth); + if (getOptions().ShowLineNumbers) + renderLineNumberColumn(OS, LI.line_number()); + if (getOptions().ShowLineStats) renderLineCoverageColumn(OS, LineCount); - if (Options.ShowLineNumbers) - renderLineNumberColumn(OS, LI.line_number()); // If there are expansion subviews, we want to highlight the first one. unsigned ExpansionColumn = 0; if (NextESV != EndESV && NextESV->getLine() == LI.line_number() && - Options.Colors) + getOptions().Colors) 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 (Options.ShowRegionMarkers && (!Options.ShowLineStatsOrRegionMarkers || - LineCount.hasMultipleRegions()) && - !LineSegments.empty()) { - renderIndent(OS, IndentLevel); - OS.indent(CombinedColumnWidth); - renderRegionMarkers(OS, LineSegments); - } + if (shouldRenderRegionMarkers(LineCount.hasMultipleRegions())) + 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"; + renderViewDivider(OS, ViewDepth + 1); + + // Re-render the current line and highlight the expansion range for + // this subview. 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"; + renderExpansionSite(OS, {*LI, LI.line_number()}, WrappedSegment, + LineSegments, ExpansionColumn, ViewDepth); + renderViewDivider(OS, ViewDepth + 1); } - // Render the child subview - if (Options.Debug) - errs() << "Expansion at line " << NextESV->getLine() << ", " - << NextESV->getStartCol() << " -> " << NextESV->getEndCol() - << "\n"; - NextESV->View->render(OS, false, NestedIndent); + + renderExpansionView(OS, *NextESV, ViewDepth + 1); RenderedSubView = true; } for (; NextISV != EndISV && NextISV->Line == LI.line_number(); ++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, false, NestedIndent); + renderViewDivider(OS, ViewDepth + 1); + renderInstantiationView(OS, *NextISV, ViewDepth + 1); RenderedSubView = true; } - if (RenderedSubView) { - renderViewDivider(NestedIndent, DividerWidth, OS); - OS << "\n"; - } + if (RenderedSubView) + renderViewDivider(OS, ViewDepth + 1); + renderLineSuffix(OS, ViewDepth); } + + renderViewFooter(OS); }