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: 15022
Status: resolved
Priority: 0/
Queue: Perl-Critic

People
Owner: thaljef [...] cpan.org
Requestors: chris+rt [...] chrisdolan.net
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.12
Fixed in: 0.13



Subject: False positive with 'if' or 'unless' as hash keys
The following sample module: package Foo; use warnings; use strict; my %hash; if ($hash{if} || $hash{unless}) { print "Foo\n"; } 1; triggers the following criticism: % perlcritic Foo.pm Postfix control 'if' used at line 6, column 11. See pages 93,94 of PBP. Postfix control 'unless' used at line 6, column 24. See pages 96,97 of PBP. Perl::Critic (or perhaps PPI?) is being mislead by the unusually-named hash keys. -- Chris
That's going to be tricky. Nearly every Policy module is prone to this problem. PPI lexes barewords into the same class, regardless of the context. I'll talk to Adam about whether PPI can/should make distinctions about barewords in hash keys. I could be imagining this, but I seem to recall that bareword hash keys weren't always treated as strings until fairly recently (since v5.6.1 perhaps). If that's the case, I wonder if the best practice should be to always quote your hash keys. -Jeff
From: cdolan [...] cpan.org
[THALJEF - Wed Oct 12 03:21:14 2005]: Show quoted text
> That's going to be tricky. Nearly every Policy module is prone to > this problem. PPI lexes barewords into the same class, regardless of > the context. I'll talk to Adam about whether PPI can/should make > distinctions about barewords in hash keys. I could be imagining this, > but I seem to recall that bareword hash keys weren't always treated as > strings until fairly recently (since v5.6.1 perhaps). If that's the > case, I wonder if the best practice should be to always quote your > hash keys. > > -Jeff
Maybe you should look for a PPI::Structure::Condition instead of a PPI::Token::Word? Or ascend the tree to see if we're inside of a hash dereference? Dunno... The same problem seems like it would apply to these: BuiltinFunctions::ProhibitStringyEval BuiltinFunctions::RequireBlockGrep BuiltinFunctions::RequireBlockMap Subroutines::ProhibitExplicitReturnUndef and maybe ControlStructures::ProhibitCascadingIfElse If I get a little free time tonight, I'll try to write some regression tests that catch these hashkey false positives. -- Chris
From: cdolan [...] cpan.org
OK, I wrote a bunch of regression tests (attached) that fail because of hash key barewords. I marked them as TODO tests, so they pass when you do Build test but you can see the failures when you do Build test test_files=t/02_policies.t verbose=1 There, you see four failing tests under: BuiltinFunctions::ProhibitStringyEval BuiltinFunctions::RequireBlockGrep BuiltinFunctions::RequireBlockMap ControlStructures::ProhibitPostfixControls In all four cases, if you can distinguish hash keys from function calls (either via a new PPI construct or by looking at the element's parent node), then the problem goes away. I couldn't create any failure with these policies (which also use PPI::Token::Word nodes) because thy look at siblings. I couldn't think of a way to give a hashkey a sibling, so I couldn't make a failure. CodeLayout::ProhibitParensWithBuiltins ControlStructures::ProhibitCascadingIfElse Subroutines::ProhibitExplicitReturnUndef -- Chris
diff -Nur Perl-Critic-0.12-orig/t/02_policies.t Perl-Critic-0.12-hashtests/t/02_policies.t --- Perl-Critic-0.12-orig/t/02_policies.t 2005-10-11 03:16:50.000000000 -0500 +++ Perl-Critic-0.12-hashtests/t/02_policies.t 2005-10-12 21:38:34.000000000 -0500 @@ -1,7 +1,7 @@ use blib; use strict; use warnings; -use Test::More tests => 96; +use Test::More tests => 100; use Perl::Critic; my $code = undef; @@ -28,6 +28,20 @@ #---------------------------------------------------------------- +TODO: { +local $TODO = "keywords as hash keys are not recognized"; + +$code = <<'END_PERL'; +my %hash; +$hash{eval} = 1; +END_PERL + +$policy = 'BuiltinFunctions::ProhibitStringyEval'; +is( critique($policy, \$code), 0, $policy); +} + +#---------------------------------------------------------------- + $code = <<'END_PERL'; grep $_ eq 'foo', @list; @matches = grep $_ eq 'foo', @list; @@ -48,6 +62,20 @@ #---------------------------------------------------------------- +TODO: { +local $TODO = "keywords as hash keys are not recognized"; + +$code = <<'END_PERL'; +my %hash; +$hash{grep} = 1; +END_PERL + +$policy = 'BuiltinFunctions::RequireBlockGrep'; +is( critique($policy, \$code), 0, $policy); +} + +#---------------------------------------------------------------- + $code = <<'END_PERL'; map $_++, @list; @foo = map $_++, @list; @@ -68,6 +96,20 @@ #----------------------------------------------------------------------------- +TODO: { +local $TODO = "keywords as hash keys are not recognized"; + +$code = <<'END_PERL'; +my %hash; +$hash{map} = 1; +END_PERL + +$policy = 'BuiltinFunctions::RequireBlockMap'; +is( critique($policy, \$code), 0, $policy); +} + +#---------------------------------------------------------------- + $code = <<'END_PERL'; @files = <*.pl>; END_PERL @@ -311,6 +353,24 @@ #---------------------------------------------------------------- +TODO: { +local $TODO = "keywords as hash keys are not recognized"; + +$code = <<'END_PERL'; +my %hash; +$hash{if} = 1; +$hash{unless} = 1; +$hash{while} = 1; +$hash{until} = 1; +$hash{for} = 1; +END_PERL + +$policy = 'ControlStructures::ProhibitPostfixControls'; +is( critique($policy, \$code), 0, $policy); +} + +#---------------------------------------------------------------- + $code = <<'END_PERL'; if ($condition1){ $foo;
From: thaljef [...] cpan.org
I put your regression tests into the build. I haven't spoken with Adam yet, but for now, I've solved this problem with a utility function that returns true if a given element is a hash key ("$foo{bar} = 1" or "%foo = (bar => 1)". Any Policy that searches for Token::Word elements probably needs to call is_hash_key($elem) before proceeding. This will be available next week in version 0.12_01 -Jeff
From: cdolan [...] cpan.org
You rock, Jeff. Thanks for the hard work! Chris