File Coverage

blib/lib/Perl/Critic/Policy/TooMuchCode/ProhibitUnusedImport.pm
Criterion Covered Total %
statement 66 67 98.5
branch 15 20 75.0
condition 11 13 84.6
subroutine 13 14 92.8
pod 3 5 60.0
total 108 119 90.7


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::TooMuchCode::ProhibitUnusedImport;
2              
3 5     5   3163 use strict;
  5         12  
  5         141  
4 5     5   26 use warnings;
  5         10  
  5         119  
5 5     5   28 use Perl::Critic::Utils;
  5         17  
  5         81  
6 5     5   4505 use parent 'Perl::Critic::Policy';
  5         18  
  5         45  
7              
8 5     5   2338 use Perl::Critic::TooMuchCode;
  5         14  
  5         144  
9 5     5   2458 use Perl::Critic::Policy::Variables::ProhibitUnusedVariables;
  5         743873  
  5         3975  
10              
11 0     0 1 0 sub default_themes { return qw( maintenance ) }
12 20     20 1 186935 sub applies_to { return 'PPI::Document' }
13             sub supported_parameters {
14             return (
15             {
16 23     23 0 448260 name => 'ignored_modules',
17             description => 'Modules which will be ignored by this policy.',
18             behavior => 'string list',
19             list_always_present_values => [
20             'Exporter',
21             'Getopt::Long',
22             'Git::Sub',
23             'MooseX::Foreign',
24             'MouseX::Foreign',
25             'Test::Needs',
26             'Test::Requires',
27             'Test::RequiresInternet',
28             ],
29             },
30             {
31             name => 'moose_type_modules',
32             description => 'Modules which import Moose-like types.',
33             behavior => 'string list',
34             list_always_present_values => [
35             'MooseX::Types::Moose',
36             'MooseX::Types::Common::Numeric',
37             'MooseX::Types::Common::String',
38             ],
39             },
40             );
41             }
42              
43             #---------------------------------------------------------------------------
44              
45             sub violates {
46 20     20 1 226 my ( $self, $elem, $doc ) = @_;
47              
48 20         47 my $moose_types = $self->{_moose_type_modules};
49              
50 20         38 my %imported;
51 20         81 $self->gather_imports_generic( \%imported, $elem, $doc );
52              
53 20         66 my %used;
54 20         33 for my $el_word (
55             @{
56             $elem->find(
57             sub {
58 534 100 100 534   8225 $_[1]->isa('PPI::Token::Word')
59             || ( $_[1]->isa('PPI::Token::Symbol')
60             && $_[1]->symbol_type eq '&' );
61             }
62             )
63 20 50       116 || []
64             }
65             ) {
66 87 100       748 if ( $el_word->isa('PPI::Token::Symbol') ) {
67 1         3 $el_word =~ s{^&}{};
68             }
69 87         218 $used{"$el_word"}++;
70             }
71              
72 20         211 Perl::Critic::TooMuchCode::__get_symbol_usage(\%used, $doc);
73              
74 20         42 my @violations;
75 20         72 my @to_report = grep { !$used{$_} } (keys %imported);
  27         88  
76              
77             # Maybe filter out Moose types.
78 20 100       61 if ( @to_report ) {
79 5         22 my %to_report = map { $_ => 1 } @to_report;
  9         35  
80              
81 5         20 for my $import ( keys %to_report ) {
82 9 100 66     60 if ( exists $used{ 'is_' . $import } || exists $used { 'to_' . $import }
      100        
83             && exists $moose_types->{$imported{$import}->[0]} ) {
84 2         13 delete $to_report{$import};
85             }
86             }
87 5         21 @to_report = keys %to_report;
88             }
89 20         74 @to_report = sort { $a cmp $b } @to_report;
  4         14  
90              
91 20         46 for my $tok (@to_report) {
92 7         640 for my $inc_mod (@{ $imported{$tok} }) {
  7         35  
93 7         41 push @violations, $self->violation( "Unused import: $tok", "A token is imported but not used in the same code.", $inc_mod );
94             }
95             }
96              
97 20         957 return @violations;
98             }
99              
100             sub gather_imports_generic {
101 20     20 0 51 my ( $self, $imported, $elem, $doc ) = @_;
102              
103 20         47 my $is_ignored = $self->{_ignored_modules};
104 20   100 534   95 my $include_statements = $elem->find(sub { $_[1]->isa('PPI::Statement::Include') && !$_[1]->pragma }) || [];
  534         7171  
105 20         313 for my $st (@$include_statements) {
106 21 50       75 next if $st->schild(0) eq 'no';
107 21 50   134   667 my $expr_qw = $st->find( sub { $_[1]->isa('PPI::Token::QuoteLike::Words'); }) or next;
  134         1562  
108              
109 21         282 my $included_module = $st->schild(1);
110 21 100       331 next if exists $is_ignored->{$included_module};
111              
112 16 50       100 if (@$expr_qw == 1) {
113 16         32 my $expr = $expr_qw->[0];
114 16         65 my @words = $expr_qw->[0]->literal;
115 16         792 for my $w (@words) {
116 27 50       97 next if $w =~ /\A [:\-\+]/x;
117              
118 27   50     45 push @{ $imported->{$w} //=[] }, $included_module;
  27         176  
119             }
120             }
121             }
122             }
123              
124             1;
125              
126             =encoding utf-8
127              
128             =head1 NAME
129              
130             TooMuchCode::ProhibitUnusedImport -- Find unused imports
131              
132             =head1 DESCRIPTION
133              
134             An "import" is a subroutine brought by a C<use> statement.
135              
136             From the documentation of L<use>, there are several forms of calling `use`. This policy scans for the following two forms:
137              
138             use Module VERSION LIST
139             use Module LIST
140              
141             ... and only the one with LIST written in C<qw()>.
142              
143             Conventionally the LIST after c<use Module> is known as arguments and
144             conventionally when it is written with C<qw()>, the LIST is treated as
145             a import list -- which is a list of symbols that becomes avaiable in
146             the current namespace.
147              
148             For example, the word C<baz> in the following statement is one of such:
149              
150             use Foo qw( baz );
151              
152             Symbols in the import list are often subroutine names or variable
153             names. If they are not used in the following program, they do not neet
154             to be imported.
155              
156             Although an experienced perl programmer would know that the
157             description above is only true by convention, there are many modules
158             on CPAN that already follows such convetion. Which is a good one to
159             follow, and I recommend you to follow.
160              
161             This policy checks only import lists written in C<qw()>, other forms
162             are ignored, or rather, too complicated to be correctly supported.
163              
164             The syntax of C<Importer> module is also supported, but only the ones
165             with C<qw()> at the end.
166              
167             use Importer 'Foo' => qw( baz );
168              
169             Modules with non-trivial form of arguments may have nothing to with
170             symbol-importing. But it might be used with a C<qw()> LIST at the end.
171             Should you wish to do so, you may let chose to let perlcritic to
172             ignore certain modules by setting the C<ignored_modules> in
173             C<.perlcriticrc>. For example:
174              
175             [TooMuchCode::ProhibitUnusedImport]
176             ignored_modules = Git::Sub Regexp::Common
177              
178             Alternatively, you may choose not to write the module arguments as a
179             C<qw()> list.
180              
181             =head2 Moose Types
182              
183             Moose Types can also be imported, but their symbols may not be used
184             as-is. Instead, some other helper functions are generated with names
185             based on the Type. For example:
186              
187             use My::Type::Library::Numeric qw( PositiveInt );
188             use My::Type::Library::String qw( LowerCaseStr );
189              
190             my $foo = 'Bar';
191             my $ok = is_PositiveInt($foo);
192             my $lower = to_LowerCaseStr($foo);
193              
194             The module C<My::Type::Library::Numeric> exports
195             C<is_PositiveInt> as well as C<PositiveInt>. While C<PositiveInt> is
196             not directly used in the following code, is should be considered as
197             being used. Similar for C<LowerCaseStr>.
198              
199             When importing from a Type library, subroutines named like C<is_*> and C<to_*>
200             are not in the import list, but they are also imported.
201              
202             By default, the following modules are treated as Type libraries
203              
204             * MooseX::Types::Moose
205             * MooseX::Types::Common::Numeric
206             * MooseX::Types::Common::String
207              
208             The list can be grown by including your module names to the
209             C<moose_type_modules> in the C<.perlcriticrc>:
210              
211             [TooMuchCode::ProhibitUnusedImport]
212             moose_type_modules = My::Type::Library::Numeric My::Type::Library::String
213              
214             =cut