Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Perl-Critic CPAN distribution.

Report information
The Basics
Id: 79289
Status: patched
Priority: 0/
Queue: Perl-Critic

People
Owner: Nobody in particular
Requestors: cpan.wade [...] anomaly.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 1.110_001
Fixed in: (no value)



Subject: False Postive in Perl::Critic::Utils::is_in_void_context()
The is_in_void_context() method returns true when called in a subscript. This means that BuiltinFunctions::ProhibitVoidGrep generates a false positive for hash slices generated with grep. It looks like the code needs a return if $parent->isa('PPI::Structure::Subscript'); in the group of tests.
On Wed Aug 29 14:01:19 2012, GWADEJ wrote: Show quoted text
> The is_in_void_context() method returns true when called in a > subscript. > > This means that BuiltinFunctions::ProhibitVoidGrep generates a false > positive for hash slices > generated with grep. > > It looks like the code needs a > > > return if $parent->isa('PPI::Structure::Subscript'); > > in the group of tests.
Thank you for your report, and your work to diagnose it. Can you provide a piece of failing code to include in the test suite? I tried my %hash; my @array; @hash{ grep { $_ % 2 } 0 .. 9 } = 0 .. 4; @array[ grep { $_ % 2 } 0 .. 9 ] = 0 .. 4; but none of the greps fails the policy. This is because the policy executes return if not is_function_call($elem); and returns before the call to is_in_void_context() is executed. And is_in_function_call() returns because of the PPI::Structure::Subscript. Thanks, Tom
On Thu Aug 30 15:32:04 2012, WYANT wrote: Show quoted text
> On Wed Aug 29 14:01:19 2012, GWADEJ wrote:
> > The is_in_void_context() method returns true when called in a > > subscript. > > > > This means that BuiltinFunctions::ProhibitVoidGrep generates a false > > positive for hash slices > > generated with grep. > > > > It looks like the code needs a > > > > > > return if $parent->isa('PPI::Structure::Subscript'); > > > > in the group of tests.
> > Thank you for your report, and your work to diagnose it. > > Can you provide a piece of failing code to include in the test suite? I > tried > > my %hash; > my @array; > > @hash{ grep { $_ % 2 } 0 .. 9 } = 0 .. 4; > @array[ grep { $_ % 2 } 0 .. 9 ] = 0 .. 4; > > but none of the greps fails the policy. > > This is because the policy executes > > return if not is_function_call($elem); > > and returns before the call to is_in_void_context() is executed. And > is_in_function_call() returns because of the PPI::Structure::Subscript.
I apologize for not sending a specific example. I didn't realize what a special edge case this was. I generated a minimal example. Running perlcritic --include Void grep_void.pl results in the message: "grep" used in void context at line 7, column 18. Use a "for" loop instead. (Severity: 3) As near as I can tell, it does not misbehave when using the block form of grep. When using the expression form, it only fails if I include the parens. Thanks for all of your work on this. G. Wade
Subject: grep_void.pl
#!/usr/bin/perl use strict; use warnings; my %domains; delete @domains{ grep ( /\.cc$/, keys %domains ) };
Thank you very much for the failing code. Your correction has been committed as SVN revision 4153. What follows is cut-and-pasted from the commit message. The ticket is really about BuiltinFunctions::ProhibitVoidGrep, but the requester's diagnosis of the point of failure and the nature of the correction was correct. This revision applies the requester's correction, and adds tests to ProhibitVoidGrep.run and ProhibitVoidMap.run, since the latter policy had the same problem. The thing is, it appears to me that most uses of grep and map in slice subscripts were passing for the wrong reason. Both policies, after ensuring they have the PPI::Token::Word that they want, call is_function_call() on the element in question, and accept the element if this returns false. The first thing that is_function_call() does is to call is_hash_key(), returning false if is_hash_key() returns true. Well, is_hash_key() is documented as detecting barewords used as hash keys. But it returns true when handed the 'grep' token in the following: @hash{ grep { /foo/ } keys %hash } @hash{ grep /foo/, keys %hash } This causes the policy to declare a true negative in the above cases, but to declare it for the wrong reason. The requester, on the other hand, was doing @hash{ grep ( /foo/, keys %hash ) ) which is a violation of a couple other policies, but should not be a violation of this one. But the parens after the 'grep' were causing is_hash_key() to fail; consequently is_function_call() succeeded, so the failure of is_in_void_context() to return false when called on a token in a subscript was exposed.