xref: /llvm-project/llvm/tools/llvm-cov/SourceCoverageView.cpp (revision f9151b93721584b70139c3195cc0df8fd4f12975)
1 //===- SourceCoverageView.cpp - Code coverage view for source code --------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This class implements rendering for code coverage of source code.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "SourceCoverageView.h"
15 #include "SourceCoverageViewText.h"
16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/Support/LineIterator.h"
19 
20 using namespace llvm;
21 
22 std::string SourceCoverageView::formatCount(uint64_t N) {
23   std::string Number = utostr(N);
24   int Len = Number.size();
25   if (Len <= 3)
26     return Number;
27   int IntLen = Len % 3 == 0 ? 3 : Len % 3;
28   std::string Result(Number.data(), IntLen);
29   if (IntLen != 3) {
30     Result.push_back('.');
31     Result += Number.substr(IntLen, 3 - IntLen);
32   }
33   Result.push_back(" kMGTPEZY"[(Len - 1) / 3]);
34   return Result;
35 }
36 
37 void SourceCoverageView::addExpansion(
38     const coverage::CounterMappingRegion &Region,
39     std::unique_ptr<SourceCoverageView> View) {
40   ExpansionSubViews.emplace_back(Region, std::move(View));
41 }
42 
43 void SourceCoverageView::addInstantiation(
44     StringRef FunctionName, unsigned Line,
45     std::unique_ptr<SourceCoverageView> View) {
46   InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
47 }
48 
49 std::unique_ptr<SourceCoverageView>
50 SourceCoverageView::create(StringRef SourceName, const MemoryBuffer &File,
51                            const CoverageViewOptions &Options,
52                            coverage::CoverageData &&CoverageInfo) {
53   return llvm::make_unique<SourceCoverageViewText>(SourceName, File, Options,
54                                                    std::move(CoverageInfo));
55 }
56 
57 void SourceCoverageView::print(raw_ostream &OS, bool WholeFile,
58                                bool ShowSourceName, unsigned ViewDepth) {
59   if (ShowSourceName)
60     renderSourceName(OS);
61 
62   // We need the expansions and instantiations sorted so we can go through them
63   // while we iterate lines.
64   std::sort(ExpansionSubViews.begin(), ExpansionSubViews.end());
65   std::sort(InstantiationSubViews.begin(), InstantiationSubViews.end());
66   auto NextESV = ExpansionSubViews.begin();
67   auto EndESV = ExpansionSubViews.end();
68   auto NextISV = InstantiationSubViews.begin();
69   auto EndISV = InstantiationSubViews.end();
70 
71   // Get the coverage information for the file.
72   auto NextSegment = CoverageInfo.begin();
73   auto EndSegment = CoverageInfo.end();
74 
75   unsigned FirstLine = NextSegment != EndSegment ? NextSegment->Line : 0;
76   const coverage::CoverageSegment *WrappedSegment = nullptr;
77   SmallVector<const coverage::CoverageSegment *, 8> LineSegments;
78   for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof(); ++LI) {
79     // If we aren't rendering the whole file, we need to filter out the prologue
80     // and epilogue.
81     if (!WholeFile) {
82       if (NextSegment == EndSegment)
83         break;
84       else if (LI.line_number() < FirstLine)
85         continue;
86     }
87 
88     // Collect the coverage information relevant to this line.
89     if (LineSegments.size())
90       WrappedSegment = LineSegments.back();
91     LineSegments.clear();
92     while (NextSegment != EndSegment && NextSegment->Line == LI.line_number())
93       LineSegments.push_back(&*NextSegment++);
94 
95     // Calculate a count to be for the line as a whole.
96     LineCoverageStats LineCount;
97     if (WrappedSegment && WrappedSegment->HasCount)
98       LineCount.addRegionCount(WrappedSegment->Count);
99     for (const auto *S : LineSegments)
100       if (S->HasCount && S->IsRegionEntry)
101         LineCount.addRegionStartCount(S->Count);
102 
103     renderLinePrefix(OS, ViewDepth);
104     if (getOptions().ShowLineStats)
105       renderLineCoverageColumn(OS, LineCount);
106     if (getOptions().ShowLineNumbers)
107       renderLineNumberColumn(OS, LI.line_number());
108 
109     // If there are expansion subviews, we want to highlight the first one.
110     unsigned ExpansionColumn = 0;
111     if (NextESV != EndESV && NextESV->getLine() == LI.line_number() &&
112         getOptions().Colors)
113       ExpansionColumn = NextESV->getStartCol();
114 
115     // Display the source code for the current line.
116     renderLine(OS, {*LI, LI.line_number()}, WrappedSegment, LineSegments,
117                ExpansionColumn, ViewDepth);
118 
119     // Show the region markers.
120     if (getOptions().ShowRegionMarkers &&
121         (!getOptions().ShowLineStatsOrRegionMarkers ||
122          LineCount.hasMultipleRegions()) &&
123         !LineSegments.empty()) {
124       renderRegionMarkers(OS, LineSegments, ViewDepth);
125     }
126 
127     // Show the expansions and instantiations for this line.
128     bool RenderedSubView = false;
129     for (; NextESV != EndESV && NextESV->getLine() == LI.line_number();
130          ++NextESV) {
131       renderViewDivider(OS, ViewDepth + 1);
132       ExpansionColumn = renderExpansionView(
133           OS, *NextESV,
134           RenderedSubView ? Optional<LineRef>({*LI, LI.line_number()})
135                           : Optional<LineRef>(),
136           ExpansionColumn, WrappedSegment, LineSegments, ViewDepth);
137       RenderedSubView = true;
138     }
139     for (; NextISV != EndISV && NextISV->Line == LI.line_number(); ++NextISV) {
140       renderInstantiationView(OS, *NextISV, ViewDepth + 1);
141       RenderedSubView = true;
142     }
143     if (RenderedSubView)
144       renderViewDivider(OS, ViewDepth + 1);
145   }
146 }
147