77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
1 //===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===//
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
2 //
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
3 // The LLVM Compiler Infrastructure
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
4 //
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
5 // This file is distributed under the University of Illinois Open Source
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
6 // License. See LICENSE.TXT for details.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
7 //
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
8 //===----------------------------------------------------------------------===//
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
9 //
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
10 // The 'CodeCoverageTool' class implements a command line tool to analyze and
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
11 // report coverage information using the profiling instrumentation and code
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
12 // coverage mapping.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
13 //
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
14 //===----------------------------------------------------------------------===//
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
15
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
16 #include "CoverageFilters.h"
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
17 #include "CoverageReport.h"
|
121
|
18 #include "CoverageSummaryInfo.h"
|
83
|
19 #include "CoverageViewOptions.h"
|
120
|
20 #include "RenderingSupport.h"
|
83
|
21 #include "SourceCoverageView.h"
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
22 #include "llvm/ADT/SmallString.h"
|
83
|
23 #include "llvm/ADT/StringRef.h"
|
95
|
24 #include "llvm/ADT/Triple.h"
|
120
|
25 #include "llvm/ProfileData/Coverage/CoverageMapping.h"
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
26 #include "llvm/ProfileData/InstrProfReader.h"
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
27 #include "llvm/Support/CommandLine.h"
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
28 #include "llvm/Support/FileSystem.h"
|
83
|
29 #include "llvm/Support/Format.h"
|
120
|
30 #include "llvm/Support/MemoryBuffer.h"
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
31 #include "llvm/Support/Path.h"
|
95
|
32 #include "llvm/Support/Process.h"
|
120
|
33 #include "llvm/Support/Program.h"
|
|
34 #include "llvm/Support/ScopedPrinter.h"
|
121
|
35 #include "llvm/Support/Threading.h"
|
120
|
36 #include "llvm/Support/ThreadPool.h"
|
|
37 #include "llvm/Support/ToolOutputFile.h"
|
121
|
38
|
83
|
39 #include <functional>
|
121
|
40 #include <map>
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
41 #include <system_error>
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
42
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
43 using namespace llvm;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
44 using namespace coverage;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
45
|
120
|
46 void exportCoverageDataToJson(const coverage::CoverageMapping &CoverageMapping,
|
121
|
47 const CoverageViewOptions &Options,
|
120
|
48 raw_ostream &OS);
|
|
49
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
50 namespace {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
51 /// \brief The implementation of the coverage tool.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
52 class CodeCoverageTool {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
53 public:
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
54 enum Command {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
55 /// \brief The show command.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
56 Show,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
57 /// \brief The report command.
|
120
|
58 Report,
|
|
59 /// \brief The export command.
|
|
60 Export
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
61 };
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
62
|
120
|
63 int run(Command Cmd, int argc, const char **argv);
|
|
64
|
|
65 private:
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
66 /// \brief Print the error message to the error output stream.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
67 void error(const Twine &Message, StringRef Whence = "");
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
68
|
120
|
69 /// \brief Print the warning message to the error output stream.
|
|
70 void warning(const Twine &Message, StringRef Whence = "");
|
|
71
|
|
72 /// \brief Convert \p Path into an absolute path and append it to the list
|
|
73 /// of collected paths.
|
|
74 void addCollectedPath(const std::string &Path);
|
|
75
|
|
76 /// \brief If \p Path is a regular file, collect the path. If it's a
|
|
77 /// directory, recursively collect all of the paths within the directory.
|
|
78 void collectPaths(const std::string &Path);
|
|
79
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
80 /// \brief Return a memory buffer for the given source file.
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
81 ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
82
|
83
|
83 /// \brief Create source views for the expansions of the view.
|
|
84 void attachExpansionSubViews(SourceCoverageView &View,
|
|
85 ArrayRef<ExpansionRecord> Expansions,
|
120
|
86 const CoverageMapping &Coverage);
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
87
|
83
|
88 /// \brief Create the source view of a particular function.
|
|
89 std::unique_ptr<SourceCoverageView>
|
120
|
90 createFunctionView(const FunctionRecord &Function,
|
|
91 const CoverageMapping &Coverage);
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
92
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
93 /// \brief Create the main source view of a particular source file.
|
83
|
94 std::unique_ptr<SourceCoverageView>
|
120
|
95 createSourceFileView(StringRef SourceFile, const CoverageMapping &Coverage);
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
96
|
120
|
97 /// \brief Load the coverage mapping data. Return nullptr if an error occurred.
|
83
|
98 std::unique_ptr<CoverageMapping> load();
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
99
|
121
|
100 /// \brief Create a mapping from files in the Coverage data to local copies
|
|
101 /// (path-equivalence).
|
|
102 void remapPathNames(const CoverageMapping &Coverage);
|
|
103
|
120
|
104 /// \brief Remove input source files which aren't mapped by \p Coverage.
|
|
105 void removeUnmappedInputs(const CoverageMapping &Coverage);
|
|
106
|
|
107 /// \brief If a demangler is available, demangle all symbol names.
|
|
108 void demangleSymbols(const CoverageMapping &Coverage);
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
109
|
120
|
110 /// \brief Write out a source file view to the filesystem.
|
|
111 void writeSourceFileView(StringRef SourceFile, CoverageMapping *Coverage,
|
|
112 CoveragePrinter *Printer, bool ShowFilenames);
|
|
113
|
|
114 typedef llvm::function_ref<int(int, const char **)> CommandLineParserType;
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
115
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
116 int show(int argc, const char **argv,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
117 CommandLineParserType commandLineParser);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
118
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
119 int report(int argc, const char **argv,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
120 CommandLineParserType commandLineParser);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
121
|
120
|
122 int export_(int argc, const char **argv,
|
|
123 CommandLineParserType commandLineParser);
|
|
124
|
|
125 std::vector<StringRef> ObjectFilenames;
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
126 CoverageViewOptions ViewOpts;
|
120
|
127 CoverageFiltersMatchAll Filters;
|
|
128
|
|
129 /// The path to the indexed profile.
|
83
|
130 std::string PGOFilename;
|
120
|
131
|
|
132 /// A list of input source files.
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
133 std::vector<std::string> SourceFiles;
|
120
|
134
|
121
|
135 /// In -path-equivalence mode, this maps the absolute paths from the coverage
|
|
136 /// mapping data to the input source files.
|
120
|
137 StringMap<std::string> RemappedFilenames;
|
|
138
|
121
|
139 /// The coverage data path to be remapped from, and the source path to be
|
|
140 /// remapped to, when using -path-equivalence.
|
|
141 Optional<std::pair<std::string, std::string>> PathRemapping;
|
120
|
142
|
121
|
143 /// The architecture the coverage mapping data targets.
|
|
144 std::vector<StringRef> CoverageArches;
|
120
|
145
|
121
|
146 /// A cache for demangled symbols.
|
|
147 DemangleCache DC;
|
|
148
|
|
149 /// A lock which guards printing to stderr.
|
120
|
150 std::mutex ErrsLock;
|
|
151
|
|
152 /// A container for input source file buffers.
|
|
153 std::mutex LoadedSourceFilesLock;
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
154 std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
155 LoadedSourceFiles;
|
121
|
156
|
|
157 /// Whitelist from -name-whitelist to be used for filtering.
|
|
158 std::unique_ptr<SpecialCaseList> NameWhitelist;
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
159 };
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
160 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
161
|
120
|
162 static std::string getErrorString(const Twine &Message, StringRef Whence,
|
|
163 bool Warning) {
|
|
164 std::string Str = (Warning ? "warning" : "error");
|
|
165 Str += ": ";
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
166 if (!Whence.empty())
|
120
|
167 Str += Whence.str() + ": ";
|
|
168 Str += Message.str() + "\n";
|
|
169 return Str;
|
|
170 }
|
|
171
|
|
172 void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
|
|
173 std::unique_lock<std::mutex> Guard{ErrsLock};
|
|
174 ViewOpts.colored_ostream(errs(), raw_ostream::RED)
|
|
175 << getErrorString(Message, Whence, false);
|
|
176 }
|
|
177
|
|
178 void CodeCoverageTool::warning(const Twine &Message, StringRef Whence) {
|
|
179 std::unique_lock<std::mutex> Guard{ErrsLock};
|
|
180 ViewOpts.colored_ostream(errs(), raw_ostream::RED)
|
|
181 << getErrorString(Message, Whence, true);
|
|
182 }
|
|
183
|
|
184 void CodeCoverageTool::addCollectedPath(const std::string &Path) {
|
121
|
185 SmallString<128> EffectivePath(Path);
|
|
186 if (std::error_code EC = sys::fs::make_absolute(EffectivePath)) {
|
|
187 error(EC.message(), Path);
|
|
188 return;
|
120
|
189 }
|
121
|
190 sys::path::remove_dots(EffectivePath, /*remove_dot_dots=*/true);
|
|
191 SourceFiles.emplace_back(EffectivePath.str());
|
120
|
192 }
|
|
193
|
|
194 void CodeCoverageTool::collectPaths(const std::string &Path) {
|
|
195 llvm::sys::fs::file_status Status;
|
|
196 llvm::sys::fs::status(Path, Status);
|
|
197 if (!llvm::sys::fs::exists(Status)) {
|
121
|
198 if (PathRemapping)
|
120
|
199 addCollectedPath(Path);
|
|
200 else
|
|
201 error("Missing source file", Path);
|
|
202 return;
|
|
203 }
|
|
204
|
|
205 if (llvm::sys::fs::is_regular_file(Status)) {
|
|
206 addCollectedPath(Path);
|
|
207 return;
|
|
208 }
|
|
209
|
|
210 if (llvm::sys::fs::is_directory(Status)) {
|
|
211 std::error_code EC;
|
|
212 for (llvm::sys::fs::recursive_directory_iterator F(Path, EC), E;
|
|
213 F != E && !EC; F.increment(EC)) {
|
|
214 if (llvm::sys::fs::is_regular_file(F->path()))
|
|
215 addCollectedPath(F->path());
|
|
216 }
|
|
217 if (EC)
|
|
218 warning(EC.message(), Path);
|
|
219 }
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
220 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
221
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
222 ErrorOr<const MemoryBuffer &>
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
223 CodeCoverageTool::getSourceFile(StringRef SourceFile) {
|
83
|
224 // If we've remapped filenames, look up the real location for this file.
|
120
|
225 std::unique_lock<std::mutex> Guard{LoadedSourceFilesLock};
|
83
|
226 if (!RemappedFilenames.empty()) {
|
|
227 auto Loc = RemappedFilenames.find(SourceFile);
|
|
228 if (Loc != RemappedFilenames.end())
|
|
229 SourceFile = Loc->second;
|
|
230 }
|
|
231 for (const auto &Files : LoadedSourceFiles)
|
|
232 if (sys::fs::equivalent(SourceFile, Files.first))
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
233 return *Files.second;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
234 auto Buffer = MemoryBuffer::getFile(SourceFile);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
235 if (auto EC = Buffer.getError()) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
236 error(EC.message(), SourceFile);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
237 return EC;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
238 }
|
95
|
239 LoadedSourceFiles.emplace_back(SourceFile, std::move(Buffer.get()));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
240 return *LoadedSourceFiles.back().second;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
241 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
242
|
120
|
243 void CodeCoverageTool::attachExpansionSubViews(
|
|
244 SourceCoverageView &View, ArrayRef<ExpansionRecord> Expansions,
|
|
245 const CoverageMapping &Coverage) {
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
246 if (!ViewOpts.ShowExpandedRegions)
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
247 return;
|
83
|
248 for (const auto &Expansion : Expansions) {
|
|
249 auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
|
|
250 if (ExpansionCoverage.empty())
|
|
251 continue;
|
|
252 auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
|
|
253 if (!SourceBuffer)
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
254 continue;
|
83
|
255
|
|
256 auto SubViewExpansions = ExpansionCoverage.getExpansions();
|
120
|
257 auto SubView =
|
|
258 SourceCoverageView::create(Expansion.Function.Name, SourceBuffer.get(),
|
|
259 ViewOpts, std::move(ExpansionCoverage));
|
83
|
260 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
|
|
261 View.addExpansion(Expansion.Region, std::move(SubView));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
262 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
263 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
264
|
83
|
265 std::unique_ptr<SourceCoverageView>
|
|
266 CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
|
120
|
267 const CoverageMapping &Coverage) {
|
83
|
268 auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
|
|
269 if (FunctionCoverage.empty())
|
|
270 return nullptr;
|
|
271 auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
|
|
272 if (!SourceBuffer)
|
|
273 return nullptr;
|
|
274
|
|
275 auto Expansions = FunctionCoverage.getExpansions();
|
121
|
276 auto View = SourceCoverageView::create(DC.demangle(Function.Name),
|
120
|
277 SourceBuffer.get(), ViewOpts,
|
|
278 std::move(FunctionCoverage));
|
83
|
279 attachExpansionSubViews(*View, Expansions, Coverage);
|
|
280
|
|
281 return View;
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
282 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
283
|
83
|
284 std::unique_ptr<SourceCoverageView>
|
|
285 CodeCoverageTool::createSourceFileView(StringRef SourceFile,
|
120
|
286 const CoverageMapping &Coverage) {
|
83
|
287 auto SourceBuffer = getSourceFile(SourceFile);
|
|
288 if (!SourceBuffer)
|
|
289 return nullptr;
|
|
290 auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
|
|
291 if (FileCoverage.empty())
|
|
292 return nullptr;
|
|
293
|
|
294 auto Expansions = FileCoverage.getExpansions();
|
120
|
295 auto View = SourceCoverageView::create(SourceFile, SourceBuffer.get(),
|
|
296 ViewOpts, std::move(FileCoverage));
|
83
|
297 attachExpansionSubViews(*View, Expansions, Coverage);
|
121
|
298 if (!ViewOpts.ShowFunctionInstantiations)
|
|
299 return View;
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
300
|
121
|
301 for (const auto &Group : Coverage.getInstantiationGroups(SourceFile)) {
|
|
302 // Skip functions which have a single instantiation.
|
|
303 if (Group.size() < 2)
|
|
304 continue;
|
120
|
305
|
121
|
306 for (const FunctionRecord *Function : Group.getInstantiations()) {
|
|
307 std::unique_ptr<SourceCoverageView> SubView{nullptr};
|
|
308
|
|
309 StringRef Funcname = DC.demangle(Function->Name);
|
83
|
310
|
121
|
311 if (Function->ExecutionCount > 0) {
|
|
312 auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
|
|
313 auto SubViewExpansions = SubViewCoverage.getExpansions();
|
|
314 SubView = SourceCoverageView::create(
|
|
315 Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
|
|
316 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
|
|
317 }
|
|
318
|
|
319 unsigned FileID = Function->CountedRegions.front().FileID;
|
|
320 unsigned Line = 0;
|
|
321 for (const auto &CR : Function->CountedRegions)
|
|
322 if (CR.FileID == FileID)
|
|
323 Line = std::max(CR.LineEnd, Line);
|
|
324 View->addInstantiation(Funcname, Line, std::move(SubView));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
325 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
326 }
|
83
|
327 return View;
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
328 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
329
|
95
|
330 static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
|
|
331 sys::fs::file_status Status;
|
|
332 if (sys::fs::status(LHS, Status))
|
|
333 return false;
|
|
334 auto LHSTime = Status.getLastModificationTime();
|
|
335 if (sys::fs::status(RHS, Status))
|
|
336 return false;
|
|
337 auto RHSTime = Status.getLastModificationTime();
|
|
338 return LHSTime > RHSTime;
|
|
339 }
|
|
340
|
83
|
341 std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
|
120
|
342 for (StringRef ObjectFilename : ObjectFilenames)
|
|
343 if (modifiedTimeGT(ObjectFilename, PGOFilename))
|
|
344 warning("profile data may be out of date - object is newer",
|
|
345 ObjectFilename);
|
|
346 auto CoverageOrErr =
|
121
|
347 CoverageMapping::load(ObjectFilenames, PGOFilename, CoverageArches);
|
120
|
348 if (Error E = CoverageOrErr.takeError()) {
|
|
349 error("Failed to load coverage: " + toString(std::move(E)),
|
|
350 join(ObjectFilenames.begin(), ObjectFilenames.end(), ", "));
|
83
|
351 return nullptr;
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
352 }
|
83
|
353 auto Coverage = std::move(CoverageOrErr.get());
|
|
354 unsigned Mismatched = Coverage->getMismatchedCount();
|
121
|
355 if (Mismatched) {
|
120
|
356 warning(utostr(Mismatched) + " functions have mismatched data");
|
|
357
|
121
|
358 if (ViewOpts.Debug) {
|
|
359 for (const auto &HashMismatch : Coverage->getHashMismatches())
|
|
360 errs() << "hash-mismatch: "
|
|
361 << "No profile record found for '" << HashMismatch.first << "'"
|
|
362 << " with hash = 0x" << utohexstr(HashMismatch.second) << "\n";
|
|
363
|
|
364 for (const auto &CounterMismatch : Coverage->getCounterMismatches())
|
|
365 errs() << "counter-mismatch: "
|
|
366 << "Coverage mapping for " << CounterMismatch.first
|
|
367 << " only has " << CounterMismatch.second
|
|
368 << " valid counter expressions\n";
|
|
369 }
|
|
370 }
|
|
371
|
|
372 remapPathNames(*Coverage);
|
|
373
|
120
|
374 if (!SourceFiles.empty())
|
|
375 removeUnmappedInputs(*Coverage);
|
|
376
|
|
377 demangleSymbols(*Coverage);
|
|
378
|
|
379 return Coverage;
|
|
380 }
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
381
|
121
|
382 void CodeCoverageTool::remapPathNames(const CoverageMapping &Coverage) {
|
|
383 if (!PathRemapping)
|
|
384 return;
|
|
385
|
|
386 // Convert remapping paths to native paths with trailing seperators.
|
|
387 auto nativeWithTrailing = [](StringRef Path) -> std::string {
|
|
388 if (Path.empty())
|
|
389 return "";
|
|
390 SmallString<128> NativePath;
|
|
391 sys::path::native(Path, NativePath);
|
|
392 if (!sys::path::is_separator(NativePath.back()))
|
|
393 NativePath += sys::path::get_separator();
|
|
394 return NativePath.c_str();
|
|
395 };
|
|
396 std::string RemapFrom = nativeWithTrailing(PathRemapping->first);
|
|
397 std::string RemapTo = nativeWithTrailing(PathRemapping->second);
|
|
398
|
|
399 // Create a mapping from coverage data file paths to local paths.
|
|
400 for (StringRef Filename : Coverage.getUniqueSourceFiles()) {
|
|
401 SmallString<128> NativeFilename;
|
|
402 sys::path::native(Filename, NativeFilename);
|
|
403 if (NativeFilename.startswith(RemapFrom)) {
|
|
404 RemappedFilenames[Filename] =
|
|
405 RemapTo + NativeFilename.substr(RemapFrom.size()).str();
|
|
406 }
|
|
407 }
|
|
408
|
|
409 // Convert input files from local paths to coverage data file paths.
|
|
410 StringMap<std::string> InvRemappedFilenames;
|
|
411 for (const auto &RemappedFilename : RemappedFilenames)
|
|
412 InvRemappedFilenames[RemappedFilename.getValue()] = RemappedFilename.getKey();
|
|
413
|
|
414 for (std::string &Filename : SourceFiles) {
|
|
415 SmallString<128> NativeFilename;
|
|
416 sys::path::native(Filename, NativeFilename);
|
|
417 auto CovFileName = InvRemappedFilenames.find(NativeFilename);
|
|
418 if (CovFileName != InvRemappedFilenames.end())
|
|
419 Filename = CovFileName->second;
|
|
420 }
|
|
421 }
|
|
422
|
120
|
423 void CodeCoverageTool::removeUnmappedInputs(const CoverageMapping &Coverage) {
|
|
424 std::vector<StringRef> CoveredFiles = Coverage.getUniqueSourceFiles();
|
|
425
|
|
426 auto UncoveredFilesIt = SourceFiles.end();
|
121
|
427 // The user may have specified source files which aren't in the coverage
|
|
428 // mapping. Filter these files away.
|
|
429 UncoveredFilesIt = std::remove_if(
|
|
430 SourceFiles.begin(), SourceFiles.end(), [&](const std::string &SF) {
|
|
431 return !std::binary_search(CoveredFiles.begin(), CoveredFiles.end(),
|
|
432 SF);
|
|
433 });
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
434
|
120
|
435 SourceFiles.erase(UncoveredFilesIt, SourceFiles.end());
|
|
436 }
|
|
437
|
|
438 void CodeCoverageTool::demangleSymbols(const CoverageMapping &Coverage) {
|
|
439 if (!ViewOpts.hasDemangler())
|
|
440 return;
|
|
441
|
|
442 // Pass function names to the demangler in a temporary file.
|
|
443 int InputFD;
|
|
444 SmallString<256> InputPath;
|
|
445 std::error_code EC =
|
|
446 sys::fs::createTemporaryFile("demangle-in", "list", InputFD, InputPath);
|
|
447 if (EC) {
|
|
448 error(InputPath, EC.message());
|
|
449 return;
|
|
450 }
|
121
|
451 ToolOutputFile InputTOF{InputPath, InputFD};
|
120
|
452
|
|
453 unsigned NumSymbols = 0;
|
|
454 for (const auto &Function : Coverage.getCoveredFunctions()) {
|
|
455 InputTOF.os() << Function.Name << '\n';
|
|
456 ++NumSymbols;
|
|
457 }
|
|
458 InputTOF.os().close();
|
|
459
|
|
460 // Use another temporary file to store the demangler's output.
|
|
461 int OutputFD;
|
|
462 SmallString<256> OutputPath;
|
|
463 EC = sys::fs::createTemporaryFile("demangle-out", "list", OutputFD,
|
|
464 OutputPath);
|
|
465 if (EC) {
|
|
466 error(OutputPath, EC.message());
|
|
467 return;
|
|
468 }
|
121
|
469 ToolOutputFile OutputTOF{OutputPath, OutputFD};
|
120
|
470 OutputTOF.os().close();
|
|
471
|
|
472 // Invoke the demangler.
|
|
473 std::vector<const char *> ArgsV;
|
|
474 for (const std::string &Arg : ViewOpts.DemanglerOpts)
|
|
475 ArgsV.push_back(Arg.c_str());
|
|
476 ArgsV.push_back(nullptr);
|
121
|
477 Optional<StringRef> Redirects[] = {InputPath.str(), OutputPath.str(), {""}};
|
120
|
478 std::string ErrMsg;
|
|
479 int RC = sys::ExecuteAndWait(ViewOpts.DemanglerOpts[0], ArgsV.data(),
|
|
480 /*env=*/nullptr, Redirects, /*secondsToWait=*/0,
|
|
481 /*memoryLimit=*/0, &ErrMsg);
|
|
482 if (RC) {
|
|
483 error(ErrMsg, ViewOpts.DemanglerOpts[0]);
|
|
484 return;
|
|
485 }
|
|
486
|
|
487 // Parse the demangler's output.
|
|
488 auto BufOrError = MemoryBuffer::getFile(OutputPath);
|
|
489 if (!BufOrError) {
|
|
490 error(OutputPath, BufOrError.getError().message());
|
|
491 return;
|
|
492 }
|
|
493
|
|
494 std::unique_ptr<MemoryBuffer> DemanglerBuf = std::move(*BufOrError);
|
|
495
|
|
496 SmallVector<StringRef, 8> Symbols;
|
|
497 StringRef DemanglerData = DemanglerBuf->getBuffer();
|
|
498 DemanglerData.split(Symbols, '\n', /*MaxSplit=*/NumSymbols,
|
|
499 /*KeepEmpty=*/false);
|
|
500 if (Symbols.size() != NumSymbols) {
|
|
501 error("Demangler did not provide expected number of symbols");
|
|
502 return;
|
|
503 }
|
|
504
|
|
505 // Cache the demangled names.
|
|
506 unsigned I = 0;
|
|
507 for (const auto &Function : Coverage.getCoveredFunctions())
|
121
|
508 // On Windows, lines in the demangler's output file end with "\r\n".
|
|
509 // Splitting by '\n' keeps '\r's, so cut them now.
|
|
510 DC.DemangledNames[Function.Name] = Symbols[I++].rtrim();
|
120
|
511 }
|
|
512
|
|
513 void CodeCoverageTool::writeSourceFileView(StringRef SourceFile,
|
|
514 CoverageMapping *Coverage,
|
|
515 CoveragePrinter *Printer,
|
|
516 bool ShowFilenames) {
|
|
517 auto View = createSourceFileView(SourceFile, *Coverage);
|
|
518 if (!View) {
|
|
519 warning("The file '" + SourceFile + "' isn't covered.");
|
|
520 return;
|
|
521 }
|
|
522
|
|
523 auto OSOrErr = Printer->createViewFile(SourceFile, /*InToplevel=*/false);
|
|
524 if (Error E = OSOrErr.takeError()) {
|
|
525 error("Could not create view file!", toString(std::move(E)));
|
|
526 return;
|
|
527 }
|
|
528 auto OS = std::move(OSOrErr.get());
|
|
529
|
|
530 View->print(*OS.get(), /*Wholefile=*/true,
|
121
|
531 /*ShowSourceName=*/ShowFilenames,
|
|
532 /*ShowTitle=*/ViewOpts.hasOutputDirectory());
|
120
|
533 Printer->closeViewFile(std::move(OS));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
534 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
535
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
536 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
|
120
|
537 cl::opt<std::string> CovFilename(
|
|
538 cl::Positional, cl::desc("Covered executable or object file."));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
539
|
120
|
540 cl::list<std::string> CovFilenames(
|
|
541 "object", cl::desc("Coverage executable or object file"), cl::ZeroOrMore,
|
|
542 cl::CommaSeparated);
|
83
|
543
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
544 cl::list<std::string> InputSourceFiles(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
545 cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
546
|
120
|
547 cl::opt<bool> DebugDumpCollectedPaths(
|
|
548 "dump-collected-paths", cl::Optional, cl::Hidden,
|
|
549 cl::desc("Show the collected paths to source files"));
|
|
550
|
83
|
551 cl::opt<std::string, true> PGOFilename(
|
|
552 "instr-profile", cl::Required, cl::location(this->PGOFilename),
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
553 cl::desc(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
554 "File with the profile data obtained after an instrumented run"));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
555
|
121
|
556 cl::list<std::string> Arches(
|
|
557 "arch", cl::desc("architectures of the coverage mapping binaries"));
|
95
|
558
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
559 cl::opt<bool> DebugDump("dump", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
560 cl::desc("Show internal debug dump"));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
561
|
120
|
562 cl::opt<CoverageViewOptions::OutputFormat> Format(
|
|
563 "format", cl::desc("Output format for line-based coverage reports"),
|
|
564 cl::values(clEnumValN(CoverageViewOptions::OutputFormat::Text, "text",
|
|
565 "Text output"),
|
|
566 clEnumValN(CoverageViewOptions::OutputFormat::HTML, "html",
|
|
567 "HTML output")),
|
|
568 cl::init(CoverageViewOptions::OutputFormat::Text));
|
|
569
|
121
|
570 cl::opt<std::string> PathRemap(
|
|
571 "path-equivalence", cl::Optional,
|
|
572 cl::desc("<from>,<to> Map coverage data paths to local source file "
|
|
573 "paths"));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
574
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
575 cl::OptionCategory FilteringCategory("Function filtering options");
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
576
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
577 cl::list<std::string> NameFilters(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
578 "name", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
579 cl::desc("Show code coverage only for functions with the given name"),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
580 cl::ZeroOrMore, cl::cat(FilteringCategory));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
581
|
121
|
582 cl::list<std::string> NameFilterFiles(
|
|
583 "name-whitelist", cl::Optional,
|
|
584 cl::desc("Show code coverage only for functions listed in the given "
|
|
585 "file"),
|
|
586 cl::ZeroOrMore, cl::cat(FilteringCategory));
|
|
587
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
588 cl::list<std::string> NameRegexFilters(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
589 "name-regex", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
590 cl::desc("Show code coverage only for functions that match the given "
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
591 "regular expression"),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
592 cl::ZeroOrMore, cl::cat(FilteringCategory));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
593
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
594 cl::opt<double> RegionCoverageLtFilter(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
595 "region-coverage-lt", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
596 cl::desc("Show code coverage only for functions with region coverage "
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
597 "less than the given threshold"),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
598 cl::cat(FilteringCategory));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
599
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
600 cl::opt<double> RegionCoverageGtFilter(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
601 "region-coverage-gt", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
602 cl::desc("Show code coverage only for functions with region coverage "
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
603 "greater than the given threshold"),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
604 cl::cat(FilteringCategory));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
605
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
606 cl::opt<double> LineCoverageLtFilter(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
607 "line-coverage-lt", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
608 cl::desc("Show code coverage only for functions with line coverage less "
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
609 "than the given threshold"),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
610 cl::cat(FilteringCategory));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
611
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
612 cl::opt<double> LineCoverageGtFilter(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
613 "line-coverage-gt", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
614 cl::desc("Show code coverage only for functions with line coverage "
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
615 "greater than the given threshold"),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
616 cl::cat(FilteringCategory));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
617
|
95
|
618 cl::opt<cl::boolOrDefault> UseColor(
|
|
619 "use-color", cl::desc("Emit colored output (default=autodetect)"),
|
|
620 cl::init(cl::BOU_UNSET));
|
|
621
|
120
|
622 cl::list<std::string> DemanglerOpts(
|
|
623 "Xdemangler", cl::desc("<demangler-path>|<demangler-option>"));
|
|
624
|
121
|
625 cl::opt<bool> RegionSummary(
|
|
626 "show-region-summary", cl::Optional,
|
|
627 cl::desc("Show region statistics in summary table"),
|
|
628 cl::init(true));
|
|
629
|
|
630 cl::opt<bool> InstantiationSummary(
|
|
631 "show-instantiation-summary", cl::Optional,
|
|
632 cl::desc("Show instantiation statistics in summary table"));
|
|
633
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
634 auto commandLineParser = [&, this](int argc, const char **argv) -> int {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
635 cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
636 ViewOpts.Debug = DebugDump;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
637
|
120
|
638 if (!CovFilename.empty())
|
|
639 ObjectFilenames.emplace_back(CovFilename);
|
|
640 for (const std::string &Filename : CovFilenames)
|
|
641 ObjectFilenames.emplace_back(Filename);
|
|
642 if (ObjectFilenames.empty()) {
|
|
643 errs() << "No filenames specified!\n";
|
|
644 ::exit(1);
|
|
645 }
|
|
646
|
|
647 ViewOpts.Format = Format;
|
|
648 switch (ViewOpts.Format) {
|
|
649 case CoverageViewOptions::OutputFormat::Text:
|
|
650 ViewOpts.Colors = UseColor == cl::BOU_UNSET
|
|
651 ? sys::Process::StandardOutHasColors()
|
|
652 : UseColor == cl::BOU_TRUE;
|
|
653 break;
|
|
654 case CoverageViewOptions::OutputFormat::HTML:
|
|
655 if (UseColor == cl::BOU_FALSE)
|
|
656 errs() << "Color output cannot be disabled when generating html.\n";
|
|
657 ViewOpts.Colors = true;
|
|
658 break;
|
|
659 }
|
|
660
|
121
|
661 // If path-equivalence was given and is a comma seperated pair then set
|
|
662 // PathRemapping.
|
|
663 auto EquivPair = StringRef(PathRemap).split(',');
|
|
664 if (!(EquivPair.first.empty() && EquivPair.second.empty()))
|
|
665 PathRemapping = EquivPair;
|
|
666
|
120
|
667 // If a demangler is supplied, check if it exists and register it.
|
|
668 if (DemanglerOpts.size()) {
|
|
669 auto DemanglerPathOrErr = sys::findProgramByName(DemanglerOpts[0]);
|
|
670 if (!DemanglerPathOrErr) {
|
|
671 error("Could not find the demangler!",
|
|
672 DemanglerPathOrErr.getError().message());
|
|
673 return 1;
|
|
674 }
|
|
675 DemanglerOpts[0] = *DemanglerPathOrErr;
|
|
676 ViewOpts.DemanglerOpts.swap(DemanglerOpts);
|
|
677 }
|
95
|
678
|
121
|
679 // Read in -name-whitelist files.
|
|
680 if (!NameFilterFiles.empty()) {
|
|
681 std::string SpecialCaseListErr;
|
|
682 NameWhitelist =
|
|
683 SpecialCaseList::create(NameFilterFiles, SpecialCaseListErr);
|
|
684 if (!NameWhitelist)
|
|
685 error(SpecialCaseListErr);
|
|
686 }
|
|
687
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
688 // Create the function filters
|
121
|
689 if (!NameFilters.empty() || NameWhitelist || !NameRegexFilters.empty()) {
|
|
690 auto NameFilterer = llvm::make_unique<CoverageFilters>();
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
691 for (const auto &Name : NameFilters)
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
692 NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
|
121
|
693 if (NameWhitelist)
|
|
694 NameFilterer->push_back(
|
|
695 llvm::make_unique<NameWhitelistCoverageFilter>(*NameWhitelist));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
696 for (const auto &Regex : NameRegexFilters)
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
697 NameFilterer->push_back(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
698 llvm::make_unique<NameRegexCoverageFilter>(Regex));
|
121
|
699 Filters.push_back(std::move(NameFilterer));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
700 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
701 if (RegionCoverageLtFilter.getNumOccurrences() ||
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
702 RegionCoverageGtFilter.getNumOccurrences() ||
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
703 LineCoverageLtFilter.getNumOccurrences() ||
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
704 LineCoverageGtFilter.getNumOccurrences()) {
|
121
|
705 auto StatFilterer = llvm::make_unique<CoverageFilters>();
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
706 if (RegionCoverageLtFilter.getNumOccurrences())
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
707 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
708 RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
709 if (RegionCoverageGtFilter.getNumOccurrences())
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
710 StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
711 RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
712 if (LineCoverageLtFilter.getNumOccurrences())
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
713 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
714 LineCoverageFilter::LessThan, LineCoverageLtFilter));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
715 if (LineCoverageGtFilter.getNumOccurrences())
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
716 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
717 RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
|
121
|
718 Filters.push_back(std::move(StatFilterer));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
719 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
720
|
121
|
721 if (!Arches.empty()) {
|
|
722 for (const std::string &Arch : Arches) {
|
|
723 if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
|
|
724 error("Unknown architecture: " + Arch);
|
|
725 return 1;
|
|
726 }
|
|
727 CoverageArches.emplace_back(Arch);
|
|
728 }
|
|
729 if (CoverageArches.size() != ObjectFilenames.size()) {
|
|
730 error("Number of architectures doesn't match the number of objects");
|
|
731 return 1;
|
|
732 }
|
95
|
733 }
|
|
734
|
120
|
735 for (const std::string &File : InputSourceFiles)
|
|
736 collectPaths(File);
|
|
737
|
|
738 if (DebugDumpCollectedPaths) {
|
|
739 for (const std::string &SF : SourceFiles)
|
|
740 outs() << SF << '\n';
|
|
741 ::exit(0);
|
83
|
742 }
|
120
|
743
|
121
|
744 ViewOpts.ShowRegionSummary = RegionSummary;
|
|
745 ViewOpts.ShowInstantiationSummary = InstantiationSummary;
|
|
746
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
747 return 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
748 };
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
749
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
750 switch (Cmd) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
751 case Show:
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
752 return show(argc, argv, commandLineParser);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
753 case Report:
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
754 return report(argc, argv, commandLineParser);
|
120
|
755 case Export:
|
|
756 return export_(argc, argv, commandLineParser);
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
757 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
758 return 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
759 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
760
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
761 int CodeCoverageTool::show(int argc, const char **argv,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
762 CommandLineParserType commandLineParser) {
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
763
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
764 cl::OptionCategory ViewCategory("Viewing options");
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
765
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
766 cl::opt<bool> ShowLineExecutionCounts(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
767 "show-line-counts", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
768 cl::desc("Show the execution counts for each line"), cl::init(true),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
769 cl::cat(ViewCategory));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
770
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
771 cl::opt<bool> ShowRegions(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
772 "show-regions", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
773 cl::desc("Show the execution counts for each region"),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
774 cl::cat(ViewCategory));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
775
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
776 cl::opt<bool> ShowBestLineRegionsCounts(
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
777 "show-line-counts-or-regions", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
778 cl::desc("Show the execution counts for each line, or the execution "
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
779 "counts for each region on lines that have multiple regions"),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
780 cl::cat(ViewCategory));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
781
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
782 cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
783 cl::desc("Show expanded source regions"),
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
784 cl::cat(ViewCategory));
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
785
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
786 cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
787 cl::desc("Show function instantiations"),
|
121
|
788 cl::init(true), cl::cat(ViewCategory));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
789
|
120
|
790 cl::opt<std::string> ShowOutputDirectory(
|
|
791 "output-dir", cl::init(""),
|
|
792 cl::desc("Directory in which coverage information is written out"));
|
|
793 cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
|
|
794 cl::aliasopt(ShowOutputDirectory));
|
|
795
|
|
796 cl::opt<uint32_t> TabSize(
|
|
797 "tab-size", cl::init(2),
|
|
798 cl::desc(
|
|
799 "Set tab expansion size for html coverage reports (default = 2)"));
|
|
800
|
|
801 cl::opt<std::string> ProjectTitle(
|
|
802 "project-title", cl::Optional,
|
|
803 cl::desc("Set project title for the coverage report"));
|
|
804
|
121
|
805 cl::opt<unsigned> NumThreads(
|
|
806 "num-threads", cl::init(0),
|
|
807 cl::desc("Number of merge threads to use (default: autodetect)"));
|
|
808 cl::alias NumThreadsA("j", cl::desc("Alias for --num-threads"),
|
|
809 cl::aliasopt(NumThreads));
|
|
810
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
811 auto Err = commandLineParser(argc, argv);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
812 if (Err)
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
813 return Err;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
814
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
815 ViewOpts.ShowLineNumbers = true;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
816 ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
817 !ShowRegions || ShowBestLineRegionsCounts;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
818 ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
819 ViewOpts.ShowExpandedRegions = ShowExpansions;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
820 ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
|
120
|
821 ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
|
|
822 ViewOpts.TabSize = TabSize;
|
|
823 ViewOpts.ProjectTitle = ProjectTitle;
|
|
824
|
|
825 if (ViewOpts.hasOutputDirectory()) {
|
|
826 if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
|
|
827 error("Could not create output directory!", E.message());
|
|
828 return 1;
|
|
829 }
|
|
830 }
|
|
831
|
|
832 sys::fs::file_status Status;
|
|
833 if (sys::fs::status(PGOFilename, Status)) {
|
|
834 error("profdata file error: can not get the file status. \n");
|
|
835 return 1;
|
|
836 }
|
|
837
|
|
838 auto ModifiedTime = Status.getLastModificationTime();
|
|
839 std::string ModifiedTimeStr = to_string(ModifiedTime);
|
121
|
840 size_t found = ModifiedTimeStr.rfind(':');
|
120
|
841 ViewOpts.CreatedTimeStr = (found != std::string::npos)
|
|
842 ? "Created: " + ModifiedTimeStr.substr(0, found)
|
|
843 : "Created: " + ModifiedTimeStr;
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
844
|
83
|
845 auto Coverage = load();
|
|
846 if (!Coverage)
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
847 return 1;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
848
|
120
|
849 auto Printer = CoveragePrinter::create(ViewOpts);
|
|
850
|
121
|
851 if (SourceFiles.empty())
|
|
852 // Get the source files from the function coverage mapping.
|
|
853 for (StringRef Filename : Coverage->getUniqueSourceFiles())
|
|
854 SourceFiles.push_back(Filename);
|
|
855
|
|
856 // Create an index out of the source files.
|
|
857 if (ViewOpts.hasOutputDirectory()) {
|
|
858 if (Error E = Printer->createIndexFile(SourceFiles, *Coverage, Filters)) {
|
|
859 error("Could not create index file!", toString(std::move(E)));
|
120
|
860 return 1;
|
|
861 }
|
121
|
862 }
|
|
863
|
|
864 if (!Filters.empty()) {
|
|
865 // Build the map of filenames to functions.
|
|
866 std::map<llvm::StringRef, std::vector<const FunctionRecord *>>
|
|
867 FilenameFunctionMap;
|
|
868 for (const auto &SourceFile : SourceFiles)
|
|
869 for (const auto &Function : Coverage->getCoveredFunctions(SourceFile))
|
|
870 if (Filters.matches(*Coverage.get(), Function))
|
|
871 FilenameFunctionMap[SourceFile].push_back(&Function);
|
|
872
|
|
873 // Only print filter matching functions for each file.
|
|
874 for (const auto &FileFunc : FilenameFunctionMap) {
|
|
875 StringRef File = FileFunc.first;
|
|
876 const auto &Functions = FileFunc.second;
|
120
|
877
|
121
|
878 auto OSOrErr = Printer->createViewFile(File, /*InToplevel=*/false);
|
|
879 if (Error E = OSOrErr.takeError()) {
|
|
880 error("Could not create view file!", toString(std::move(E)));
|
|
881 return 1;
|
|
882 }
|
|
883 auto OS = std::move(OSOrErr.get());
|
83
|
884
|
121
|
885 bool ShowTitle = ViewOpts.hasOutputDirectory();
|
|
886 for (const auto *Function : Functions) {
|
|
887 auto FunctionView = createFunctionView(*Function, *Coverage);
|
|
888 if (!FunctionView) {
|
|
889 warning("Could not read coverage for '" + Function->Name + "'.");
|
|
890 continue;
|
|
891 }
|
|
892 FunctionView->print(*OS.get(), /*WholeFile=*/false,
|
|
893 /*ShowSourceName=*/true, ShowTitle);
|
|
894 ShowTitle = false;
|
83
|
895 }
|
120
|
896
|
121
|
897 Printer->closeViewFile(std::move(OS));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
898 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
899 return 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
900 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
901
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
902 // Show files
|
120
|
903 bool ShowFilenames =
|
|
904 (SourceFiles.size() != 1) || ViewOpts.hasOutputDirectory() ||
|
|
905 (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML);
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
906
|
121
|
907 // If NumThreads is not specified, auto-detect a good default.
|
|
908 if (NumThreads == 0)
|
|
909 NumThreads =
|
|
910 std::max(1U, std::min(llvm::heavyweight_hardware_concurrency(),
|
|
911 unsigned(SourceFiles.size())));
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
912
|
121
|
913 if (!ViewOpts.hasOutputDirectory() || NumThreads == 1) {
|
120
|
914 for (const std::string &SourceFile : SourceFiles)
|
|
915 writeSourceFileView(SourceFile, Coverage.get(), Printer.get(),
|
|
916 ShowFilenames);
|
|
917 } else {
|
|
918 // In -output-dir mode, it's safe to use multiple threads to print files.
|
121
|
919 ThreadPool Pool(NumThreads);
|
120
|
920 for (const std::string &SourceFile : SourceFiles)
|
|
921 Pool.async(&CodeCoverageTool::writeSourceFileView, this, SourceFile,
|
|
922 Coverage.get(), Printer.get(), ShowFilenames);
|
|
923 Pool.wait();
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
924 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
925
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
926 return 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
927 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
928
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
929 int CodeCoverageTool::report(int argc, const char **argv,
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
930 CommandLineParserType commandLineParser) {
|
121
|
931 cl::opt<bool> ShowFunctionSummaries(
|
|
932 "show-functions", cl::Optional, cl::init(false),
|
|
933 cl::desc("Show coverage summaries for each function"));
|
|
934
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
935 auto Err = commandLineParser(argc, argv);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
936 if (Err)
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
937 return Err;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
938
|
121
|
939 if (ViewOpts.Format == CoverageViewOptions::OutputFormat::HTML) {
|
120
|
940 error("HTML output for summary reports is not yet supported.");
|
121
|
941 return 1;
|
|
942 }
|
120
|
943
|
83
|
944 auto Coverage = load();
|
|
945 if (!Coverage)
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
946 return 1;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
947
|
120
|
948 CoverageReport Report(ViewOpts, *Coverage.get());
|
121
|
949 if (!ShowFunctionSummaries) {
|
|
950 if (SourceFiles.empty())
|
|
951 Report.renderFileReports(llvm::outs());
|
|
952 else
|
|
953 Report.renderFileReports(llvm::outs(), SourceFiles);
|
|
954 } else {
|
|
955 if (SourceFiles.empty()) {
|
|
956 error("Source files must be specified when -show-functions=true is "
|
|
957 "specified");
|
|
958 return 1;
|
|
959 }
|
|
960
|
|
961 Report.renderFunctionReports(SourceFiles, DC, llvm::outs());
|
|
962 }
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
963 return 0;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
964 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
965
|
120
|
966 int CodeCoverageTool::export_(int argc, const char **argv,
|
|
967 CommandLineParserType commandLineParser) {
|
|
968
|
|
969 auto Err = commandLineParser(argc, argv);
|
|
970 if (Err)
|
|
971 return Err;
|
|
972
|
121
|
973 if (ViewOpts.Format != CoverageViewOptions::OutputFormat::Text) {
|
|
974 error("Coverage data can only be exported as textual JSON.");
|
|
975 return 1;
|
|
976 }
|
|
977
|
120
|
978 auto Coverage = load();
|
|
979 if (!Coverage) {
|
|
980 error("Could not load coverage information");
|
|
981 return 1;
|
|
982 }
|
|
983
|
121
|
984 exportCoverageDataToJson(*Coverage.get(), ViewOpts, outs());
|
120
|
985
|
|
986 return 0;
|
|
987 }
|
|
988
|
83
|
989 int showMain(int argc, const char *argv[]) {
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
990 CodeCoverageTool Tool;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
991 return Tool.run(CodeCoverageTool::Show, argc, argv);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
992 }
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
993
|
83
|
994 int reportMain(int argc, const char *argv[]) {
|
77
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
995 CodeCoverageTool Tool;
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
996 return Tool.run(CodeCoverageTool::Report, argc, argv);
|
Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp>
parents:
diff
changeset
|
997 }
|
120
|
998
|
|
999 int exportMain(int argc, const char *argv[]) {
|
|
1000 CodeCoverageTool Tool;
|
|
1001 return Tool.run(CodeCoverageTool::Export, argc, argv);
|
|
1002 }
|