oi->size = 0;
}
- s = SvPV_const(sv, len);
+ if (sv) {
+ s = SvPV_const(sv, len);
+ } else {
+ s = "{";
+ len = 1;
+ }
+
if (len > oi->size) {
Safefree(oi->buf);
Newx(oi->buf, len, char);
oi->size = len;
}
Copy(s, oi->buf, len, char);
+
oi->len = len;
oi->pos = src;
oi->line = line;
return o;
}
+/* ... ck_scope ............................................................ */
+
+STATIC OP *(*indirect_old_ck_scope) (pTHX_ OP *) = 0;
+STATIC OP *(*indirect_old_ck_lineseq)(pTHX_ OP *) = 0;
+
+STATIC OP *indirect_ck_scope(pTHX_ OP *o) {
+ OP *(*old_ck)(pTHX_ OP *) = 0;
+
+ switch (o->op_type) {
+ case OP_SCOPE: old_ck = indirect_old_ck_scope; break;
+ case OP_LINESEQ: old_ck = indirect_old_ck_lineseq; break;
+ }
+ o = CALL_FPTR(old_ck)(aTHX_ o);
+
+ if (indirect_hint()) {
+ indirect_map_store(o, PL_oldbufptr, NULL, CopLINE(&PL_compiling));
+ return o;
+ }
+
+ indirect_map_delete(o);
+ return o;
+}
+
+/* ... ck_leave ............................................................ */
+
+STATIC OP *(*indirect_old_ck_leave)(pTHX_ OP *) = 0;
+
+STATIC OP *indirect_ck_leave(pTHX_ OP *o) {
+ o = CALL_FPTR(indirect_old_ck_leave)(aTHX_ o);
+
+ /* Cleanup relevant entries in case ck_method catches them later. */
+ indirect_map_delete(o);
+ return o;
+}
+
/* ... ck_method ........................................................... */
STATIC OP *(*indirect_old_ck_method)(pTHX_ OP *) = 0;
case OP_CONST:
case OP_RV2SV:
case OP_PADSV:
+ case OP_SCOPE:
+ case OP_LEAVE:
break;
default:
goto done;
PL_check[OP_RV2SV] = MEMBER_TO_FPTR(indirect_ck_rv2sv);
indirect_old_ck_padany = PL_check[OP_PADANY];
PL_check[OP_PADANY] = MEMBER_TO_FPTR(indirect_ck_padany);
+ indirect_old_ck_scope = PL_check[OP_SCOPE];
+ PL_check[OP_SCOPE] = MEMBER_TO_FPTR(indirect_ck_scope);
+ indirect_old_ck_lineseq = PL_check[OP_LINESEQ];
+ PL_check[OP_LINESEQ] = MEMBER_TO_FPTR(indirect_ck_scope);
+ indirect_old_ck_leave = PL_check[OP_LEAVE];
+ PL_check[OP_LEAVE] = MEMBER_TO_FPTR(indirect_ck_leave);
+
indirect_old_ck_method = PL_check[OP_METHOD];
PL_check[OP_METHOD] = MEMBER_TO_FPTR(indirect_ck_method);
indirect_old_ck_entersub = PL_check[OP_ENTERSUB];
When enabled (or disabled as some may prefer to say, since you actually turn it on by calling C<no indirect>), this pragma warns about indirect object syntax constructs that may have slipped into your code.
This syntax is now considered harmful, since its parsing has many quirks and its use is error prone (when C<swoosh> isn't defined, C<swoosh $x> actually compiles to C<< $x->swoosh >>).
-It currently does not warn when the object is enclosed between braces (like C<meth { $obj } @args>) or for core functions (C<print> or C<say>).
+It currently does not warn for core functions (C<print>, C<say>, C<exec> or C<system>).
This may change in the future, or may be added as optional features that would be enabled by passing options to C<unimport>.
This module is B<not> a source filter.
=cut
sub msg {
- "Indirect call of method \"$_[1]\" on object \"$_[0]\" at $_[2] line $_[3].\n"
+ my $obj = $_[0];
+
+ join ' ', "Indirect call of method \"$_[1]\" on",
+ ($obj =~ /^\s*\{/ ? "a block" : "object \"$obj\""),
+ "at $_[2] line $_[3].\n";
};
=head1 CONSTANTS
my ($obj, $pkg, $cb, $x, @a);
our $y;
sub meh;
+sub try (&);
{
local $/ = "####";
####
$obj = $pkg->$cb(qw/foo bar baz/);
####
-$obj = new { $x };
-####
-$obj = new
- {
- $x }
- ();
-####
-$obj = new {
- $x } qq/foo/;
-####
-$obj = new
- {
- $x
- }(qw/bar baz/);
-####
meh;
####
meh $_;
system $x $x, @a;
####
system { $a[0] } @a;
+####
+try { };
+####
+try { 1; };
+####
+try { 1; 1; };
+####
+try { try { }; 1; };
my ($tests, $reports);
BEGIN {
- $tests = 52;
- $reports = 53;
+ $tests = 60;
+ $reports = 68;
}
use Test::More tests => 3 * (4 * $tests + $reports) + 2;
map {
my ($meth, $obj, $file, $line) = @$_;
- $_ = quotemeta for $meth, $obj;
+ $meth = quotemeta $meth;
+ $obj = ($obj =~ /^\s*\{/) ? "a block" : "object \"\Q$obj\E\"";
$file = '\(eval \d+\)' unless defined $file;
$line = '\d+' unless defined $line;
- qr/^Indirect call of method "$meth" on object "$obj" at $file line $line/
+ qr/^Indirect call of method "$meth" on $obj at $file line $line/
} eval $expected;
}
Hlagh->new(meh $x)
----
[ 'meh', '$x' ]
+####
+meh { };
+----
+[ 'meh', '{' ]
+####
+meh {
+ 1;
+};
+----
+[ 'meh', '{' ]
+####
+meh {
+ 1;
+ 1;
+};
+----
+[ 'meh', '{' ]
+####
+meh { new Hlagh; 1; };
+----
+[ 'new', 'Hlagh' ], [ 'meh', '{' ]
+####
+meh { feh $x; 1; };
+----
+[ 'feh', '$x' ], [ 'meh', '{' ]
+####
+meh { feh $x; use indirect; new Hlagh; 1; };
+----
+[ 'feh', '$x' ], [ 'meh', '{' ]
+####
+meh { feh $y; 1; };
+----
+[ 'feh', '$y' ], [ 'meh', '{' ]
+####
+meh { feh $x; 1; } new Hlagh, feh $y;
+----
+[ 'feh', '$x' ], [ 'new', 'Hlagh' ], [ 'feh', '$y' ], [ 'meh', '{' ]