diff options
author | vvvv <vvvv@ydb.tech> | 2024-02-06 20:01:22 +0300 |
---|---|---|
committer | vvvv <vvvv@ydb.tech> | 2024-02-06 20:22:16 +0300 |
commit | 0203b7a9a40828bb2bd4c32029b79ff0ea3d1f8f (patch) | |
tree | e630d0d5bd0bd29fc8c2d2842ed2cfde781b993a /contrib/libs/llvm16/tools/llvm-cov/SourceCoverageView.cpp | |
parent | ba27db76d99d12a4f1c06960b5449423218614c4 (diff) | |
download | ydb-0203b7a9a40828bb2bd4c32029b79ff0ea3d1f8f.tar.gz |
llvm16 targets
Diffstat (limited to 'contrib/libs/llvm16/tools/llvm-cov/SourceCoverageView.cpp')
-rw-r--r-- | contrib/libs/llvm16/tools/llvm-cov/SourceCoverageView.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/contrib/libs/llvm16/tools/llvm-cov/SourceCoverageView.cpp b/contrib/libs/llvm16/tools/llvm-cov/SourceCoverageView.cpp new file mode 100644 index 0000000000..ea86acadf0 --- /dev/null +++ b/contrib/libs/llvm16/tools/llvm-cov/SourceCoverageView.cpp @@ -0,0 +1,281 @@ +//===- SourceCoverageView.cpp - Code coverage view for source code --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file This class implements rendering for code coverage of source code. +/// +//===----------------------------------------------------------------------===// + +#include "SourceCoverageView.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 CoveragePrinter::StreamDestructor::operator()(raw_ostream *OS) const { + if (OS == &outs()) + return; + delete OS; +} + +std::string CoveragePrinter::getOutputPath(StringRef Path, StringRef Extension, + bool InToplevel, + bool Relative) const { + assert(!Extension.empty() && "The file extension may not be empty"); + + SmallString<256> FullPath; + + if (!Relative) + FullPath.append(Opts.ShowOutputDirectory); + + if (!InToplevel) + sys::path::append(FullPath, getCoverageDir()); + + SmallString<256> ParentPath = sys::path::parent_path(Path); + sys::path::remove_dots(ParentPath, /*remove_dot_dot=*/true); + sys::path::append(FullPath, sys::path::relative_path(ParentPath)); + + auto PathFilename = (sys::path::filename(Path) + "." + Extension).str(); + sys::path::append(FullPath, PathFilename); + sys::path::native(FullPath); + + return std::string(FullPath.str()); +} + +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::FA_Read | sys::fs::FA_Write); + auto OS = CoveragePrinter::OwnedStream(RawStream); + if (E) + return errorCodeToError(E); + return std::move(OS); +} + +std::unique_ptr<CoveragePrinter> +CoveragePrinter::create(const CoverageViewOptions &Opts) { + switch (Opts.Format) { + case CoverageViewOptions::OutputFormat::Text: + return std::make_unique<CoveragePrinterText>(Opts); + case CoverageViewOptions::OutputFormat::HTML: + return std::make_unique<CoveragePrinterHTML>(Opts); + case CoverageViewOptions::OutputFormat::Lcov: + // Unreachable because CodeCoverage.cpp should terminate with an error + // before we get here. + llvm_unreachable("Lcov format is not supported!"); + } + llvm_unreachable("Unknown coverage output format!"); +} + +unsigned SourceCoverageView::getFirstUncoveredLineNo() { + const auto MinSegIt = find_if(CoverageInfo, [](const CoverageSegment &S) { + return S.HasCount && S.Count == 0; + }); + + // There is no uncovered line, return zero. + if (MinSegIt == CoverageInfo.end()) + return 0; + + return (*MinSegIt).Line; +} + +std::string SourceCoverageView::formatCount(uint64_t N) { + std::string Number = utostr(N); + int Len = Number.size(); + if (Len <= 3) + return Number; + int IntLen = Len % 3 == 0 ? 3 : Len % 3; + std::string Result(Number.data(), IntLen); + if (IntLen != 3) { + Result.push_back('.'); + Result += Number.substr(IntLen, 3 - IntLen); + } + Result.push_back(" kMGTPEZY"[(Len - 1) / 3]); + return Result; +} + +bool SourceCoverageView::shouldRenderRegionMarkers( + const LineCoverageStats &LCS) const { + if (!getOptions().ShowRegionMarkers) + return false; + + CoverageSegmentArray Segments = LCS.getLineSegments(); + if (Segments.empty()) + return false; + for (unsigned I = 0, E = Segments.size() - 1; I < E; ++I) { + const auto *CurSeg = Segments[I]; + if (!CurSeg->IsRegionEntry || CurSeg->Count == LCS.getExecutionCount()) + continue; + return true; + } + return false; +} + +bool SourceCoverageView::hasSubViews() const { + return !ExpansionSubViews.empty() || !InstantiationSubViews.empty() || + !BranchSubViews.empty(); +} + +std::unique_ptr<SourceCoverageView> +SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File, + const CoverageViewOptions &Options, + CoverageData &&CoverageInfo) { + switch (Options.Format) { + case CoverageViewOptions::OutputFormat::Text: + return std::make_unique<SourceCoverageViewText>( + SourceName, File, Options, std::move(CoverageInfo)); + case CoverageViewOptions::OutputFormat::HTML: + return std::make_unique<SourceCoverageViewHTML>( + SourceName, File, Options, std::move(CoverageInfo)); + case CoverageViewOptions::OutputFormat::Lcov: + // Unreachable because CodeCoverage.cpp should terminate with an error + // before we get here. + llvm_unreachable("Lcov format is not supported!"); + } + llvm_unreachable("Unknown coverage output format!"); +} + +std::string SourceCoverageView::getSourceName() const { + SmallString<128> SourceText(SourceName); + sys::path::remove_dots(SourceText, /*remove_dot_dot=*/true); + sys::path::native(SourceText); + return std::string(SourceText.str()); +} + +void SourceCoverageView::addExpansion( + const CounterMappingRegion &Region, + std::unique_ptr<SourceCoverageView> View) { + ExpansionSubViews.emplace_back(Region, std::move(View)); +} + +void SourceCoverageView::addBranch(unsigned Line, + ArrayRef<CountedRegion> Regions, + std::unique_ptr<SourceCoverageView> View) { + BranchSubViews.emplace_back(Line, Regions, std::move(View)); +} + +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, bool ShowTitle, + unsigned ViewDepth) { + if (ShowTitle) + renderTitle(OS, "Coverage Report"); + + renderViewHeader(OS); + + if (ShowSourceName) + renderSourceName(OS, WholeFile); + + renderTableHeader(OS, (ViewDepth > 0) ? 0 : getFirstUncoveredLineNo(), + ViewDepth); + + // We need the expansions, instantiations, and branches sorted so we can go + // through them while we iterate lines. + llvm::stable_sort(ExpansionSubViews); + llvm::stable_sort(InstantiationSubViews); + llvm::stable_sort(BranchSubViews); + auto NextESV = ExpansionSubViews.begin(); + auto EndESV = ExpansionSubViews.end(); + auto NextISV = InstantiationSubViews.begin(); + auto EndISV = InstantiationSubViews.end(); + auto NextBRV = BranchSubViews.begin(); + auto EndBRV = BranchSubViews.end(); + + // Get the coverage information for the file. + auto StartSegment = CoverageInfo.begin(); + auto EndSegment = CoverageInfo.end(); + LineCoverageIterator LCI{CoverageInfo, 1}; + LineCoverageIterator LCIEnd = LCI.getEnd(); + + unsigned FirstLine = StartSegment != EndSegment ? StartSegment->Line : 0; + for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof(); + ++LI, ++LCI) { + // If we aren't rendering the whole file, we need to filter out the prologue + // and epilogue. + if (!WholeFile) { + if (LCI == LCIEnd) + break; + else if (LI.line_number() < FirstLine) + continue; + } + + renderLinePrefix(OS, ViewDepth); + if (getOptions().ShowLineNumbers) + renderLineNumberColumn(OS, LI.line_number()); + + if (getOptions().ShowLineStats) + renderLineCoverageColumn(OS, *LCI); + + // If there are expansion subviews, we want to highlight the first one. + unsigned ExpansionColumn = 0; + if (NextESV != EndESV && NextESV->getLine() == LI.line_number() && + getOptions().Colors) + ExpansionColumn = NextESV->getStartCol(); + + // Display the source code for the current line. + renderLine(OS, {*LI, LI.line_number()}, *LCI, ExpansionColumn, ViewDepth); + + // Show the region markers. + if (shouldRenderRegionMarkers(*LCI)) + renderRegionMarkers(OS, *LCI, ViewDepth); + + // Show the expansions, instantiations, and branches for this line. + bool RenderedSubView = false; + for (; NextESV != EndESV && NextESV->getLine() == LI.line_number(); + ++NextESV) { + renderViewDivider(OS, ViewDepth + 1); + + // Re-render the current line and highlight the expansion range for + // this subview. + if (RenderedSubView) { + ExpansionColumn = NextESV->getStartCol(); + renderExpansionSite(OS, {*LI, LI.line_number()}, *LCI, ExpansionColumn, + ViewDepth); + renderViewDivider(OS, ViewDepth + 1); + } + + renderExpansionView(OS, *NextESV, ViewDepth + 1); + RenderedSubView = true; + } + for (; NextISV != EndISV && NextISV->Line == LI.line_number(); ++NextISV) { + renderViewDivider(OS, ViewDepth + 1); + renderInstantiationView(OS, *NextISV, ViewDepth + 1); + RenderedSubView = true; + } + for (; NextBRV != EndBRV && NextBRV->Line == LI.line_number(); ++NextBRV) { + renderViewDivider(OS, ViewDepth + 1); + renderBranchView(OS, *NextBRV, ViewDepth + 1); + RenderedSubView = true; + } + if (RenderedSubView) + renderViewDivider(OS, ViewDepth + 1); + renderLineSuffix(OS, ViewDepth); + } + + renderViewFooter(OS); +} |