comparison tools/llvm-cov/CodeCoverage.cpp @ 83:60c9769439b8 LLVM3.7

LLVM 3.7
author Tatsuki IHA <e125716@ie.u-ryukyu.ac.jp>
date Wed, 18 Feb 2015 14:55:36 +0900
parents 54457678186b
children afa8332a0e37
comparison
equal deleted inserted replaced
78:af83660cff7b 83:60c9769439b8
11 // report coverage information using the profiling instrumentation and code 11 // report coverage information using the profiling instrumentation and code
12 // coverage mapping. 12 // coverage mapping.
13 // 13 //
14 //===----------------------------------------------------------------------===// 14 //===----------------------------------------------------------------------===//
15 15
16 #include "FunctionCoverageMapping.h"
17 #include "RenderingSupport.h" 16 #include "RenderingSupport.h"
17 #include "CoverageFilters.h"
18 #include "CoverageReport.h"
18 #include "CoverageViewOptions.h" 19 #include "CoverageViewOptions.h"
19 #include "CoverageFilters.h"
20 #include "SourceCoverageDataManager.h"
21 #include "SourceCoverageView.h" 20 #include "SourceCoverageView.h"
22 #include "CoverageSummary.h" 21 #include "llvm/ADT/SmallString.h"
23 #include "CoverageReport.h"
24 #include "llvm/ADT/StringRef.h" 22 #include "llvm/ADT/StringRef.h"
25 #include "llvm/ADT/SmallString.h" 23 #include "llvm/ProfileData/CoverageMapping.h"
26 #include "llvm/ADT/SmallSet.h"
27 #include "llvm/ADT/DenseSet.h"
28 #include "llvm/ProfileData/InstrProfReader.h" 24 #include "llvm/ProfileData/InstrProfReader.h"
29 #include "llvm/ProfileData/CoverageMapping.h"
30 #include "llvm/ProfileData/CoverageMappingReader.h"
31 #include "llvm/Support/CommandLine.h" 25 #include "llvm/Support/CommandLine.h"
32 #include "llvm/Support/FileSystem.h" 26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/Format.h"
33 #include "llvm/Support/ManagedStatic.h" 28 #include "llvm/Support/ManagedStatic.h"
34 #include "llvm/Support/MemoryObject.h"
35 #include "llvm/Support/Format.h"
36 #include "llvm/Support/Path.h" 29 #include "llvm/Support/Path.h"
30 #include "llvm/Support/PrettyStackTrace.h"
37 #include "llvm/Support/Signals.h" 31 #include "llvm/Support/Signals.h"
38 #include "llvm/Support/PrettyStackTrace.h" 32 #include <functional>
39 #include <system_error> 33 #include <system_error>
40 #include <functional>
41 34
42 using namespace llvm; 35 using namespace llvm;
43 using namespace coverage; 36 using namespace coverage;
44 37
45 namespace { 38 namespace {
46 /// \brief Distribute the functions into instantiation sets.
47 /// An instantiation set is a collection of functions
48 /// that have the same source code, e.g.
49 /// template functions specializations.
50 class FunctionInstantiationSetCollector {
51 ArrayRef<FunctionCoverageMapping> FunctionMappings;
52 typedef uint64_t KeyType;
53 typedef std::vector<const FunctionCoverageMapping *> SetType;
54 std::unordered_map<uint64_t, SetType> InstantiatedFunctions;
55
56 static KeyType getKey(const MappingRegion &R) {
57 return uint64_t(R.LineStart) | uint64_t(R.ColumnStart) << 32;
58 }
59
60 public:
61 void insert(const FunctionCoverageMapping &Function, unsigned FileID) {
62 KeyType Key = 0;
63 for (const auto &R : Function.MappingRegions) {
64 if (R.FileID == FileID) {
65 Key = getKey(R);
66 break;
67 }
68 }
69 auto I = InstantiatedFunctions.find(Key);
70 if (I == InstantiatedFunctions.end()) {
71 SetType Set;
72 Set.push_back(&Function);
73 InstantiatedFunctions.insert(std::make_pair(Key, Set));
74 } else
75 I->second.push_back(&Function);
76 }
77
78 std::unordered_map<KeyType, SetType>::iterator begin() {
79 return InstantiatedFunctions.begin();
80 }
81
82 std::unordered_map<KeyType, SetType>::iterator end() {
83 return InstantiatedFunctions.end();
84 }
85 };
86
87 /// \brief The implementation of the coverage tool. 39 /// \brief The implementation of the coverage tool.
88 class CodeCoverageTool { 40 class CodeCoverageTool {
89 public: 41 public:
90 enum Command { 42 enum Command {
91 /// \brief The show command. 43 /// \brief The show command.
98 void error(const Twine &Message, StringRef Whence = ""); 50 void error(const Twine &Message, StringRef Whence = "");
99 51
100 /// \brief Return a memory buffer for the given source file. 52 /// \brief Return a memory buffer for the given source file.
101 ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile); 53 ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
102 54
103 /// \brief Return true if two filepaths refer to the same file. 55 /// \brief Create source views for the expansions of the view.
104 bool equivalentFiles(StringRef A, StringRef B); 56 void attachExpansionSubViews(SourceCoverageView &View,
105 57 ArrayRef<ExpansionRecord> Expansions,
106 /// \brief Collect a set of function's file ids which correspond to the 58 CoverageMapping &Coverage);
107 /// given source file. Return false if the set is empty. 59
108 bool gatherInterestingFileIDs(StringRef SourceFile, 60 /// \brief Create the source view of a particular function.
109 const FunctionCoverageMapping &Function, 61 std::unique_ptr<SourceCoverageView>
110 SmallSet<unsigned, 8> &InterestingFileIDs); 62 createFunctionView(const FunctionRecord &Function, CoverageMapping &Coverage);
111
112 /// \brief Find the file id which is not an expanded file id.
113 bool findMainViewFileID(StringRef SourceFile,
114 const FunctionCoverageMapping &Function,
115 unsigned &MainViewFileID);
116
117 bool findMainViewFileID(const FunctionCoverageMapping &Function,
118 unsigned &MainViewFileID);
119
120 /// \brief Create a source view which shows coverage for an expansion
121 /// of a file.
122 void createExpansionSubView(const MappingRegion &ExpandedRegion,
123 const FunctionCoverageMapping &Function,
124 SourceCoverageView &Parent);
125
126 void createExpansionSubViews(SourceCoverageView &View, unsigned ViewFileID,
127 const FunctionCoverageMapping &Function);
128
129 /// \brief Create a source view which shows coverage for an instantiation
130 /// of a funciton.
131 void createInstantiationSubView(StringRef SourceFile,
132 const FunctionCoverageMapping &Function,
133 SourceCoverageView &View);
134 63
135 /// \brief Create the main source view of a particular source file. 64 /// \brief Create the main source view of a particular source file.
136 /// Return true if this particular source file is not covered. 65 std::unique_ptr<SourceCoverageView>
137 bool 66 createSourceFileView(StringRef SourceFile, CoverageMapping &Coverage);
138 createSourceFileView(StringRef SourceFile, SourceCoverageView &View,
139 ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
140 bool UseOnlyRegionsInMainFile = false);
141 67
142 /// \brief Load the coverage mapping data. Return true if an error occured. 68 /// \brief Load the coverage mapping data. Return true if an error occured.
143 bool load(); 69 std::unique_ptr<CoverageMapping> load();
144 70
145 int run(Command Cmd, int argc, const char **argv); 71 int run(Command Cmd, int argc, const char **argv);
146 72
147 typedef std::function<int(int, const char **)> CommandLineParserType; 73 typedef std::function<int(int, const char **)> CommandLineParserType;
148 74
150 CommandLineParserType commandLineParser); 76 CommandLineParserType commandLineParser);
151 77
152 int report(int argc, const char **argv, 78 int report(int argc, const char **argv,
153 CommandLineParserType commandLineParser); 79 CommandLineParserType commandLineParser);
154 80
155 StringRef ObjectFilename; 81 std::string ObjectFilename;
156 CoverageViewOptions ViewOpts; 82 CoverageViewOptions ViewOpts;
157 std::unique_ptr<IndexedInstrProfReader> PGOReader; 83 std::string PGOFilename;
158 CoverageFiltersMatchAll Filters; 84 CoverageFiltersMatchAll Filters;
159 std::vector<std::string> SourceFiles; 85 std::vector<std::string> SourceFiles;
160 std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>> 86 std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
161 LoadedSourceFiles; 87 LoadedSourceFiles;
162 std::vector<FunctionCoverageMapping> FunctionMappingRecords;
163 bool CompareFilenamesOnly; 88 bool CompareFilenamesOnly;
89 StringMap<std::string> RemappedFilenames;
164 }; 90 };
165 } 91 }
166 92
167 void CodeCoverageTool::error(const Twine &Message, StringRef Whence) { 93 void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
168 errs() << "error: "; 94 errs() << "error: ";
171 errs() << Message << "\n"; 97 errs() << Message << "\n";
172 } 98 }
173 99
174 ErrorOr<const MemoryBuffer &> 100 ErrorOr<const MemoryBuffer &>
175 CodeCoverageTool::getSourceFile(StringRef SourceFile) { 101 CodeCoverageTool::getSourceFile(StringRef SourceFile) {
176 SmallString<256> Path(SourceFile); 102 // If we've remapped filenames, look up the real location for this file.
177 sys::fs::make_absolute(Path); 103 if (!RemappedFilenames.empty()) {
178 for (const auto &Files : LoadedSourceFiles) { 104 auto Loc = RemappedFilenames.find(SourceFile);
179 if (sys::fs::equivalent(Path.str(), Files.first)) { 105 if (Loc != RemappedFilenames.end())
106 SourceFile = Loc->second;
107 }
108 for (const auto &Files : LoadedSourceFiles)
109 if (sys::fs::equivalent(SourceFile, Files.first))
180 return *Files.second; 110 return *Files.second;
181 }
182 }
183 auto Buffer = MemoryBuffer::getFile(SourceFile); 111 auto Buffer = MemoryBuffer::getFile(SourceFile);
184 if (auto EC = Buffer.getError()) { 112 if (auto EC = Buffer.getError()) {
185 error(EC.message(), SourceFile); 113 error(EC.message(), SourceFile);
186 return EC; 114 return EC;
187 } 115 }
188 LoadedSourceFiles.push_back(std::make_pair( 116 LoadedSourceFiles.push_back(
189 std::string(Path.begin(), Path.end()), std::move(Buffer.get()))); 117 std::make_pair(SourceFile, std::move(Buffer.get())));
190 return *LoadedSourceFiles.back().second; 118 return *LoadedSourceFiles.back().second;
191 } 119 }
192 120
193 /// \brief Return a line start - line end range which contains 121 void
194 /// all the mapping regions of a given function with a particular file id. 122 CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View,
195 std::pair<unsigned, unsigned> 123 ArrayRef<ExpansionRecord> Expansions,
196 findExpandedFileInterestingLineRange(unsigned FileID, 124 CoverageMapping &Coverage) {
197 const FunctionCoverageMapping &Function) {
198 unsigned LineStart = std::numeric_limits<unsigned>::max();
199 unsigned LineEnd = 0;
200 for (const auto &Region : Function.MappingRegions) {
201 if (Region.FileID != FileID)
202 continue;
203 LineStart = std::min(Region.LineStart, LineStart);
204 LineEnd = std::max(Region.LineEnd, LineEnd);
205 }
206 return std::make_pair(LineStart, LineEnd);
207 }
208
209 bool CodeCoverageTool::equivalentFiles(StringRef A, StringRef B) {
210 if (CompareFilenamesOnly)
211 return sys::path::filename(A).equals_lower(sys::path::filename(B));
212 return sys::fs::equivalent(A, B);
213 }
214
215 bool CodeCoverageTool::gatherInterestingFileIDs(
216 StringRef SourceFile, const FunctionCoverageMapping &Function,
217 SmallSet<unsigned, 8> &InterestingFileIDs) {
218 bool Interesting = false;
219 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
220 if (equivalentFiles(SourceFile, Function.Filenames[I])) {
221 InterestingFileIDs.insert(I);
222 Interesting = true;
223 }
224 }
225 return Interesting;
226 }
227
228 bool
229 CodeCoverageTool::findMainViewFileID(StringRef SourceFile,
230 const FunctionCoverageMapping &Function,
231 unsigned &MainViewFileID) {
232 llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false);
233 llvm::SmallVector<bool, 8> FilenameEquivalence(Function.Filenames.size(),
234 false);
235 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
236 if (equivalentFiles(SourceFile, Function.Filenames[I]))
237 FilenameEquivalence[I] = true;
238 }
239 for (const auto &Region : Function.MappingRegions) {
240 if (Region.Kind == MappingRegion::ExpansionRegion &&
241 FilenameEquivalence[Region.FileID])
242 IsExpandedFile[Region.ExpandedFileID] = true;
243 }
244 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
245 if (!FilenameEquivalence[I] || IsExpandedFile[I])
246 continue;
247 MainViewFileID = I;
248 return false;
249 }
250 return true;
251 }
252
253 bool
254 CodeCoverageTool::findMainViewFileID(const FunctionCoverageMapping &Function,
255 unsigned &MainViewFileID) {
256 llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(), false);
257 for (const auto &Region : Function.MappingRegions) {
258 if (Region.Kind == MappingRegion::ExpansionRegion)
259 IsExpandedFile[Region.ExpandedFileID] = true;
260 }
261 for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
262 if (IsExpandedFile[I])
263 continue;
264 MainViewFileID = I;
265 return false;
266 }
267 return true;
268 }
269
270 void CodeCoverageTool::createExpansionSubView(
271 const MappingRegion &ExpandedRegion,
272 const FunctionCoverageMapping &Function, SourceCoverageView &Parent) {
273 auto ExpandedLines = findExpandedFileInterestingLineRange(
274 ExpandedRegion.ExpandedFileID, Function);
275 if (ViewOpts.Debug)
276 llvm::outs() << "Expansion of " << ExpandedRegion.ExpandedFileID << ":"
277 << ExpandedLines.first << " -> " << ExpandedLines.second
278 << " @ " << ExpandedRegion.FileID << ", "
279 << ExpandedRegion.LineStart << ":"
280 << ExpandedRegion.ColumnStart << "\n";
281 auto SourceBuffer =
282 getSourceFile(Function.Filenames[ExpandedRegion.ExpandedFileID]);
283 if (!SourceBuffer)
284 return;
285 auto SubView = llvm::make_unique<SourceCoverageView>(
286 SourceBuffer.get(), Parent.getOptions(), ExpandedLines.first,
287 ExpandedLines.second, ExpandedRegion);
288 SourceCoverageDataManager RegionManager;
289 for (const auto &Region : Function.MappingRegions) {
290 if (Region.FileID == ExpandedRegion.ExpandedFileID)
291 RegionManager.insert(Region);
292 }
293 SubView->load(RegionManager);
294 createExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID, Function);
295 Parent.addChild(std::move(SubView));
296 }
297
298 void CodeCoverageTool::createExpansionSubViews(
299 SourceCoverageView &View, unsigned ViewFileID,
300 const FunctionCoverageMapping &Function) {
301 if (!ViewOpts.ShowExpandedRegions) 125 if (!ViewOpts.ShowExpandedRegions)
302 return; 126 return;
303 for (const auto &Region : Function.MappingRegions) { 127 for (const auto &Expansion : Expansions) {
304 if (Region.Kind != CounterMappingRegion::ExpansionRegion) 128 auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
129 if (ExpansionCoverage.empty())
305 continue; 130 continue;
306 if (Region.FileID != ViewFileID) 131 auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
132 if (!SourceBuffer)
307 continue; 133 continue;
308 createExpansionSubView(Region, Function, View); 134
309 } 135 auto SubViewExpansions = ExpansionCoverage.getExpansions();
310 } 136 auto SubView = llvm::make_unique<SourceCoverageView>(
311 137 SourceBuffer.get(), ViewOpts, std::move(ExpansionCoverage));
312 void CodeCoverageTool::createInstantiationSubView( 138 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
313 StringRef SourceFile, const FunctionCoverageMapping &Function, 139 View.addExpansion(Expansion.Region, std::move(SubView));
314 SourceCoverageView &View) { 140 }
315 SourceCoverageDataManager RegionManager; 141 }
316 SmallSet<unsigned, 8> InterestingFileIDs; 142
317 if (!gatherInterestingFileIDs(SourceFile, Function, InterestingFileIDs)) 143 std::unique_ptr<SourceCoverageView>
318 return; 144 CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
319 // Get the interesting regions 145 CoverageMapping &Coverage) {
320 for (const auto &Region : Function.MappingRegions) { 146 auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
321 if (InterestingFileIDs.count(Region.FileID)) 147 if (FunctionCoverage.empty())
322 RegionManager.insert(Region); 148 return nullptr;
323 } 149 auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
324 View.load(RegionManager); 150 if (!SourceBuffer)
325 unsigned MainFileID; 151 return nullptr;
326 if (findMainViewFileID(SourceFile, Function, MainFileID)) 152
327 return; 153 auto Expansions = FunctionCoverage.getExpansions();
328 createExpansionSubViews(View, MainFileID, Function); 154 auto View = llvm::make_unique<SourceCoverageView>(
329 } 155 SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage));
330 156 attachExpansionSubViews(*View, Expansions, Coverage);
331 bool CodeCoverageTool::createSourceFileView( 157
332 StringRef SourceFile, SourceCoverageView &View, 158 return View;
333 ArrayRef<FunctionCoverageMapping> FunctionMappingRecords, 159 }
334 bool UseOnlyRegionsInMainFile) { 160
335 SourceCoverageDataManager RegionManager; 161 std::unique_ptr<SourceCoverageView>
336 FunctionInstantiationSetCollector InstantiationSetCollector; 162 CodeCoverageTool::createSourceFileView(StringRef SourceFile,
337 163 CoverageMapping &Coverage) {
338 for (const auto &Function : FunctionMappingRecords) { 164 auto SourceBuffer = getSourceFile(SourceFile);
339 unsigned MainFileID; 165 if (!SourceBuffer)
340 if (findMainViewFileID(SourceFile, Function, MainFileID)) 166 return nullptr;
341 continue; 167 auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
342 SmallSet<unsigned, 8> InterestingFileIDs; 168 if (FileCoverage.empty())
343 if (UseOnlyRegionsInMainFile) { 169 return nullptr;
344 InterestingFileIDs.insert(MainFileID); 170
345 } else if (!gatherInterestingFileIDs(SourceFile, Function, 171 auto Expansions = FileCoverage.getExpansions();
346 InterestingFileIDs)) 172 auto View = llvm::make_unique<SourceCoverageView>(
347 continue; 173 SourceBuffer.get(), ViewOpts, std::move(FileCoverage));
348 // Get the interesting regions 174 attachExpansionSubViews(*View, Expansions, Coverage);
349 for (const auto &Region : Function.MappingRegions) { 175
350 if (InterestingFileIDs.count(Region.FileID)) 176 for (auto Function : Coverage.getInstantiations(SourceFile)) {
351 RegionManager.insert(Region); 177 auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
352 } 178 auto SubViewExpansions = SubViewCoverage.getExpansions();
353 InstantiationSetCollector.insert(Function, MainFileID); 179 auto SubView = llvm::make_unique<SourceCoverageView>(
354 createExpansionSubViews(View, MainFileID, Function); 180 SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
355 } 181 attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
356 if (RegionManager.getSourceRegions().empty()) 182
357 return true; 183 if (SubView) {
358 View.load(RegionManager); 184 unsigned FileID = Function->CountedRegions.front().FileID;
359 // Show instantiations 185 unsigned Line = 0;
360 if (!ViewOpts.ShowFunctionInstantiations) 186 for (const auto &CR : Function->CountedRegions)
361 return false; 187 if (CR.FileID == FileID)
362 for (const auto &InstantiationSet : InstantiationSetCollector) { 188 Line = std::max(CR.LineEnd, Line);
363 if (InstantiationSet.second.size() < 2) 189 View->addInstantiation(Function->Name, Line, std::move(SubView));
364 continue; 190 }
365 auto InterestingRange = findExpandedFileInterestingLineRange( 191 }
366 InstantiationSet.second.front()->MappingRegions.front().FileID, 192 return View;
367 *InstantiationSet.second.front()); 193 }
368 for (auto Function : InstantiationSet.second) { 194
369 auto SubView = llvm::make_unique<SourceCoverageView>( 195 std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
370 View, InterestingRange.first, InterestingRange.second, 196 auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename);
371 Function->PrettyName); 197 if (std::error_code EC = CoverageOrErr.getError()) {
372 createInstantiationSubView(SourceFile, *Function, *SubView); 198 colored_ostream(errs(), raw_ostream::RED)
373 View.addChild(std::move(SubView)); 199 << "error: Failed to load coverage: " << EC.message();
374 } 200 errs() << "\n";
375 } 201 return nullptr;
376 return false; 202 }
377 } 203 auto Coverage = std::move(CoverageOrErr.get());
378 204 unsigned Mismatched = Coverage->getMismatchedCount();
379 bool CodeCoverageTool::load() { 205 if (Mismatched) {
380 auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename); 206 colored_ostream(errs(), raw_ostream::RED)
381 if (auto EC = CounterMappingBuff.getError()) { 207 << "warning: " << Mismatched << " functions have mismatched data. ";
382 error(EC.message(), ObjectFilename); 208 errs() << "\n";
383 return true; 209 }
384 } 210
385 ObjectFileCoverageMappingReader MappingReader(CounterMappingBuff.get()); 211 if (CompareFilenamesOnly) {
386 if (auto EC = MappingReader.readHeader()) { 212 auto CoveredFiles = Coverage.get()->getUniqueSourceFiles();
387 error(EC.message(), ObjectFilename); 213 for (auto &SF : SourceFiles) {
388 return true; 214 StringRef SFBase = sys::path::filename(SF);
389 } 215 for (const auto &CF : CoveredFiles)
390 216 if (SFBase == sys::path::filename(CF)) {
391 std::vector<uint64_t> Counts; 217 RemappedFilenames[CF] = SF;
392 for (const auto &I : MappingReader) { 218 SF = CF;
393 FunctionCoverageMapping Function(I.FunctionName, I.Filenames); 219 break;
394
395 // Create the mapping regions with evaluated execution counts
396 Counts.clear();
397 PGOReader->getFunctionCounts(Function.Name, I.FunctionHash, Counts);
398
399 // Get the biggest referenced counters
400 bool RegionError = false;
401 CounterMappingContext Ctx(I.Expressions, Counts);
402 for (const auto &R : I.MappingRegions) {
403 // Compute the values of mapped regions
404 if (ViewOpts.Debug) {
405 outs() << "File " << R.FileID << "| " << R.LineStart << ":"
406 << R.ColumnStart << " -> " << R.LineEnd << ":" << R.ColumnEnd
407 << " = ";
408 Ctx.dump(R.Count);
409 if (R.Kind == CounterMappingRegion::ExpansionRegion) {
410 outs() << " (Expanded file id = " << R.ExpandedFileID << ") ";
411 } 220 }
412 outs() << "\n"; 221 }
413 } 222 }
414 std::error_code Error; 223
415 Function.MappingRegions.push_back( 224 return Coverage;
416 MappingRegion(R, Ctx.evaluate(R.Count, Error)));
417 if (Error && !RegionError) {
418 colored_ostream(errs(), raw_ostream::RED)
419 << "error: Regions and counters don't match in a function '"
420 << Function.PrettyName << "' (re-run the instrumented binary).";
421 errs() << "\n";
422 RegionError = true;
423 }
424 }
425
426 if (RegionError || !Filters.matches(Function))
427 continue;
428
429 FunctionMappingRecords.push_back(Function);
430 }
431 return false;
432 } 225 }
433 226
434 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { 227 int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
435 // Print a stack trace if we signal out. 228 // Print a stack trace if we signal out.
436 sys::PrintStackTraceOnErrorSignal(); 229 sys::PrintStackTraceOnErrorSignal();
437 PrettyStackTraceProgram X(argc, argv); 230 PrettyStackTraceProgram X(argc, argv);
438 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 231 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
439 232
233 cl::opt<std::string, true> ObjectFilename(
234 cl::Positional, cl::Required, cl::location(this->ObjectFilename),
235 cl::desc("Covered executable or object file."));
236
440 cl::list<std::string> InputSourceFiles( 237 cl::list<std::string> InputSourceFiles(
441 cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore); 238 cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
442 239
443 cl::opt<std::string> PGOFilename( 240 cl::opt<std::string, true> PGOFilename(
444 "instr-profile", cl::Required, 241 "instr-profile", cl::Required, cl::location(this->PGOFilename),
445 cl::desc( 242 cl::desc(
446 "File with the profile data obtained after an instrumented run")); 243 "File with the profile data obtained after an instrumented run"));
447 244
448 cl::opt<bool> DebugDump("dump", cl::Optional, 245 cl::opt<bool> DebugDump("dump", cl::Optional,
449 cl::desc("Show internal debug dump")); 246 cl::desc("Show internal debug dump"));
450 247
451 cl::opt<bool> FilenameEquivalence( 248 cl::opt<bool> FilenameEquivalence(
452 "filename-equivalence", cl::Optional, 249 "filename-equivalence", cl::Optional,
453 cl::desc("Compare the filenames instead of full filepaths")); 250 cl::desc("Treat source files as equivalent to paths in the coverage data "
251 "when the file names match, even if the full paths do not"));
454 252
455 cl::OptionCategory FilteringCategory("Function filtering options"); 253 cl::OptionCategory FilteringCategory("Function filtering options");
456 254
457 cl::list<std::string> NameFilters( 255 cl::list<std::string> NameFilters(
458 "name", cl::Optional, 256 "name", cl::Optional,
491 289
492 auto commandLineParser = [&, this](int argc, const char **argv) -> int { 290 auto commandLineParser = [&, this](int argc, const char **argv) -> int {
493 cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); 291 cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
494 ViewOpts.Debug = DebugDump; 292 ViewOpts.Debug = DebugDump;
495 CompareFilenamesOnly = FilenameEquivalence; 293 CompareFilenamesOnly = FilenameEquivalence;
496
497 if (auto EC = IndexedInstrProfReader::create(PGOFilename, PGOReader)) {
498 error(EC.message(), PGOFilename);
499 return 1;
500 }
501 294
502 // Create the function filters 295 // Create the function filters
503 if (!NameFilters.empty() || !NameRegexFilters.empty()) { 296 if (!NameFilters.empty() || !NameRegexFilters.empty()) {
504 auto NameFilterer = new CoverageFilters; 297 auto NameFilterer = new CoverageFilters;
505 for (const auto &Name : NameFilters) 298 for (const auto &Name : NameFilters)
527 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>( 320 StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
528 RegionCoverageFilter::GreaterThan, LineCoverageGtFilter)); 321 RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
529 Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer)); 322 Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
530 } 323 }
531 324
532 SourceFiles = InputSourceFiles; 325 for (const auto &File : InputSourceFiles) {
326 SmallString<128> Path(File);
327 if (!CompareFilenamesOnly)
328 if (std::error_code EC = sys::fs::make_absolute(Path)) {
329 errs() << "error: " << File << ": " << EC.message();
330 return 1;
331 }
332 SourceFiles.push_back(Path.str());
333 }
533 return 0; 334 return 0;
534 }; 335 };
535
536 // Parse the object filename
537 if (argc > 1) {
538 StringRef Arg(argv[1]);
539 if (Arg.equals_lower("-help") || Arg.equals_lower("-version")) {
540 cl::ParseCommandLineOptions(2, argv, "LLVM code coverage tool\n");
541 return 0;
542 }
543 ObjectFilename = Arg;
544
545 argv[1] = argv[0];
546 --argc;
547 ++argv;
548 } else {
549 errs() << sys::path::filename(argv[0]) << ": No executable file given!\n";
550 return 1;
551 }
552 336
553 switch (Cmd) { 337 switch (Cmd) {
554 case Show: 338 case Show:
555 return show(argc, argv, commandLineParser); 339 return show(argc, argv, commandLineParser);
556 case Report: 340 case Report:
603 ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts; 387 ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
604 ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts; 388 ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts;
605 ViewOpts.ShowExpandedRegions = ShowExpansions; 389 ViewOpts.ShowExpandedRegions = ShowExpansions;
606 ViewOpts.ShowFunctionInstantiations = ShowInstantiations; 390 ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
607 391
608 if (load()) 392 auto Coverage = load();
393 if (!Coverage)
609 return 1; 394 return 1;
610 395
611 if (!Filters.empty()) { 396 if (!Filters.empty()) {
612 // Show functions 397 // Show functions
613 for (const auto &Function : FunctionMappingRecords) { 398 for (const auto &Function : Coverage->getCoveredFunctions()) {
614 unsigned MainFileID; 399 if (!Filters.matches(Function))
615 if (findMainViewFileID(Function, MainFileID))
616 continue; 400 continue;
617 StringRef SourceFile = Function.Filenames[MainFileID]; 401
618 auto SourceBuffer = getSourceFile(SourceFile); 402 auto mainView = createFunctionView(Function, *Coverage);
619 if (!SourceBuffer) 403 if (!mainView) {
620 return 1; 404 ViewOpts.colored_ostream(outs(), raw_ostream::RED)
621 auto Range = findExpandedFileInterestingLineRange(MainFileID, Function); 405 << "warning: Could not read coverage for '" << Function.Name;
622 SourceCoverageView mainView(SourceBuffer.get(), ViewOpts, Range.first, 406 outs() << "\n";
623 Range.second); 407 continue;
624 createSourceFileView(SourceFile, mainView, Function, true); 408 }
625 ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) 409 ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << Function.Name
626 << Function.PrettyName << " from " << SourceFile << ":"; 410 << ":";
627 outs() << "\n"; 411 outs() << "\n";
628 mainView.render(outs()); 412 mainView->render(outs(), /*WholeFile=*/false);
629 if (FunctionMappingRecords.size() > 1) 413 outs() << "\n";
630 outs() << "\n";
631 } 414 }
632 return 0; 415 return 0;
633 } 416 }
634 417
635 // Show files 418 // Show files
636 bool ShowFilenames = SourceFiles.size() != 1; 419 bool ShowFilenames = SourceFiles.size() != 1;
637 420
638 if (SourceFiles.empty()) { 421 if (SourceFiles.empty())
639 // Get the source files from the function coverage mapping 422 // Get the source files from the function coverage mapping
640 std::set<StringRef> UniqueFilenames; 423 for (StringRef Filename : Coverage->getUniqueSourceFiles())
641 for (const auto &Function : FunctionMappingRecords) {
642 for (const auto &Filename : Function.Filenames)
643 UniqueFilenames.insert(Filename);
644 }
645 for (const auto &Filename : UniqueFilenames)
646 SourceFiles.push_back(Filename); 424 SourceFiles.push_back(Filename);
647 }
648 425
649 for (const auto &SourceFile : SourceFiles) { 426 for (const auto &SourceFile : SourceFiles) {
650 auto SourceBuffer = getSourceFile(SourceFile); 427 auto mainView = createSourceFileView(SourceFile, *Coverage);
651 if (!SourceBuffer) 428 if (!mainView) {
652 return 1;
653 SourceCoverageView mainView(SourceBuffer.get(), ViewOpts);
654 if (createSourceFileView(SourceFile, mainView, FunctionMappingRecords)) {
655 ViewOpts.colored_ostream(outs(), raw_ostream::RED) 429 ViewOpts.colored_ostream(outs(), raw_ostream::RED)
656 << "warning: The file '" << SourceFile << "' isn't covered."; 430 << "warning: The file '" << SourceFile << "' isn't covered.";
657 outs() << "\n"; 431 outs() << "\n";
658 continue; 432 continue;
659 } 433 }
660 434
661 if (ShowFilenames) { 435 if (ShowFilenames) {
662 ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":"; 436 ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":";
663 outs() << "\n"; 437 outs() << "\n";
664 } 438 }
665 mainView.render(outs()); 439 mainView->render(outs(), /*Wholefile=*/true);
666 if (SourceFiles.size() > 1) 440 if (SourceFiles.size() > 1)
667 outs() << "\n"; 441 outs() << "\n";
668 } 442 }
669 443
670 return 0; 444 return 0;
679 if (Err) 453 if (Err)
680 return Err; 454 return Err;
681 455
682 ViewOpts.Colors = !NoColors; 456 ViewOpts.Colors = !NoColors;
683 457
684 if (load()) 458 auto Coverage = load();
459 if (!Coverage)
685 return 1; 460 return 1;
686 461
687 CoverageSummary Summarizer; 462 CoverageReport Report(ViewOpts, std::move(Coverage));
688 Summarizer.createSummaries(FunctionMappingRecords); 463 if (SourceFiles.empty())
689 CoverageReport Report(ViewOpts, Summarizer);
690 if (SourceFiles.empty() && Filters.empty()) {
691 Report.renderFileReports(llvm::outs()); 464 Report.renderFileReports(llvm::outs());
692 return 0; 465 else
693 } 466 Report.renderFunctionReports(SourceFiles, llvm::outs());
694
695 Report.renderFunctionReports(llvm::outs());
696 return 0; 467 return 0;
697 } 468 }
698 469
699 int show_main(int argc, const char **argv) { 470 int showMain(int argc, const char *argv[]) {
700 CodeCoverageTool Tool; 471 CodeCoverageTool Tool;
701 return Tool.run(CodeCoverageTool::Show, argc, argv); 472 return Tool.run(CodeCoverageTool::Show, argc, argv);
702 } 473 }
703 474
704 int report_main(int argc, const char **argv) { 475 int reportMain(int argc, const char *argv[]) {
705 CodeCoverageTool Tool; 476 CodeCoverageTool Tool;
706 return Tool.run(CodeCoverageTool::Report, argc, argv); 477 return Tool.run(CodeCoverageTool::Report, argc, argv);
707 } 478 }