2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/runtime/base/code-coverage.h"
21 #include "hphp/runtime/base/execution-context.h"
22 #include "hphp/runtime/base/type-array.h"
23 #include "hphp/runtime/base/type-string.h"
24 #include "hphp/runtime/ext/extension.h"
26 #include "hphp/util/logger.h"
29 ///////////////////////////////////////////////////////////////////////////////
32 * The function below will be called by the interpreter on each
33 * evaluated expression when running hhvm with:
34 * $ hhvm -v Eval.RecordCodeCoverage=1 <phpfile>
36 * The (line0, line1) pair is supposed to represent the start and end
37 * of an evaluated expression. One should normally increment the line
38 * usage counters for all the lines between line0 and line1 but certain
39 * constructs like including a file, eval-ing a string, or even
40 * executing a for loop do not have a good value for line1.
42 * Indeed on this toy cover.php file:
47 * for($i = 0; $i < 2; $i++) {
55 * eval("echo 'bar\n';");
57 * and with this command:
59 * $ hhvm -v Eval.RecordCodeCoverage=1 \
60 * -v Eval.CodeCoverageOutputFile=/tmp/cov.log \
63 * one get this output (with appropriate printf in this file):
65 * /home/pad/cover.php, (1, 12)
66 * /home/pad/cover.php, (3, 3)
68 * /home/pad/cover.php, (4, 6)
69 * /home/pad/cover.php, (4, 4)
70 * /home/pad/cover.php, (5, 5)
72 * /home/pad/cover.php, (4, 4)
73 * /home/pad/cover.php, (4, 4)
74 * /home/pad/cover.php, (5, 5)
76 * /home/pad/cover.php, (4, 4)
77 * /home/pad/cover.php, (4, 4)
78 * /home/pad/cover.php, (8, 10)
79 * /home/pad/cover.php, (8, 9)
80 * /home/pad/cover.php, (8, 10)
81 * 6/home/pad/cover.php, (12, 12)
82 * /home/pad/cover.php, (12, 12)
83 * /home/pad/cover.php, (1, 2)
84 * /home/pad/cover.php, (1, 2)
86 * So right now it is just simpler to ignore line1.
88 void CodeCoverage::Record(const char *filename
, int line0
, int line1
) {
89 if (!filename
|| !*filename
|| line0
<= 0 || line1
<= 0 || line0
> line1
) {
92 Logger::Verbose("%s, (%d, %d)\n", filename
, line0
, line1
);
94 CodeCoverageMap::iterator iter
= m_hits
.find(filename
);
95 if (iter
== m_hits
.end()) {
96 std::vector
<int> &lines
= m_hits
[filename
];
97 lines
.resize(line1
+ 1);
98 for (int i
= line0
; i
<= line0
/* should be line1 one day */; i
++) {
102 std::vector
<int> &lines
= iter
->second
;
103 if ((int)lines
.size() < line1
+ 1) {
104 lines
.resize(line1
+ 1);
106 for (int i
= line0
; i
<= line0
/* should be line1 one day */; i
++) {
112 Array
CodeCoverage::Report(bool sys
/* = true */) {
113 Array ret
= Array::Create();
114 for (CodeCoverageMap::const_iterator iter
= m_hits
.begin();
115 iter
!= m_hits
.end(); ++iter
) {
116 if (!sys
&& Extension::IsSystemlibPath(iter
->first
)) {
119 const std::vector
<int> &lines
= iter
->second
;
120 Array tmp
= Array::Create();
121 for (int i
= 1; i
< (int)lines
.size(); i
++) {
123 tmp
.set(i
, Variant((int64_t)lines
[i
]));
126 ret
.set(String(iter
->first
), Variant(tmp
));
132 void CodeCoverage::Report(const std::string
&filename
) {
133 std::ofstream
f(filename
.c_str());
135 Logger::Error("unable to open %s", filename
.c_str());
140 for (CodeCoverageMap::const_iterator iter
= m_hits
.begin();
141 iter
!= m_hits
.end();) {
142 const std::vector
<int> &lines
= iter
->second
;
143 f
<< "\"" << iter
->first
<< "\": [";
144 int count
= lines
.size();
145 for (int i
= 0 /* not 1 */; i
< count
; i
++) {
152 if (++iter
!= m_hits
.end()) {
162 void CodeCoverage::Reset() {
164 resetCoverageCounters();
167 ///////////////////////////////////////////////////////////////////////////////