Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Perl::Critic policy to catch quoted execution?

by Your Mother (Archbishop)
on Sep 22, 2022 at 16:17 UTC ( [id://11147063]=perlquestion: print w/replies, xml ) Need Help??

Your Mother has asked for the wisdom of the Perl Monks concerning the following question:

Is there a Perl::Critic policy to catch attempts to use method calls within interpolation? So, it would catch this, and perhaps more convoluted examples like "$ref->()" or "$obj->$meth".

say "U GOTS $account->balance LEFTZ";

If not, would you do it naïvely in PPI or something? This isn’t a big enough deal to chase a lot, I’m just curious. :P

Replies are listed 'Best First'.
Re: Perl::Critic policy to catch quoted execution?
by AnomalousMonk (Archbishop) on Sep 22, 2022 at 17:16 UTC

    Since such method calls do not do anything like what one might naively expect, I'm not sure a Perl::Critic policy would be useful:

    Win8 Strawberry 5.8.9.5 (32) Thu 09/22/2022 13:05:47 C:\@Work\Perl\monks >perl use strict; use warnings; my $ref = sub { return "hiya \n"; }; print $ref->(); my $str = "foo $ref->() bar \n"; print $str; ^Z hiya foo CODE(0x9145ec)->() bar
    What criticism would you expect in this case? Isn't the fact that something's wrong going to be immediately obvious?


    Give a man a fish:  <%-{-{-{-<

      Obvious is in the eye of the beholder. I’ve seen this class of error make it into production in two workplaces. Update: for criticism, just to flag it exactly as you say: “This won’t output what you seem to expect.”

Re: Perl::Critic policy to catch quoted execution?
by LanX (Saint) on Sep 22, 2022 at 22:41 UTC
    I'm not good with PPI or Critic, but my understanding is that it's only parsing legal syntax into tokens, and like demonstrated everything behind the -> is just a string.

    But maybe this can help?

    C:\>perl -MO=Deparse,-q print "A $a->meth or $ref->() or $obj->$meth B"; __DATA__ print 'A ' . $a . '->meth or ' . $ref . '->() or ' . $obj . '->' . $me +th . ' B'; __DATA__ - syntax OK Terminating on signal SIGINT(2)

    so you could regex the deparsed output, or search the OP-Tree, or probably tell PPI to check for real strings starting with '->'.

    HT(probably)H

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

      Oh, that’s fun. Whether or not I end up doing anything related to the original question I’m glad you showed that.

Re: Perl::Critic policy to catch quoted execution?
by Anonymous Monk on Sep 24, 2022 at 20:14 UTC

    PPI does not look inside string-like things, so most Perl::Critic policies do not, either. PPIx::QuoteLike makes an attempt to sort out string contents, and it parses your string as

    $ pqldump '"U GOTS $account->balance LEFTZ"'
    
    "U GOTS $account->balance LEFTZ"
    PPIx::QuoteLike	"..."	failures=0	interpolates=1
      PPIx::QuoteLike::Token::String	'U GOTS '
      PPIx::QuoteLike::Token::Interpolation	'$account'
      PPIx::QuoteLike::Token::String	'->balance LEFTZ'
    

    Maybe you could look at an interpolation followed by '->' as a red flag? I have no idea what edge cases or false positives would exist. And you would need to look inside regular expressions as well.

    Disclaimer: I am the author of PPIx::QuoteLike.

Re: Perl::Critic policy to catch quoted execution?
by Anonymous Monk on Sep 23, 2022 at 10:10 UTC

      Preliminary version , probably false positive on proper interpolation

      https://metacpan.org/pod/PPI::Token::Quote::Double

      https://metacpan.org/pod/PPIx::QuoteLike

      https://metacpan.org/pod/Perl::Critic::Utils#is_method_call(-$element-)

      #!/usr/bin/perl -- use strict; use warnings; use Perl::Critic; my $code = \<<'__CODE__'; say "$hi ->bye"; say "$hi -> bye"; say "$hi->bye"; # line 3 say "U @{[~~gmtime]} GOTS $account->balance LEFTZ"; __CODE__ print "$$code\n"; my $critic = Perl::Critic->new( -verbose => 11, ### these fail me -theme => 'yourmother', -include => ['interpolate', ], ); $critic->config()->add_policy( -policy => 'Perl::Critic::Policy::ValuesAndExpressions::SubMethodC +allsDontInterpolate', ); my @violations = $critic->critique( $code ); print @violations; exit( 0 ); BEGIN { package Perl::Critic::Policy::ValuesAndExpressions::SubMethodCalls +DontInterpolate; $INC{ join('/',split '::', __PACKAGE__).'.pm' } = __FILE__; our $VERSION = '0.01'; use strict; use warnings; use Readonly; use parent 'Perl::Critic::Policy'; use Perl::Critic::Utils qw{ :severities }; sub supported_parameters { return () } sub default_severity { return $SEVERITY_LOWEST } # didn't work sub default_themes { return qw< yourmother > } # sub default_themes { return qw< bugs maintenance yourmother +> } sub applies_to { return qw/PPI::Statement/ } Readonly::Scalar my $DESC => q{sub/method calls dont interpolate. This + won't output what you seem to expect.}; Readonly::Scalar my $EXPL => q{Maybe $foo->bar() should be @{[ $foo->b +ar ]} cause sub/method calls don't interpolate like $variables.)}; sub violates { my ( $self, $elem, undef ) = @_; my $qqs = $elem->find('PPI::Token::Quote::Double') ; for my $qq ( @$qqs ){ my $content = $qq->content ; if( $content =~ /(?<!\\)(?:\\\\)*[\$]/ and $content =~ m{\w->\ +w} ){ return $self->violation( $DESC, $EXPL, $elem ); } } return; } 1; }

        Hey, thanks for taking a stab at it. I’ll play around with it.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11147063]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (3)
As of 2024-03-29 14:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found