File Coverage

Cover.xs
Criterion Covered Total %
statement 93 121 76.8
branch 75 210 35.7
condition n/a
subroutine n/a
pod n/a
total 168 331 50.7


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4             #include
5              
6             static GV *sub_to_gv(pTHX_ SV *sv);
7             Perl_ppaddr_t orig_subhandler;
8             Perl_ppaddr_t orig_openhandler;
9             //Perl_ppaddr_t orig_sysopenhandler;
10              
11             // If we do not use threads we will make this global
12             // The performance impact of fetching it each time is significant, so avoid it
13             // if we can.
14             #ifdef USE_ITHREADS
15             #define fetch_report HV *report = get_hv("Test2::Plugin::Cover::REPORT", GV_ADDMULTI);
16             #define fetch_opens AV *opens = get_av("Test2::Plugin::Cover::OPENS", GV_ADDMULTI);
17             #else
18             HV *report;
19             AV *opens;
20             #define fetch_report NOOP
21             #define fetch_opens NOOP
22             #endif
23              
24             #define fetch_from SV *from = get_sv("Test2::Plugin::Cover::FROM", 0);
25             #define fetch_root SV *root = get_sv("Test2::Plugin::Cover::ROOT", 0);
26             #define fetch_enabled SV *enabled = get_sv("Test2::Plugin::Cover::ENABLED", 0);
27             #define fetch_trace_opens SV *trace_opens = get_sv("Test2::Plugin::Cover::TRACE_OPENS", 0);
28              
29 256           void add_entry(char *fname, STRLEN fnamelen, char *sname, STRLEN snamelen) {
30             fetch_report;
31 256           HV *file = NULL;
32 256           SV **existing_file = hv_fetch(report, fname, fnamelen, 0);
33 256 100         if (existing_file) {
34 92           file = (HV *)SvRV(*existing_file);
35             }
36             else {
37 164           file = newHV();
38 164           hv_store(report, fname, fnamelen, newRV_inc((SV *)file), 0);
39             }
40              
41 256           HV *sub = NULL;
42 256           SV **existing_sub = hv_fetch(file, sname, snamelen, 0);
43 256 100         if (existing_sub) {
44 72           sub = (HV *)SvRV(*existing_sub);
45             }
46             else {
47 184           sub = newHV();
48 184           hv_store(file, sname, snamelen, newRV_inc((SV *)sub), 0);
49             }
50              
51 256           fetch_from;
52 256 50         if (!(from && SvOK(from))) {
    50          
    0          
    0          
53 0           from = newSVpv("*", 1);
54             }
55             else {
56 256           from = sv_mortalcopy(from);
57 256           SvREFCNT_inc(from);
58             }
59              
60 256 100         if (!hv_exists_ent(sub, from, 0)) {
61 196           hv_store_ent(sub, from, from, 0);
62             }
63              
64 256           return;
65             }
66              
67 17347           static OP* my_subhandler(pTHX) {
68 17347           dSP;
69 17347           OP* out = orig_subhandler(aTHX);
70              
71 17347           fetch_enabled;
72 17347 50         if (!SvTRUE(enabled)) {
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    100          
    0          
73 38           return out;
74             }
75              
76 17309 100         if (out != NULL && (out->op_type == OP_NEXTSTATE || out->op_type == OP_DBSTATE)) {
    100          
    50          
77 14279 50         char *fname = CopFILE(cCOPx(out));
78 14279           STRLEN namelen = strlen(fname);
79              
80             // Check for absolute paths and reject them. This is a very
81             // unix-oriented optimization.
82 14279 100         if (!strncmp(fname, "/", 1)) {
83 14115           fetch_root;
84              
85 14115 50         if (root != NULL && SvPOK(root)) {
    50          
86             STRLEN len;
87 14115           char *rt = NULL;
88 14115 50         rt = SvPV(root, len);
89              
90 24168 100         if (namelen < len) return out;
91              
92 10132 100         if (strncmp(fname, rt, len)) {
93 10132           return out;
94             }
95             }
96             }
97              
98 243           char *subname = NULL;
99 243           STRLEN sublen = 0;
100              
101 243           GV *my_gv = sub_to_gv(aTHX_ *SP);
102 243 50         if (my_gv != NULL) {
103 243           subname = GvNAME(my_gv);
104 243           sublen = strlen(subname);
105             }
106             else {
107 0           subname = "*";
108 0           sublen = 1;
109             }
110              
111 243           add_entry(fname, namelen, subname, sublen);
112             }
113              
114 3273           return out;
115             }
116              
117             // Copied and modified from Devel::NYTProf
118 243           static GV *sub_to_gv(pTHX_ SV *sv) {
119 243           CV *cv = NULL;
120              
121             /* copied from top of perl's pp_entersub */
122             /* modified to return either CV or else a GV */
123             /* or a NULL in cases that pp_entersub would croak */
124 243           switch (SvTYPE(sv)) {
125             default:
126 11 50         if (!SvROK(sv)) {
127 0           char *sym = NULL;
128              
129 0 0         if (sv == &PL_sv_yes) { /* unfound import, ignore */
130 0           return NULL;
131             }
132 0 0         if (SvGMAGICAL(sv)) {
133 0           mg_get(sv);
134 0 0         if (SvROK(sv))
135 0           goto got_rv;
136 0 0         sym = SvPOKp(sv) ? SvPVX(sv) : Nullch;
137             }
138             // else {
139             // This causes the warnings from issue #2 https://github.com/Test-More/Test2-Plugin-Cover/issues/2
140             //sym = SvPV_nolen(sv);
141             // }
142              
143 0 0         if (!sym)
144 0           return NULL;
145 0 0         if (PL_op->op_private & HINT_STRICT_REFS)
146 0           return NULL;
147 0           cv = get_cv(sym, TRUE);
148 0           break;
149             }
150             got_rv:
151             {
152 11           SV **sp = &sv; /* Used in tryAMAGICunDEREF macro. */
153 11           tryAMAGICunDEREF(to_cv);
154             }
155 11           cv = (CV*)SvRV(sv);
156 11 50         if (SvTYPE(cv) == SVt_PVCV)
157 11           break;
158              
159             /* FALL THROUGH */
160             case SVt_PVHV:
161             case SVt_PVAV:
162 0           return NULL;
163              
164             case SVt_PVCV:
165 232           cv = (CV*)sv;
166 232           break;
167              
168             case SVt_PVGV:
169 0 0         if (!(isGV_with_GP(sv) && (cv = GvCVu((GV*)sv)))) {
    0          
    0          
    0          
    0          
170 0           HV *stash = NULL;
171 0           GV *gv = NULL;
172 0           cv = sv_2cv(sv, &stash, &gv, FALSE);
173              
174 0 0         if (gv) {
175 0           return gv;
176             }
177             }
178              
179 0 0         if (!cv) { /* would autoload in this situation */
180 0           return NULL;
181             }
182              
183 0           break;
184             }
185              
186 243 50         if (cv) {
187 243           GV *out = CvGV(cv);
188 243 50         if (out && isGV_with_GP(out)) {
    50          
    50          
    0          
189 243           return out;
190             }
191             }
192              
193 0           return NULL;
194             }
195              
196 14           void _sv_file_handler(SV *filename) {
197 24 50         if (filename == NULL) return;
198 14 100         if (!SvPOKp(filename)) return;
199              
200 13           STRLEN namelen = 0;
201 13 50         char *fname = SvPV(filename, namelen);
202              
203 13           add_entry(fname, namelen, "<>", 2);
204              
205 13           fetch_trace_opens;
206 13 50         if (!SvTRUE(trace_opens)) return;
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    100          
    0          
207              
208 4           const PERL_CONTEXT* cx = cxstack;
209 4           AV* row = newAV();
210              
211 4           av_push(row, newSVpvn(fname, namelen));
212 4 50         av_push(row, newSVpv(OutCopFILE(PL_curcop), 0));
213 4           av_push(row, newSViv(CopLINE(PL_curcop)));
214              
215 4 50         SV* package = newSVpv(CopSTASHPV(PL_curcop), 0);
    50          
    50          
    50          
    0          
    50          
    50          
216 4           av_push(row, package);
217              
218             fetch_opens;
219 4           av_push(opens, newRV_inc((SV *)row));
220             }
221              
222 15           static OP* my_openhandler(pTHX) {
223 15           dSP;
224              
225 15           fetch_enabled;
226 15 50         if (SvTRUE(enabled)) {
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
227 15           SV **mark = PL_stack_base + TOPMARK;
228 15           I32 items = (I32)(sp - mark);
229              
230             // Only grab for 2-arg or 3-arg form
231 15 100         if (items == 2 || items == 3) {
    100          
232 14           _sv_file_handler(TOPs);
233             }
234             }
235              
236 15           return orig_openhandler(aTHX);
237             }
238              
239             //static OP* my_sysopenhandler(pTHX) {
240             // dSP;
241             //
242             // fetch_enabled;
243             // if (SvTRUE(enabled)) {
244             // SV **mark = PL_stack_base + TOPMARK;
245             // I32 ax = (I32)(mark - PL_stack_base + 1);
246             // I32 items = (I32)(sp - mark);
247             //
248             // if (items >= 2) {
249             // _sv_file_handler(PL_stack_base[ax + (1)]);
250             // }
251             // }
252             //
253             // return orig_sysopenhandler(aTHX);
254             //}
255              
256             MODULE = Test2::Plugin::Cover PACKAGE = Test2::Plugin::Cover
257              
258             PROTOTYPES: ENABLE
259              
260             BOOT:
261             {
262             //Initialize the global files HV, but only if we are not a threaded perl
263             #ifndef USE_ITHREADS
264 7           report = get_hv("Test2::Plugin::Cover::REPORT", GV_ADDMULTI);
265 7           SvREFCNT_inc(report);
266 7           opens = get_av("Test2::Plugin::Cover::OPENS", GV_ADDMULTI);
267 7           SvREFCNT_inc(opens);
268             #endif
269              
270 7           orig_subhandler = PL_ppaddr[OP_ENTERSUB];
271 7           PL_ppaddr[OP_ENTERSUB] = my_subhandler;
272              
273 7           orig_openhandler = PL_ppaddr[OP_OPEN];
274 7           PL_ppaddr[OP_OPEN] = my_openhandler;
275              
276             //orig_sysopenhandler = PL_ppaddr[OP_SYSOPEN];
277             //PL_ppaddr[OP_SYSOPEN] = my_sysopenhandler;
278             }