llvm.org GIT mirror llvm / 40a78f8
Reapply "[llvm-cov] Add an -output-dir option for the show sub-command"" Passing -output-dir path/to/dir to llvm-cov show creates path/to/dir if it doesn't already exist, and prints reports into that directory. In function view mode, all views are written into path/to/dir/functions.$EXTENSION. In file view mode, all views are written into path/to/dir/coverage/$PATH.$EXTENSION. Changes since the initial commit: - Avoid accidentally closing stdout twice. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273985 91177308-0d34-0410-b5e6-96231b3b80d8 Vedant Kumar 3 years ago
8 changed file(s) with 138 addition(s) and 6 deletion(s). Raw diff Collapse all Expand all
239239
240240 Use the specified output format. The supported formats are: "text".
241241
242 .. option:: -output-dir=PATH
243
244 Specify a directory to write coverage reports into. If the directory does not
245 exist, it is created. When used in function view mode (i.e when -name or
246 -name-regex are used to select specific functions), the report is written to
247 PATH/functions.EXTENSION. When used in file view mode, a report for each file
248 is written to PATH/REL_PATH_TO_FILE.EXTENSION.
249
242250 .. option:: -line-coverage-gt=
243251
244252 Show code coverage only for functions with line coverage greater than the
2727
2828 // RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -filename-equivalence %s | FileCheck -check-prefixes=CHECK,WHOLE-FILE %s
2929 // RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -instr-profile %t.profdata -filename-equivalence -name=main %s | FileCheck -check-prefixes=CHECK,FILTER %s
30
31 // Test -output-dir.
32 // RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.dir -instr-profile %t.profdata -filename-equivalence %s
33 // RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping -output-dir %t.dir -instr-profile %t.profdata -filename-equivalence -name=main %s
34 // RUN: FileCheck -check-prefixes=CHECK,WHOLE-FILE -input-file %t.dir/coverage/tmp/showLineExecutionCounts.cpp.txt %s
35 // RUN: FileCheck -check-prefixes=CHECK,FILTER -input-file %t.dir/functions.txt %s
405405 clEnumValEnd),
406406 cl::init(CoverageViewOptions::OutputFormat::Text));
407407
408 cl::opt ShowOutputDirectory(
409 "output-dir", cl::init(""),
410 cl::desc("Directory in which coverage information is written out"));
411 cl::alias ShowOutputDirectoryA("o", cl::desc("Alias for --output-dir"),
412 cl::aliasopt(ShowOutputDirectory));
413
408414 auto Err = commandLineParser(argc, argv);
409415 if (Err)
410416 return Err;
417423 ViewOpts.ShowExpandedRegions = ShowExpansions;
418424 ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
419425 ViewOpts.ShowFormat = ShowFormat;
426 ViewOpts.ShowOutputDirectory = ShowOutputDirectory;
427
428 if (ViewOpts.ShowOutputDirectory != "") {
429 if (auto E = sys::fs::create_directories(ViewOpts.ShowOutputDirectory)) {
430 error("Could not create output directory!", E.message());
431 return 1;
432 }
433 }
420434
421435 auto Coverage = load();
422436 if (!Coverage)
435449 << "\n";
436450 continue;
437451 }
438 mainView->print(outs(), /*WholeFile=*/false, /*ShowSourceName=*/true);
439 outs() << "\n";
452
453 auto OSOrErr =
454 mainView->createOutputFile("functions", /*InToplevel=*/true);
455 if (Error E = OSOrErr.takeError()) {
456 handleAllErrors(OSOrErr.takeError(),
457 [&](const ErrorInfoBase &EI) { error(EI.message()); });
458 return 1;
459 }
460 auto OS = std::move(OSOrErr.get());
461 mainView->print(*OS.get(), /*WholeFile=*/false, /*ShowSourceName=*/true);
462 mainView->closeOutputFile(std::move(OS));
440463 }
441464 return 0;
442465 }
458481 continue;
459482 }
460483
461 mainView->print(outs(), /*Wholefile=*/true,
484 auto OSOrErr = mainView->createOutputFile(SourceFile, /*InToplevel=*/false);
485 if (Error E = OSOrErr.takeError()) {
486 handleAllErrors(OSOrErr.takeError(),
487 [&](const ErrorInfoBase &EI) { error(EI.message()); });
488 return 1;
489 }
490 auto OS = std::move(OSOrErr.get());
491 mainView->print(*OS.get(), /*Wholefile=*/true,
462492 /*ShowSourceName=*/ShowFilenames);
463 if (SourceFiles.size() > 1)
464 outs() << "\n";
493 mainView->closeOutputFile(std::move(OS));
465494 }
466495
467496 return 0;
2929 bool ShowFunctionInstantiations;
3030 bool ShowFullFilenames;
3131 OutputFormat ShowFormat;
32 std::string ShowOutputDirectory;
3233
3334 /// \brief Change the output's stream color if the colors are enabled.
3435 ColoredRawOstream colored_ostream(raw_ostream &OS,
1414 #include "SourceCoverageViewText.h"
1515 #include "llvm/ADT/SmallString.h"
1616 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/Support/FileSystem.h"
1718 #include "llvm/Support/LineIterator.h"
19 #include "llvm/Support/Path.h"
1820
1921 using namespace llvm;
2022
3335 return Result;
3436 }
3537
38 void SourceCoverageView::StreamDestructor::operator()(raw_ostream *OS) const {
39 if (OS == &outs())
40 return;
41 delete OS;
42 }
43
44 /// \brief Create a file at ``Dir/ToplevelDir/@Path.Extension``. If
45 /// \p ToplevelDir is empty, its path component is skipped.
46 static Expected
47 createFileInDirectory(StringRef Dir, StringRef ToplevelDir, StringRef Path,
48 StringRef Extension) {
49 assert(Extension.size() && "The file extension may not be empty");
50
51 SmallString<256> FullPath(Dir);
52 if (!ToplevelDir.empty())
53 sys::path::append(FullPath, ToplevelDir);
54
55 auto PathBaseDir = sys::path::relative_path(sys::path::parent_path(Path));
56 sys::path::append(FullPath, PathBaseDir);
57
58 if (auto E = sys::fs::create_directories(FullPath))
59 return errorCodeToError(E);
60
61 auto PathFilename = (sys::path::filename(Path) + "." + Extension).str();
62 sys::path::append(FullPath, PathFilename);
63
64 std::error_code E;
65 auto OS = SourceCoverageView::OwnedStream(
66 new raw_fd_ostream(FullPath, E, sys::fs::F_RW));
67 if (E)
68 return errorCodeToError(E);
69 return std::move(OS);
70 }
71
72 Expected
73 SourceCoverageView::createOutputStream(const CoverageViewOptions &Opts,
74 StringRef Path, StringRef Extension,
75 bool InToplevel) {
76 if (Opts.ShowOutputDirectory == "")
77 return OwnedStream(&outs());
78
79 return createFileInDirectory(Opts.ShowOutputDirectory,
80 InToplevel ? "" : "coverage", Path, Extension);
81 }
82
3683 void SourceCoverageView::addExpansion(
3784 const coverage::CounterMappingRegion &Region,
3885 std::unique_ptr View) {
100100 ///
101101 /// A source coverage view and its nested sub-views form a file-oriented
102102 /// representation of code coverage data. This view can be printed out by a
103 /// renderer which implements the Rendering Interface.
103 /// renderer which implements both the File Creation and Rendering interfaces.
104104 class SourceCoverageView {
105105 /// A function or file name.
106106 StringRef SourceName;
120120 /// A container for all instantiations (e.g template functions) in the source
121121 /// on display.
122122 std::vector InstantiationSubViews;
123
124 public:
125 struct StreamDestructor {
126 void operator()(raw_ostream *OS) const;
127 };
128
129 using OwnedStream = std::unique_ptr;
130
131 /// @name File Creation Interface
132 /// @{
133
134 /// \brief Create a file to print a coverage view into.
135 virtual Expected createOutputFile(StringRef Path,
136 bool InToplevel) = 0;
137
138 /// \brief Close a file which has been used to print a coverage view.
139 virtual void closeOutputFile(OwnedStream OS) = 0;
140
141 /// @}
123142
124143 protected:
125144 struct LineRef {
182201 /// digits.
183202 static std::string formatCount(uint64_t N);
184203
204 /// \brief If directory output is enabled, create a file with \p Path as the
205 /// suffix. Otherwise, return stdout.
206 static Expected
207 createOutputStream(const CoverageViewOptions &Opts, StringRef Path,
208 StringRef Extension, bool InToplevel);
209
185210 SourceCoverageView(StringRef SourceName, const MemoryBuffer &File,
186211 const CoverageViewOptions &Options,
187212 coverage::CoverageData &&CoverageInfo)
3535 }
3636
3737 } // anonymous namespace
38
39 Expected
40 SourceCoverageViewText::createOutputFile(StringRef Path, bool InToplevel) {
41 return createOutputStream(getOptions(), Path, "txt", InToplevel);
42 }
43
44 void SourceCoverageViewText::closeOutputFile(OwnedStream OS) {
45 OS->operator<<('\n');
46 }
3847
3948 void SourceCoverageViewText::renderSourceName(raw_ostream &OS) {
4049 getOptions().colored_ostream(OS, raw_ostream::CYAN) << getSourceName()
1919
2020 /// \brief A code coverage view which supports text-based rendering.
2121 class SourceCoverageViewText : public SourceCoverageView {
22 public:
23 Expected createOutputFile(StringRef Path,
24 bool InToplevel) override;
25
26 void closeOutputFile(OwnedStream OS) override;
27
28 private:
2229 void renderSourceName(raw_ostream &OS) override;
2330
2431 void renderLinePrefix(raw_ostream &OS, unsigned ViewDepth) override;