1*9880d681SAndroid Build Coastguard Worker //===- SourceCoverageView.cpp - Code coverage view for source code --------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker // The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker ///
10*9880d681SAndroid Build Coastguard Worker /// \file This class implements rendering for code coverage of source code.
11*9880d681SAndroid Build Coastguard Worker ///
12*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
13*9880d681SAndroid Build Coastguard Worker
14*9880d681SAndroid Build Coastguard Worker #include "SourceCoverageView.h"
15*9880d681SAndroid Build Coastguard Worker #include "SourceCoverageViewHTML.h"
16*9880d681SAndroid Build Coastguard Worker #include "SourceCoverageViewText.h"
17*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/SmallString.h"
18*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/StringExtras.h"
19*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/FileSystem.h"
20*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/LineIterator.h"
21*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Path.h"
22*9880d681SAndroid Build Coastguard Worker
23*9880d681SAndroid Build Coastguard Worker using namespace llvm;
24*9880d681SAndroid Build Coastguard Worker
operator ()(raw_ostream * OS) const25*9880d681SAndroid Build Coastguard Worker void CoveragePrinter::StreamDestructor::operator()(raw_ostream *OS) const {
26*9880d681SAndroid Build Coastguard Worker if (OS == &outs())
27*9880d681SAndroid Build Coastguard Worker return;
28*9880d681SAndroid Build Coastguard Worker delete OS;
29*9880d681SAndroid Build Coastguard Worker }
30*9880d681SAndroid Build Coastguard Worker
getOutputPath(StringRef Path,StringRef Extension,bool InToplevel,bool Relative)31*9880d681SAndroid Build Coastguard Worker std::string CoveragePrinter::getOutputPath(StringRef Path, StringRef Extension,
32*9880d681SAndroid Build Coastguard Worker bool InToplevel, bool Relative) {
33*9880d681SAndroid Build Coastguard Worker assert(Extension.size() && "The file extension may not be empty");
34*9880d681SAndroid Build Coastguard Worker
35*9880d681SAndroid Build Coastguard Worker SmallString<256> FullPath;
36*9880d681SAndroid Build Coastguard Worker
37*9880d681SAndroid Build Coastguard Worker if (!Relative)
38*9880d681SAndroid Build Coastguard Worker FullPath.append(Opts.ShowOutputDirectory);
39*9880d681SAndroid Build Coastguard Worker
40*9880d681SAndroid Build Coastguard Worker if (!InToplevel)
41*9880d681SAndroid Build Coastguard Worker sys::path::append(FullPath, getCoverageDir());
42*9880d681SAndroid Build Coastguard Worker
43*9880d681SAndroid Build Coastguard Worker SmallString<256> ParentPath = sys::path::parent_path(Path);
44*9880d681SAndroid Build Coastguard Worker sys::path::remove_dots(ParentPath, /*remove_dot_dots=*/true);
45*9880d681SAndroid Build Coastguard Worker sys::path::append(FullPath, sys::path::relative_path(ParentPath));
46*9880d681SAndroid Build Coastguard Worker
47*9880d681SAndroid Build Coastguard Worker auto PathFilename = (sys::path::filename(Path) + "." + Extension).str();
48*9880d681SAndroid Build Coastguard Worker sys::path::append(FullPath, PathFilename);
49*9880d681SAndroid Build Coastguard Worker
50*9880d681SAndroid Build Coastguard Worker return FullPath.str();
51*9880d681SAndroid Build Coastguard Worker }
52*9880d681SAndroid Build Coastguard Worker
53*9880d681SAndroid Build Coastguard Worker Expected<CoveragePrinter::OwnedStream>
createOutputStream(StringRef Path,StringRef Extension,bool InToplevel)54*9880d681SAndroid Build Coastguard Worker CoveragePrinter::createOutputStream(StringRef Path, StringRef Extension,
55*9880d681SAndroid Build Coastguard Worker bool InToplevel) {
56*9880d681SAndroid Build Coastguard Worker if (!Opts.hasOutputDirectory())
57*9880d681SAndroid Build Coastguard Worker return OwnedStream(&outs());
58*9880d681SAndroid Build Coastguard Worker
59*9880d681SAndroid Build Coastguard Worker std::string FullPath = getOutputPath(Path, Extension, InToplevel, false);
60*9880d681SAndroid Build Coastguard Worker
61*9880d681SAndroid Build Coastguard Worker auto ParentDir = sys::path::parent_path(FullPath);
62*9880d681SAndroid Build Coastguard Worker if (auto E = sys::fs::create_directories(ParentDir))
63*9880d681SAndroid Build Coastguard Worker return errorCodeToError(E);
64*9880d681SAndroid Build Coastguard Worker
65*9880d681SAndroid Build Coastguard Worker std::error_code E;
66*9880d681SAndroid Build Coastguard Worker raw_ostream *RawStream = new raw_fd_ostream(FullPath, E, sys::fs::F_RW);
67*9880d681SAndroid Build Coastguard Worker auto OS = CoveragePrinter::OwnedStream(RawStream);
68*9880d681SAndroid Build Coastguard Worker if (E)
69*9880d681SAndroid Build Coastguard Worker return errorCodeToError(E);
70*9880d681SAndroid Build Coastguard Worker return std::move(OS);
71*9880d681SAndroid Build Coastguard Worker }
72*9880d681SAndroid Build Coastguard Worker
73*9880d681SAndroid Build Coastguard Worker std::unique_ptr<CoveragePrinter>
create(const CoverageViewOptions & Opts)74*9880d681SAndroid Build Coastguard Worker CoveragePrinter::create(const CoverageViewOptions &Opts) {
75*9880d681SAndroid Build Coastguard Worker switch (Opts.Format) {
76*9880d681SAndroid Build Coastguard Worker case CoverageViewOptions::OutputFormat::Text:
77*9880d681SAndroid Build Coastguard Worker return llvm::make_unique<CoveragePrinterText>(Opts);
78*9880d681SAndroid Build Coastguard Worker case CoverageViewOptions::OutputFormat::HTML:
79*9880d681SAndroid Build Coastguard Worker return llvm::make_unique<CoveragePrinterHTML>(Opts);
80*9880d681SAndroid Build Coastguard Worker }
81*9880d681SAndroid Build Coastguard Worker llvm_unreachable("Unknown coverage output format!");
82*9880d681SAndroid Build Coastguard Worker }
83*9880d681SAndroid Build Coastguard Worker
formatCount(uint64_t N)84*9880d681SAndroid Build Coastguard Worker std::string SourceCoverageView::formatCount(uint64_t N) {
85*9880d681SAndroid Build Coastguard Worker std::string Number = utostr(N);
86*9880d681SAndroid Build Coastguard Worker int Len = Number.size();
87*9880d681SAndroid Build Coastguard Worker if (Len <= 3)
88*9880d681SAndroid Build Coastguard Worker return Number;
89*9880d681SAndroid Build Coastguard Worker int IntLen = Len % 3 == 0 ? 3 : Len % 3;
90*9880d681SAndroid Build Coastguard Worker std::string Result(Number.data(), IntLen);
91*9880d681SAndroid Build Coastguard Worker if (IntLen != 3) {
92*9880d681SAndroid Build Coastguard Worker Result.push_back('.');
93*9880d681SAndroid Build Coastguard Worker Result += Number.substr(IntLen, 3 - IntLen);
94*9880d681SAndroid Build Coastguard Worker }
95*9880d681SAndroid Build Coastguard Worker Result.push_back(" kMGTPEZY"[(Len - 1) / 3]);
96*9880d681SAndroid Build Coastguard Worker return Result;
97*9880d681SAndroid Build Coastguard Worker }
98*9880d681SAndroid Build Coastguard Worker
shouldRenderRegionMarkers(bool LineHasMultipleRegions) const99*9880d681SAndroid Build Coastguard Worker bool SourceCoverageView::shouldRenderRegionMarkers(
100*9880d681SAndroid Build Coastguard Worker bool LineHasMultipleRegions) const {
101*9880d681SAndroid Build Coastguard Worker return getOptions().ShowRegionMarkers &&
102*9880d681SAndroid Build Coastguard Worker (!getOptions().ShowLineStatsOrRegionMarkers || LineHasMultipleRegions);
103*9880d681SAndroid Build Coastguard Worker }
104*9880d681SAndroid Build Coastguard Worker
hasSubViews() const105*9880d681SAndroid Build Coastguard Worker bool SourceCoverageView::hasSubViews() const {
106*9880d681SAndroid Build Coastguard Worker return !ExpansionSubViews.empty() || !InstantiationSubViews.empty();
107*9880d681SAndroid Build Coastguard Worker }
108*9880d681SAndroid Build Coastguard Worker
109*9880d681SAndroid Build Coastguard Worker std::unique_ptr<SourceCoverageView>
create(StringRef SourceName,const MemoryBuffer & File,const CoverageViewOptions & Options,coverage::CoverageData && CoverageInfo)110*9880d681SAndroid Build Coastguard Worker SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File,
111*9880d681SAndroid Build Coastguard Worker const CoverageViewOptions &Options,
112*9880d681SAndroid Build Coastguard Worker coverage::CoverageData &&CoverageInfo) {
113*9880d681SAndroid Build Coastguard Worker switch (Options.Format) {
114*9880d681SAndroid Build Coastguard Worker case CoverageViewOptions::OutputFormat::Text:
115*9880d681SAndroid Build Coastguard Worker return llvm::make_unique<SourceCoverageViewText>(SourceName, File, Options,
116*9880d681SAndroid Build Coastguard Worker std::move(CoverageInfo));
117*9880d681SAndroid Build Coastguard Worker case CoverageViewOptions::OutputFormat::HTML:
118*9880d681SAndroid Build Coastguard Worker return llvm::make_unique<SourceCoverageViewHTML>(SourceName, File, Options,
119*9880d681SAndroid Build Coastguard Worker std::move(CoverageInfo));
120*9880d681SAndroid Build Coastguard Worker }
121*9880d681SAndroid Build Coastguard Worker llvm_unreachable("Unknown coverage output format!");
122*9880d681SAndroid Build Coastguard Worker }
123*9880d681SAndroid Build Coastguard Worker
addExpansion(const coverage::CounterMappingRegion & Region,std::unique_ptr<SourceCoverageView> View)124*9880d681SAndroid Build Coastguard Worker void SourceCoverageView::addExpansion(
125*9880d681SAndroid Build Coastguard Worker const coverage::CounterMappingRegion &Region,
126*9880d681SAndroid Build Coastguard Worker std::unique_ptr<SourceCoverageView> View) {
127*9880d681SAndroid Build Coastguard Worker ExpansionSubViews.emplace_back(Region, std::move(View));
128*9880d681SAndroid Build Coastguard Worker }
129*9880d681SAndroid Build Coastguard Worker
addInstantiation(StringRef FunctionName,unsigned Line,std::unique_ptr<SourceCoverageView> View)130*9880d681SAndroid Build Coastguard Worker void SourceCoverageView::addInstantiation(
131*9880d681SAndroid Build Coastguard Worker StringRef FunctionName, unsigned Line,
132*9880d681SAndroid Build Coastguard Worker std::unique_ptr<SourceCoverageView> View) {
133*9880d681SAndroid Build Coastguard Worker InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
134*9880d681SAndroid Build Coastguard Worker }
135*9880d681SAndroid Build Coastguard Worker
print(raw_ostream & OS,bool WholeFile,bool ShowSourceName,unsigned ViewDepth)136*9880d681SAndroid Build Coastguard Worker void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
137*9880d681SAndroid Build Coastguard Worker bool ShowSourceName, unsigned ViewDepth) {
138*9880d681SAndroid Build Coastguard Worker if (ShowSourceName)
139*9880d681SAndroid Build Coastguard Worker renderSourceName(OS);
140*9880d681SAndroid Build Coastguard Worker
141*9880d681SAndroid Build Coastguard Worker renderViewHeader(OS);
142*9880d681SAndroid Build Coastguard Worker
143*9880d681SAndroid Build Coastguard Worker // We need the expansions and instantiations sorted so we can go through them
144*9880d681SAndroid Build Coastguard Worker // while we iterate lines.
145*9880d681SAndroid Build Coastguard Worker std::sort(ExpansionSubViews.begin(), ExpansionSubViews.end());
146*9880d681SAndroid Build Coastguard Worker std::sort(InstantiationSubViews.begin(), InstantiationSubViews.end());
147*9880d681SAndroid Build Coastguard Worker auto NextESV = ExpansionSubViews.begin();
148*9880d681SAndroid Build Coastguard Worker auto EndESV = ExpansionSubViews.end();
149*9880d681SAndroid Build Coastguard Worker auto NextISV = InstantiationSubViews.begin();
150*9880d681SAndroid Build Coastguard Worker auto EndISV = InstantiationSubViews.end();
151*9880d681SAndroid Build Coastguard Worker
152*9880d681SAndroid Build Coastguard Worker // Get the coverage information for the file.
153*9880d681SAndroid Build Coastguard Worker auto NextSegment = CoverageInfo.begin();
154*9880d681SAndroid Build Coastguard Worker auto EndSegment = CoverageInfo.end();
155*9880d681SAndroid Build Coastguard Worker
156*9880d681SAndroid Build Coastguard Worker unsigned FirstLine = NextSegment != EndSegment ? NextSegment->Line : 0;
157*9880d681SAndroid Build Coastguard Worker const coverage::CoverageSegment *WrappedSegment = nullptr;
158*9880d681SAndroid Build Coastguard Worker SmallVector<const coverage::CoverageSegment *, 8> LineSegments;
159*9880d681SAndroid Build Coastguard Worker for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof(); ++LI) {
160*9880d681SAndroid Build Coastguard Worker // If we aren't rendering the whole file, we need to filter out the prologue
161*9880d681SAndroid Build Coastguard Worker // and epilogue.
162*9880d681SAndroid Build Coastguard Worker if (!WholeFile) {
163*9880d681SAndroid Build Coastguard Worker if (NextSegment == EndSegment)
164*9880d681SAndroid Build Coastguard Worker break;
165*9880d681SAndroid Build Coastguard Worker else if (LI.line_number() < FirstLine)
166*9880d681SAndroid Build Coastguard Worker continue;
167*9880d681SAndroid Build Coastguard Worker }
168*9880d681SAndroid Build Coastguard Worker
169*9880d681SAndroid Build Coastguard Worker // Collect the coverage information relevant to this line.
170*9880d681SAndroid Build Coastguard Worker if (LineSegments.size())
171*9880d681SAndroid Build Coastguard Worker WrappedSegment = LineSegments.back();
172*9880d681SAndroid Build Coastguard Worker LineSegments.clear();
173*9880d681SAndroid Build Coastguard Worker while (NextSegment != EndSegment && NextSegment->Line == LI.line_number())
174*9880d681SAndroid Build Coastguard Worker LineSegments.push_back(&*NextSegment++);
175*9880d681SAndroid Build Coastguard Worker
176*9880d681SAndroid Build Coastguard Worker // Calculate a count to be for the line as a whole.
177*9880d681SAndroid Build Coastguard Worker LineCoverageStats LineCount;
178*9880d681SAndroid Build Coastguard Worker if (WrappedSegment && WrappedSegment->HasCount)
179*9880d681SAndroid Build Coastguard Worker LineCount.addRegionCount(WrappedSegment->Count);
180*9880d681SAndroid Build Coastguard Worker for (const auto *S : LineSegments)
181*9880d681SAndroid Build Coastguard Worker if (S->HasCount && S->IsRegionEntry)
182*9880d681SAndroid Build Coastguard Worker LineCount.addRegionStartCount(S->Count);
183*9880d681SAndroid Build Coastguard Worker
184*9880d681SAndroid Build Coastguard Worker renderLinePrefix(OS, ViewDepth);
185*9880d681SAndroid Build Coastguard Worker if (getOptions().ShowLineStats)
186*9880d681SAndroid Build Coastguard Worker renderLineCoverageColumn(OS, LineCount);
187*9880d681SAndroid Build Coastguard Worker if (getOptions().ShowLineNumbers)
188*9880d681SAndroid Build Coastguard Worker renderLineNumberColumn(OS, LI.line_number());
189*9880d681SAndroid Build Coastguard Worker
190*9880d681SAndroid Build Coastguard Worker // If there are expansion subviews, we want to highlight the first one.
191*9880d681SAndroid Build Coastguard Worker unsigned ExpansionColumn = 0;
192*9880d681SAndroid Build Coastguard Worker if (NextESV != EndESV && NextESV->getLine() == LI.line_number() &&
193*9880d681SAndroid Build Coastguard Worker getOptions().Colors)
194*9880d681SAndroid Build Coastguard Worker ExpansionColumn = NextESV->getStartCol();
195*9880d681SAndroid Build Coastguard Worker
196*9880d681SAndroid Build Coastguard Worker // Display the source code for the current line.
197*9880d681SAndroid Build Coastguard Worker renderLine(OS, {*LI, LI.line_number()}, WrappedSegment, LineSegments,
198*9880d681SAndroid Build Coastguard Worker ExpansionColumn, ViewDepth);
199*9880d681SAndroid Build Coastguard Worker
200*9880d681SAndroid Build Coastguard Worker // Show the region markers.
201*9880d681SAndroid Build Coastguard Worker if (shouldRenderRegionMarkers(LineCount.hasMultipleRegions()))
202*9880d681SAndroid Build Coastguard Worker renderRegionMarkers(OS, LineSegments, ViewDepth);
203*9880d681SAndroid Build Coastguard Worker
204*9880d681SAndroid Build Coastguard Worker // Show the expansions and instantiations for this line.
205*9880d681SAndroid Build Coastguard Worker bool RenderedSubView = false;
206*9880d681SAndroid Build Coastguard Worker for (; NextESV != EndESV && NextESV->getLine() == LI.line_number();
207*9880d681SAndroid Build Coastguard Worker ++NextESV) {
208*9880d681SAndroid Build Coastguard Worker renderViewDivider(OS, ViewDepth + 1);
209*9880d681SAndroid Build Coastguard Worker
210*9880d681SAndroid Build Coastguard Worker // Re-render the current line and highlight the expansion range for
211*9880d681SAndroid Build Coastguard Worker // this subview.
212*9880d681SAndroid Build Coastguard Worker if (RenderedSubView) {
213*9880d681SAndroid Build Coastguard Worker ExpansionColumn = NextESV->getStartCol();
214*9880d681SAndroid Build Coastguard Worker renderExpansionSite(OS, {*LI, LI.line_number()}, WrappedSegment,
215*9880d681SAndroid Build Coastguard Worker LineSegments, ExpansionColumn, ViewDepth);
216*9880d681SAndroid Build Coastguard Worker renderViewDivider(OS, ViewDepth + 1);
217*9880d681SAndroid Build Coastguard Worker }
218*9880d681SAndroid Build Coastguard Worker
219*9880d681SAndroid Build Coastguard Worker renderExpansionView(OS, *NextESV, ViewDepth + 1);
220*9880d681SAndroid Build Coastguard Worker RenderedSubView = true;
221*9880d681SAndroid Build Coastguard Worker }
222*9880d681SAndroid Build Coastguard Worker for (; NextISV != EndISV && NextISV->Line == LI.line_number(); ++NextISV) {
223*9880d681SAndroid Build Coastguard Worker renderViewDivider(OS, ViewDepth + 1);
224*9880d681SAndroid Build Coastguard Worker renderInstantiationView(OS, *NextISV, ViewDepth + 1);
225*9880d681SAndroid Build Coastguard Worker RenderedSubView = true;
226*9880d681SAndroid Build Coastguard Worker }
227*9880d681SAndroid Build Coastguard Worker if (RenderedSubView)
228*9880d681SAndroid Build Coastguard Worker renderViewDivider(OS, ViewDepth + 1);
229*9880d681SAndroid Build Coastguard Worker renderLineSuffix(OS, ViewDepth);
230*9880d681SAndroid Build Coastguard Worker }
231*9880d681SAndroid Build Coastguard Worker
232*9880d681SAndroid Build Coastguard Worker renderViewFooter(OS);
233*9880d681SAndroid Build Coastguard Worker }
234