line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package App::perlimports::Include; |
2
|
|
|
|
|
|
|
|
3
|
76
|
|
|
76
|
|
2026
|
use Moo; |
|
76
|
|
|
|
|
9116
|
|
|
76
|
|
|
|
|
696
|
|
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
our $VERSION = '0.000052'; |
6
|
|
|
|
|
|
|
|
7
|
76
|
|
|
76
|
|
73811
|
use Data::Dumper qw( Dumper ); |
|
76
|
|
|
|
|
431474
|
|
|
76
|
|
|
|
|
6588
|
|
8
|
76
|
|
|
76
|
|
682
|
use List::Util qw( any none uniq ); |
|
76
|
|
|
|
|
227
|
|
|
76
|
|
|
|
|
6611
|
|
9
|
76
|
|
|
76
|
|
49935
|
use Memoize qw( flush_cache memoize ); |
|
76
|
|
|
|
|
198681
|
|
|
76
|
|
|
|
|
5213
|
|
10
|
76
|
|
|
76
|
|
34929
|
use MooX::StrictConstructor; |
|
76
|
|
|
|
|
375069
|
|
|
76
|
|
|
|
|
486
|
|
11
|
76
|
|
|
76
|
|
346802
|
use PPI::Document (); |
|
76
|
|
|
|
|
8857483
|
|
|
76
|
|
|
|
|
3162
|
|
12
|
76
|
|
|
76
|
|
45505
|
use PPIx::Utils::Classification qw( is_function_call is_perl_builtin ); |
|
76
|
|
|
|
|
1064935
|
|
|
76
|
|
|
|
|
7821
|
|
13
|
76
|
|
|
76
|
|
42076
|
use Ref::Util qw( is_plain_arrayref is_plain_hashref ); |
|
76
|
|
|
|
|
46015
|
|
|
76
|
|
|
|
|
5812
|
|
14
|
76
|
|
|
76
|
|
1083
|
use Sub::HandlesVia; |
|
76
|
|
|
|
|
7220
|
|
|
76
|
|
|
|
|
971
|
|
15
|
76
|
|
|
76
|
|
212995
|
use Try::Tiny qw( catch try ); |
|
76
|
|
|
|
|
233
|
|
|
76
|
|
|
|
|
4699
|
|
16
|
76
|
|
|
76
|
|
591
|
use Types::Standard qw(ArrayRef Bool HashRef InstanceOf Maybe Object Str); |
|
76
|
|
|
|
|
274
|
|
|
76
|
|
|
|
|
889
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
with 'App::perlimports::Role::Logger'; |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
memoize('is_function_call'); |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub BUILD { |
23
|
50
|
|
|
50
|
0
|
239486
|
flush_cache('is_function_call'); |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
has _explicit_exports => ( |
27
|
|
|
|
|
|
|
is => 'ro', |
28
|
|
|
|
|
|
|
isa => HashRef, |
29
|
|
|
|
|
|
|
handles_via => 'Hash', |
30
|
|
|
|
|
|
|
handles => { |
31
|
|
|
|
|
|
|
_delete_export => 'delete', |
32
|
|
|
|
|
|
|
_explicit_export_count => 'count', |
33
|
|
|
|
|
|
|
_has_explicit_exports => 'count', |
34
|
|
|
|
|
|
|
_import_name => 'get', |
35
|
|
|
|
|
|
|
_is_importable => 'exists', |
36
|
|
|
|
|
|
|
}, |
37
|
|
|
|
|
|
|
lazy => 1, |
38
|
|
|
|
|
|
|
builder => '_build_explicit_exports', |
39
|
|
|
|
|
|
|
); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
has _document => ( |
42
|
|
|
|
|
|
|
is => 'ro', |
43
|
|
|
|
|
|
|
isa => InstanceOf ['App::perlimports::Document'], |
44
|
|
|
|
|
|
|
required => 1, |
45
|
|
|
|
|
|
|
init_arg => 'document', |
46
|
|
|
|
|
|
|
); |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
has _export_inspector => ( |
49
|
|
|
|
|
|
|
is => 'ro', |
50
|
|
|
|
|
|
|
isa => InstanceOf ['App::perlimports::ExportInspector'], |
51
|
|
|
|
|
|
|
predicate => '_has_export_inspector', # used in test |
52
|
|
|
|
|
|
|
lazy => 1, |
53
|
|
|
|
|
|
|
builder => '_build_export_inspector', |
54
|
|
|
|
|
|
|
); |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
has formatted_ppi_statement => ( |
57
|
|
|
|
|
|
|
is => 'ro', |
58
|
|
|
|
|
|
|
isa => InstanceOf ['PPI::Statement::Include'], |
59
|
|
|
|
|
|
|
lazy => 1, |
60
|
|
|
|
|
|
|
builder => '_build_formatted_ppi_statement', |
61
|
|
|
|
|
|
|
); |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
has _ignored_modules => ( |
64
|
|
|
|
|
|
|
is => 'ro', |
65
|
|
|
|
|
|
|
isa => ArrayRef, |
66
|
|
|
|
|
|
|
init_arg => 'ignored_modules', |
67
|
|
|
|
|
|
|
predicate => '_has_ignored_modules', |
68
|
|
|
|
|
|
|
); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
has _imports => ( |
71
|
|
|
|
|
|
|
is => 'ro', |
72
|
|
|
|
|
|
|
isa => ArrayRef, |
73
|
|
|
|
|
|
|
lazy => 1, |
74
|
|
|
|
|
|
|
builder => '_build_imports', |
75
|
|
|
|
|
|
|
); |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
has _include => ( |
78
|
|
|
|
|
|
|
is => 'ro', |
79
|
|
|
|
|
|
|
isa => InstanceOf ['PPI::Statement::Include'], |
80
|
|
|
|
|
|
|
init_arg => 'include', |
81
|
|
|
|
|
|
|
required => 1, |
82
|
|
|
|
|
|
|
); |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
has _is_ignored => ( |
85
|
|
|
|
|
|
|
is => 'ro', |
86
|
|
|
|
|
|
|
isa => Bool, |
87
|
|
|
|
|
|
|
lazy => 1, |
88
|
|
|
|
|
|
|
builder => '_build_is_ignored', |
89
|
|
|
|
|
|
|
); |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
has _isa_test_builder_module => ( |
92
|
|
|
|
|
|
|
is => 'ro', |
93
|
|
|
|
|
|
|
isa => Bool, |
94
|
|
|
|
|
|
|
lazy => 1, |
95
|
|
|
|
|
|
|
default => sub { shift->_export_inspector->isa_test_builder }, |
96
|
|
|
|
|
|
|
); |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
has _is_translatable => ( |
99
|
|
|
|
|
|
|
is => 'ro', |
100
|
|
|
|
|
|
|
isa => Bool, |
101
|
|
|
|
|
|
|
lazy => 1, |
102
|
|
|
|
|
|
|
builder => '_build_is_translatable', |
103
|
|
|
|
|
|
|
documentation => 'Is this a require which can be converted to a use?', |
104
|
|
|
|
|
|
|
); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
has module_name => ( |
107
|
|
|
|
|
|
|
is => 'ro', |
108
|
|
|
|
|
|
|
isa => Maybe [Str], |
109
|
|
|
|
|
|
|
lazy => 1, |
110
|
|
|
|
|
|
|
default => sub { shift->_include->module }, |
111
|
|
|
|
|
|
|
); |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
has _original_imports => ( |
114
|
|
|
|
|
|
|
is => 'ro', |
115
|
|
|
|
|
|
|
isa => Maybe [ArrayRef], |
116
|
|
|
|
|
|
|
init_arg => 'original_imports', |
117
|
|
|
|
|
|
|
handles_via => 'Array', |
118
|
|
|
|
|
|
|
handles => { |
119
|
|
|
|
|
|
|
_all_original_imports => 'elements', |
120
|
|
|
|
|
|
|
_has_original_imports => 'count', |
121
|
|
|
|
|
|
|
}, |
122
|
|
|
|
|
|
|
); |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
has _pad_imports => ( |
125
|
|
|
|
|
|
|
is => 'ro', |
126
|
|
|
|
|
|
|
isa => Bool, |
127
|
|
|
|
|
|
|
init_arg => 'pad_imports', |
128
|
|
|
|
|
|
|
default => sub { 1 }, |
129
|
|
|
|
|
|
|
); |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
has _tidy_whitespace => ( |
132
|
|
|
|
|
|
|
is => 'ro', |
133
|
|
|
|
|
|
|
isa => Bool, |
134
|
|
|
|
|
|
|
init_arg => 'tidy_whitespace', |
135
|
|
|
|
|
|
|
lazy => 1, |
136
|
|
|
|
|
|
|
default => sub { 1 }, |
137
|
|
|
|
|
|
|
); |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
has _will_never_export => ( |
140
|
|
|
|
|
|
|
is => 'ro', |
141
|
|
|
|
|
|
|
isa => Bool, |
142
|
|
|
|
|
|
|
lazy => 1, |
143
|
|
|
|
|
|
|
default => sub { |
144
|
|
|
|
|
|
|
my $self = shift; |
145
|
|
|
|
|
|
|
return exists $self->_document->never_exports->{ $self->module_name } |
146
|
|
|
|
|
|
|
|| $self->_export_inspector->is_oo_class; |
147
|
|
|
|
|
|
|
}, |
148
|
|
|
|
|
|
|
); |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub _build_export_inspector { |
151
|
49
|
|
|
49
|
|
4836
|
my $self = shift; |
152
|
49
|
|
|
|
|
975
|
return $self->_document->inspector_for( $self->module_name ); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# If we have implicit (but not explicit) exports, we will make a best guess at |
156
|
|
|
|
|
|
|
# what gets exported by using the implicit list. |
157
|
|
|
|
|
|
|
sub _build_explicit_exports { |
158
|
47
|
|
|
47
|
|
3736
|
my $self = shift; |
159
|
47
|
100
|
|
|
|
955
|
return $self->_export_inspector->has_explicit_exports |
160
|
|
|
|
|
|
|
? $self->_export_inspector->explicit_exports |
161
|
|
|
|
|
|
|
: $self->_export_inspector->implicit_exports; |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
## no critic (Subroutines::ProhibitExcessComplexity) |
165
|
|
|
|
|
|
|
sub _build_imports { |
166
|
47
|
|
|
47
|
|
3190
|
my $self = shift; |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# This is not a real symbol, so we should never be looking for it to appear |
169
|
|
|
|
|
|
|
# in the code. |
170
|
47
|
100
|
|
|
|
844
|
$self->_delete_export('verbose') if $self->module_name eq 'Carp'; |
171
|
|
|
|
|
|
|
|
172
|
47
|
|
|
|
|
1435
|
my %found; |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Stolen from Perl::Critic::Policy::TooMuchCode::ProhibitUnfoundImport |
175
|
47
|
|
|
|
|
110
|
for my $word ( @{ $self->_document->possible_imports } ) { |
|
47
|
|
|
|
|
1032
|
|
176
|
727
|
50
|
|
|
|
3738
|
next if exists $found{"$word"}; |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# No need to keep looking if we've found everything that can be |
179
|
|
|
|
|
|
|
# imported |
180
|
727
|
100
|
|
|
|
4093
|
last unless $self->_imports_remain( \%found ); |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# We don't want (for instance) pragma names to be confused with |
183
|
|
|
|
|
|
|
# functions. |
184
|
|
|
|
|
|
|
# |
185
|
|
|
|
|
|
|
# ie: |
186
|
|
|
|
|
|
|
# use warnings; |
187
|
|
|
|
|
|
|
# use Test::Warnings; # exports warnings() |
188
|
|
|
|
|
|
|
# |
189
|
|
|
|
|
|
|
# However, we also want to catch function calls in use statements, like |
190
|
|
|
|
|
|
|
# "use lib catfile( 't', 'lib');" |
191
|
|
|
|
|
|
|
# |
192
|
|
|
|
|
|
|
# or |
193
|
|
|
|
|
|
|
# |
194
|
|
|
|
|
|
|
# use Mojo::File qw( curfile ); |
195
|
|
|
|
|
|
|
# use lib curfile->sibling('lib')->to_string; |
196
|
723
|
|
|
|
|
22210
|
my $is_function_call = is_function_call($word); |
197
|
723
|
100
|
66
|
|
|
123378
|
if ( |
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
198
|
|
|
|
|
|
|
$word->parent |
199
|
|
|
|
|
|
|
&& $word->parent->isa('PPI::Statement::Include') |
200
|
|
|
|
|
|
|
&& ( !$is_function_call |
201
|
|
|
|
|
|
|
&& !( $word->snext_sibling && $word->snext_sibling eq '->' ) ) |
202
|
|
|
|
|
|
|
) { |
203
|
211
|
|
|
|
|
15143
|
next; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# Don't turn "use POSIX ();" into "use POSIX qw( sprintf );" |
207
|
|
|
|
|
|
|
# If it's a function and it's a builtin function and it's either not |
208
|
|
|
|
|
|
|
# included in original_imports or original imports are not implicit |
209
|
|
|
|
|
|
|
# then skip this. |
210
|
512
|
100
|
100
|
|
|
8201
|
if ( defined $self->_original_imports |
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
211
|
292
|
|
|
292
|
|
2066
|
&& ( none { $_ eq $word } @{ $self->_original_imports } ) |
|
236
|
|
|
|
|
972
|
|
212
|
|
|
|
|
|
|
&& $is_function_call |
213
|
|
|
|
|
|
|
&& is_perl_builtin($word) ) { |
214
|
129
|
|
|
|
|
4040
|
next; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
383
|
|
|
|
|
2665
|
my @found_import; |
218
|
383
|
|
|
|
|
1192
|
my $isa_symbol = $word->isa('PPI::Token::Symbol'); |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# Don't confuse my @Foo with a use of @Foo which is exported by a module. |
221
|
383
|
100
|
100
|
|
|
1083
|
if ( $isa_symbol && $word->content =~ m{\A(@|%|$)} ) { |
222
|
25
|
|
|
|
|
211
|
my $previous_sibling = $word->sprevious_sibling; |
223
|
25
|
100
|
66
|
|
|
675
|
if ( $previous_sibling && $previous_sibling->content eq 'my' ) { |
224
|
9
|
|
|
|
|
59
|
next; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# If a module exports %foo and we find $foo{bar}, $word->canonical |
229
|
|
|
|
|
|
|
# returns $foo and $word->symbol returns %foo |
230
|
374
|
100
|
100
|
|
|
2811
|
if ( $isa_symbol |
|
|
50
|
66
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
50
|
100
|
|
|
|
|
|
|
50
|
100
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
231
|
|
|
|
|
|
|
&& $self->_is_importable( $word->symbol ) ) { |
232
|
9
|
|
|
|
|
769
|
@found_import = ( $word->symbol ); |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
# Match on \&is_Str as is_Str |
236
|
|
|
|
|
|
|
elsif ($isa_symbol |
237
|
|
|
|
|
|
|
&& $word->symbol_type eq '&' |
238
|
|
|
|
|
|
|
&& $self->_is_importable( substr( $word->symbol, 1 ) ) ) { |
239
|
0
|
|
|
|
|
0
|
@found_import = ( substr( $word->symbol, 1 ) ); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# Don't catch ${foo} here and mistake it for "foo". We deal with that |
243
|
|
|
|
|
|
|
# elsewhere. Don't catch @{ split_header $str }. |
244
|
|
|
|
|
|
|
elsif ( |
245
|
|
|
|
|
|
|
$self->_is_importable("$word") |
246
|
|
|
|
|
|
|
&& !( |
247
|
|
|
|
|
|
|
$word =~ m{^\w} |
248
|
|
|
|
|
|
|
&& $word->previous_token |
249
|
|
|
|
|
|
|
&& $word->previous_token eq '{' |
250
|
|
|
|
|
|
|
&& $word->previous_token->previous_token |
251
|
|
|
|
|
|
|
&& $word->previous_token->previous_token eq '$' |
252
|
|
|
|
|
|
|
) |
253
|
|
|
|
|
|
|
) { |
254
|
41
|
|
|
|
|
19811
|
@found_import = ("$word"); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# Maybe a subroutine ref has been exported. For instance, |
258
|
|
|
|
|
|
|
# Getopt::Long exports &GetOptions |
259
|
|
|
|
|
|
|
elsif ($is_function_call |
260
|
|
|
|
|
|
|
&& $self->_is_importable( '&' . $word ) ) { |
261
|
1
|
|
|
|
|
41
|
@found_import = ( '&' . "$word" ); |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# Maybe this is an inner package referencing a function in main. We |
265
|
|
|
|
|
|
|
# don't really deal with inner packages otherwise, so this could break |
266
|
|
|
|
|
|
|
# some things. |
267
|
|
|
|
|
|
|
elsif ($is_function_call |
268
|
|
|
|
|
|
|
&& $word =~ m{^::\w+} |
269
|
|
|
|
|
|
|
&& $self->_is_importable( substr( $word, 2 ) ) ) { |
270
|
0
|
|
|
|
|
0
|
@found_import = ( substr( $word, 2 ) ); |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
# PPI can think that an imported function in a ternary is a label |
274
|
|
|
|
|
|
|
# my $foo = $enabled ? GEOIP_MEMORY_CACHE : 0; |
275
|
|
|
|
|
|
|
# The content of the $word will be "GEOIP_MEMORY_CACHE :" |
276
|
|
|
|
|
|
|
elsif ( $word->isa('PPI::Token::Label') ) { |
277
|
0
|
0
|
|
|
|
0
|
if ( $word->content =~ m{^(\w+)} ) { |
278
|
0
|
|
|
|
|
0
|
my $label = $1; |
279
|
0
|
0
|
|
|
|
0
|
if ( $self->_is_importable($label) ) { |
280
|
0
|
|
|
|
|
0
|
@found_import = ($label); |
281
|
0
|
|
|
|
|
0
|
$found{$label}++; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
# Sometimes an import is only used to set a default value for a |
287
|
|
|
|
|
|
|
# variable in a signature. Without treating a prototype as a signature, |
288
|
|
|
|
|
|
|
# we would miss the import entirely. I'm not particularly proud of |
289
|
|
|
|
|
|
|
# this, but since PPI doesn't yet support signatures, this will at |
290
|
|
|
|
|
|
|
# least help us cover some cases. If the prototype is actually a |
291
|
|
|
|
|
|
|
# prototype, then this just shouldn't find anything. |
292
|
|
|
|
|
|
|
elsif ( $word->isa('PPI::Token::Prototype') ) { |
293
|
0
|
|
|
|
|
0
|
my $prototype = $word->prototype; |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
# sometimes closing parens don't get included by PPI. |
296
|
0
|
0
|
|
|
|
0
|
if ( substr( $prototype, -1, 1 ) eq '(' ) { |
297
|
0
|
|
|
|
|
0
|
$prototype .= ')'; |
298
|
|
|
|
|
|
|
} |
299
|
0
|
|
|
|
|
0
|
$prototype =~ s{,}{;}g; |
300
|
|
|
|
|
|
|
|
301
|
0
|
|
|
|
|
0
|
$prototype .= ';'; # Won't hurt if there's an extra ";" |
302
|
0
|
|
|
|
|
0
|
my $new = PPI::Document->new( \$prototype ); |
303
|
|
|
|
|
|
|
my $words = $new->find( |
304
|
|
|
|
|
|
|
sub { |
305
|
0
|
|
|
0
|
|
0
|
$_[1]->isa('PPI::Token::Word') |
306
|
|
|
|
|
|
|
|| $_[1]->isa('PPI::Token::Symbol'); |
307
|
|
|
|
|
|
|
} |
308
|
0
|
|
0
|
|
|
0
|
) || []; |
309
|
0
|
|
|
|
|
0
|
for my $word ( @{$words} ) { |
|
0
|
|
|
|
|
0
|
|
310
|
0
|
0
|
|
|
|
0
|
if ( $self->_is_importable("$word") ) { |
311
|
0
|
|
|
|
|
0
|
push @found_import, "$word"; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
374
|
|
|
|
|
72251
|
for my $found (@found_import) { |
317
|
51
|
100
|
|
|
|
217
|
if ( !$self->_is_already_imported($found) ) { |
318
|
45
|
|
|
|
|
205
|
$found{$found}++; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# A used import might be a variable interpolated into quotes. |
324
|
47
|
100
|
|
|
|
487
|
if ( $self->_imports_remain( \%found ) ) { |
325
|
43
|
|
|
|
|
520
|
for my $var ( keys %{ $self->_document->interpolated_symbols } ) { |
|
43
|
|
|
|
|
1116
|
|
326
|
9
|
100
|
|
|
|
238
|
if ( $self->_is_importable($var) ) { |
327
|
6
|
|
|
|
|
139
|
$found{$var} = 1; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
} |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# A used import might be just be a symbol that just gets exported. ie. If |
333
|
|
|
|
|
|
|
# it appears as @EXPORT = ( 'SOME_SYMBOL') we don't want to miss it. |
334
|
47
|
50
|
100
|
|
|
1186
|
if ( $self->_imports_remain( \%found ) |
|
|
|
66
|
|
|
|
|
335
|
|
|
|
|
|
|
&& $self->_document->my_own_inspector |
336
|
|
|
|
|
|
|
&& $self->_document->my_own_inspector->is_exporter ) { |
337
|
0
|
|
|
|
|
0
|
for my $symbol ( |
338
|
|
|
|
|
|
|
uniq( |
339
|
|
|
|
|
|
|
$self->_document->my_own_inspector->implicit_export_names, |
340
|
|
|
|
|
|
|
$self->_document->my_own_inspector->explicit_export_names |
341
|
|
|
|
|
|
|
) |
342
|
|
|
|
|
|
|
) { |
343
|
0
|
0
|
|
|
|
0
|
if ( $self->_is_importable($symbol) ) { |
344
|
0
|
|
|
|
|
0
|
$found{$symbol} = 1; |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
} |
347
|
|
|
|
|
|
|
} |
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
# A used import might just be something that gets re-exported by |
350
|
|
|
|
|
|
|
# Sub::Exporter |
351
|
47
|
100
|
|
|
|
1826
|
if ( $self->_imports_remain( \%found ) ) { |
352
|
43
|
|
|
|
|
746
|
for my $func ( $self->_document->sub_exporter_export_list ) { |
353
|
2
|
100
|
|
|
|
38
|
if ( $self->_is_importable($func) ) { |
354
|
1
|
|
|
|
|
23
|
$found{$func}++; |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
|
359
|
47
|
|
|
|
|
1304
|
my @found = map { $self->_import_name($_) } keys %found; |
|
52
|
|
|
|
|
423
|
|
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
# Some modules have imports which are basically flags, rather than names of |
362
|
|
|
|
|
|
|
# symbols to export. So if a flag is already in the import, we need to |
363
|
|
|
|
|
|
|
# preserve it, rather than risk altering the behaviour of the module. |
364
|
47
|
100
|
|
|
|
1477
|
if ( $self->_export_inspector->has_import_flags ) { |
365
|
10
|
|
|
|
|
307
|
for my $arg ( @{ $self->_export_inspector->import_flags } ) { |
|
10
|
|
|
|
|
223
|
|
366
|
10
|
100
|
100
|
|
|
439
|
if ( defined $self->_original_imports |
367
|
9
|
|
|
9
|
|
49
|
&& ( any { $_ eq $arg } @{ $self->_original_imports } ) ) { |
|
6
|
|
|
|
|
35
|
|
368
|
3
|
|
|
|
|
19
|
push @found, $arg; |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
47
|
|
|
|
|
1228
|
@found = uniq _sort_symbols(@found); |
374
|
47
|
100
|
|
|
|
257
|
if ( $self->_original_imports ) { |
375
|
18
|
|
|
|
|
49
|
my @preserved = grep { m{\A[!_]} } @{ $self->_original_imports }; |
|
28
|
|
|
|
|
134
|
|
|
18
|
|
|
|
|
93
|
|
376
|
18
|
|
|
|
|
83
|
@found = uniq( @preserved, @found ); |
377
|
|
|
|
|
|
|
} |
378
|
47
|
|
|
|
|
1059
|
return \@found; |
379
|
|
|
|
|
|
|
} |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
## use critic |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub _build_is_ignored { |
384
|
50
|
|
|
50
|
|
4289
|
my $self = shift; |
385
|
|
|
|
|
|
|
|
386
|
50
|
50
|
|
|
|
325
|
if ( $self->_include->type eq 'require' ) { |
387
|
0
|
0
|
|
|
|
0
|
return 1 if !$self->_is_translatable; |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
# This will be rewritten as "use Foo ();" |
391
|
50
|
100
|
|
|
|
2717
|
return 0 if $self->_will_never_export; |
392
|
|
|
|
|
|
|
|
393
|
49
|
50
|
|
|
|
6185
|
return 1 if $self->_export_inspector->has_fatal_error; |
394
|
|
|
|
|
|
|
|
395
|
49
|
50
|
|
|
|
4815
|
return 0 if $self->_export_inspector->is_oo_class; |
396
|
|
|
|
|
|
|
|
397
|
49
|
100
|
|
|
|
2226
|
return 1 if $self->_export_inspector->is_moose_class; |
398
|
|
|
|
|
|
|
|
399
|
48
|
50
|
|
|
|
6235
|
return 1 if $self->_export_inspector->uses_moose; |
400
|
|
|
|
|
|
|
|
401
|
48
|
50
|
|
|
|
4551
|
return 1 if $self->_export_inspector->is_moo_class; |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
return 1 |
404
|
48
|
100
|
|
1
|
|
1857
|
if any { $_ eq 'Moo::Object' } @{ $self->_export_inspector->pkg_isa }; |
|
1
|
|
|
|
|
53
|
|
|
48
|
|
|
|
|
1018
|
|
405
|
|
|
|
|
|
|
|
406
|
47
|
|
|
|
|
2452
|
return 0; |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub _build_is_translatable { |
410
|
47
|
|
|
47
|
|
1844
|
my $self = shift; |
411
|
|
|
|
|
|
|
|
412
|
47
|
50
|
|
|
|
276
|
return 0 if !$self->_include->type; |
413
|
47
|
50
|
|
|
|
1436
|
return 0 if $self->_include->type ne 'require'; |
414
|
0
|
0
|
|
|
|
0
|
return 0 if $self->module_name eq 'Exporter'; |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
# We can deal with a top level require. |
417
|
|
|
|
|
|
|
# require Foo; can be changed to use Foo (); |
418
|
|
|
|
|
|
|
# We don't want to touch requires which are inside any kind of a condition. |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
# If there is no parent, then it's likely just a single snippet |
421
|
|
|
|
|
|
|
# provided by a text editor. We can process the snippet. If it's part |
422
|
|
|
|
|
|
|
# of a larger document and the parent is not a PPI::Document, this |
423
|
|
|
|
|
|
|
# would appear not to be a top level require. |
424
|
0
|
0
|
0
|
|
|
0
|
if ( $self->_include->parent |
425
|
|
|
|
|
|
|
&& !$self->_include->parent->isa('PPI::Document') ) { |
426
|
0
|
|
|
|
|
0
|
return 0; |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
# Postfix conditions are a bit harder to find. If the significant |
430
|
|
|
|
|
|
|
# children amount to more than "require Module;", we'll just move on. |
431
|
0
|
|
|
|
|
0
|
my @children = $self->_include->schildren; |
432
|
|
|
|
|
|
|
|
433
|
0
|
|
|
|
|
0
|
my $statement = join q{ }, @children[ 0 .. 2 ]; |
434
|
0
|
0
|
|
|
|
0
|
if ( $statement ne 'require ' . $self->module_name . ' ;' ) { |
435
|
0
|
|
|
|
|
0
|
return 0; |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
# Any other case of "require Foo;" should be translated to "use Foo ();" |
439
|
|
|
|
|
|
|
# as those are functionally equivalent. |
440
|
0
|
|
|
|
|
0
|
return 1; |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
## no critic (Subroutines::ProhibitExcessComplexity) |
444
|
|
|
|
|
|
|
sub _build_formatted_ppi_statement { |
445
|
50
|
|
|
50
|
|
7653
|
my $self = shift; |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
# The following steps may seem a bit out of order, but we're trying to |
448
|
|
|
|
|
|
|
# short circuit if at all possible. That means not building an |
449
|
|
|
|
|
|
|
# ExportInspector object unless we really need to. |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
# Nothing to do here. Preserve the original statement. |
452
|
50
|
100
|
|
|
|
977
|
return $self->_include if $self->_is_ignored; |
453
|
|
|
|
|
|
|
|
454
|
48
|
50
|
|
|
|
1785
|
my $maybe_module_version |
455
|
|
|
|
|
|
|
= $self->_include->module_version |
456
|
|
|
|
|
|
|
? q{ } . $self->_include->module_version |
457
|
|
|
|
|
|
|
: q{}; |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
# In this case we either have a module which we know will never export |
460
|
|
|
|
|
|
|
# symbols or a module which can export but for which we haven't found any |
461
|
|
|
|
|
|
|
# imported symbols. In both cases we'll want to rewrite with an empty list |
462
|
|
|
|
|
|
|
# of imports. |
463
|
48
|
100
|
66
|
|
|
4267
|
if ( $self->_will_never_export |
|
|
|
100
|
|
|
|
|
464
|
|
|
|
|
|
|
|| $self->_is_translatable |
465
|
47
|
|
|
|
|
3997
|
|| !@{ $self->_imports } ) { |
466
|
15
|
|
|
|
|
671
|
return $self->_maybe_get_new_include( |
467
|
|
|
|
|
|
|
sprintf( |
468
|
|
|
|
|
|
|
'use %s%s ();', $self->module_name, $maybe_module_version |
469
|
|
|
|
|
|
|
) |
470
|
|
|
|
|
|
|
); |
471
|
|
|
|
|
|
|
} |
472
|
|
|
|
|
|
|
|
473
|
33
|
|
|
|
|
1102
|
my $statement; |
474
|
|
|
|
|
|
|
|
475
|
33
|
|
|
|
|
238
|
my @args = $self->_include->arguments; |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
# Don't touch a do { } block. |
478
|
33
|
100
|
100
|
|
|
2083
|
if ( $self->_isa_test_builder_module && @args && $args[0] eq 'do' ) { |
|
|
|
66
|
|
|
|
|
479
|
1
|
|
|
|
|
113
|
return $self->_include; |
480
|
|
|
|
|
|
|
} |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
# Do some contortions to turn PPI objects back into a data structure so |
483
|
|
|
|
|
|
|
# that we can add or replace an import hash key and then end up with a new |
484
|
|
|
|
|
|
|
# list which is sorted on hash keys. This makes the assumption that the |
485
|
|
|
|
|
|
|
# same key won't get passed twice. This is pretty gross, but I was too lazy |
486
|
|
|
|
|
|
|
# to try to figure out how to do this with PPI and I think it should |
487
|
|
|
|
|
|
|
# *mostly* work. I don't like the formatting that Data::Dumper comes up |
488
|
|
|
|
|
|
|
# with, so we'll run it through perltidy. |
489
|
|
|
|
|
|
|
|
490
|
32
|
50
|
66
|
|
|
2695
|
if ( $self->_isa_test_builder_module |
491
|
|
|
|
|
|
|
&& @args ) { |
492
|
0
|
|
|
|
|
0
|
my $all; |
493
|
|
|
|
|
|
|
|
494
|
0
|
0
|
0
|
|
|
0
|
if ( $args[0]->isa('PPI::Token::Word') ) { |
|
|
0
|
|
|
|
|
|
495
|
0
|
|
|
|
|
0
|
$all = join q{ }, map { "$_" } @args; |
|
0
|
|
|
|
|
0
|
|
496
|
|
|
|
|
|
|
} |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
elsif ($args[0]->isa('PPI::Structure::List') |
499
|
|
|
|
|
|
|
&& $args[0]->braces eq '()' ) { |
500
|
0
|
|
|
|
|
0
|
for my $child ( $args[0]->children ) { |
501
|
0
|
|
|
|
|
0
|
$all .= "$child"; |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
## no critic (BuiltinFunctions::ProhibitStringyEval) |
506
|
0
|
|
|
|
|
0
|
my $args; |
507
|
|
|
|
|
|
|
my $error; |
508
|
|
|
|
|
|
|
try { |
509
|
0
|
|
|
0
|
|
0
|
$args = eval( '{' . $all . '}' ); |
510
|
|
|
|
|
|
|
} |
511
|
|
|
|
|
|
|
catch { |
512
|
0
|
|
|
0
|
|
0
|
$self->logger->info($_); |
513
|
0
|
|
|
|
|
0
|
$error = 1; |
514
|
0
|
|
|
|
|
0
|
}; |
515
|
|
|
|
|
|
|
## use critic |
516
|
|
|
|
|
|
|
|
517
|
0
|
0
|
0
|
|
|
0
|
if ( !$error && !is_plain_hashref($args) ) { |
518
|
0
|
|
|
|
|
0
|
$self->logger->info( 'Not a hashref: ' . Dumper($args) ); |
519
|
0
|
|
|
|
|
0
|
$error = 1; |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
# We will replace these with our own parsed imports. |
523
|
0
|
|
|
|
|
0
|
delete $args->{import}; |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
# Ignore this line if we can't parse it. This will happen if the arg to |
526
|
|
|
|
|
|
|
# test is a do block, for example. |
527
|
0
|
0
|
|
|
|
0
|
return $self->_include if $error; |
528
|
|
|
|
|
|
|
|
529
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Terse = 1; |
530
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Indent = 0; |
531
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Sortkeys = 1; |
532
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Quotekeys = 0; |
533
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Useqq = 0; |
534
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Trailingcomma = 1; |
535
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Deparse = 1; |
536
|
|
|
|
|
|
|
|
537
|
0
|
|
|
|
|
0
|
my $dumped = Dumper($args); |
538
|
0
|
|
|
|
|
0
|
my $non_import_args; |
539
|
|
|
|
|
|
|
my $import_arg; |
540
|
|
|
|
|
|
|
|
541
|
0
|
0
|
|
|
|
0
|
if ( $dumped =~ m/^{(.*)}$/ ) { |
542
|
0
|
|
|
|
|
0
|
$non_import_args = $1; |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
|
545
|
0
|
0
|
|
|
|
0
|
if ( $self->_imports ) { |
546
|
|
|
|
|
|
|
$import_arg = sprintf( |
547
|
|
|
|
|
|
|
'import => [qw( %s )]', |
548
|
0
|
|
|
|
|
0
|
join( q{ }, @{ $self->_imports } ) |
|
0
|
|
|
|
|
0
|
|
549
|
|
|
|
|
|
|
); |
550
|
|
|
|
|
|
|
} |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
my $all_args = join ', ', |
553
|
0
|
0
|
|
|
|
0
|
grep { $_ && $_ =~ m{\w} } ( $import_arg, $non_import_args ); |
|
0
|
|
|
|
|
0
|
|
554
|
|
|
|
|
|
|
|
555
|
0
|
|
|
|
|
0
|
$statement = sprintf( |
556
|
|
|
|
|
|
|
'use %s%s %s;', |
557
|
|
|
|
|
|
|
$self->module_name, |
558
|
|
|
|
|
|
|
$maybe_module_version, |
559
|
|
|
|
|
|
|
$all_args |
560
|
|
|
|
|
|
|
); |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
# save ~60ms in cases where we don't need Perl::Tidy |
563
|
0
|
|
|
|
|
0
|
require Perl::Tidy; ## no perlimports |
564
|
0
|
|
|
|
|
0
|
Perl::Tidy::perltidy( |
565
|
|
|
|
|
|
|
argv => '-npro', |
566
|
|
|
|
|
|
|
source => \$statement, |
567
|
|
|
|
|
|
|
destination => \$statement |
568
|
|
|
|
|
|
|
); |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
else { |
572
|
32
|
100
|
|
|
|
634
|
my $padding = $self->_pad_imports ? q{ } : q{}; |
573
|
32
|
100
|
|
|
|
631
|
my $template |
574
|
|
|
|
|
|
|
= $self->_isa_test_builder_module |
575
|
|
|
|
|
|
|
? 'use %s%s import => [ qw(%s%s%s) ];' |
576
|
|
|
|
|
|
|
: 'use %s%s qw(%s%s%s);'; |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
$statement = sprintf( |
579
|
|
|
|
|
|
|
$template, |
580
|
|
|
|
|
|
|
$self->module_name, |
581
|
|
|
|
|
|
|
$maybe_module_version, |
582
|
|
|
|
|
|
|
$padding, |
583
|
|
|
|
|
|
|
join( |
584
|
|
|
|
|
|
|
q{ }, |
585
|
32
|
|
|
|
|
927
|
@{ $self->_imports } |
|
32
|
|
|
|
|
800
|
|
586
|
|
|
|
|
|
|
), |
587
|
|
|
|
|
|
|
$padding, |
588
|
|
|
|
|
|
|
); |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
# Don't deal with Test::Builder classes here to keep it simple for now |
592
|
32
|
50
|
33
|
|
|
595
|
if ( length($statement) > 78 && !$self->_isa_test_builder_module ) { |
593
|
0
|
|
|
|
|
0
|
$statement = sprintf( |
594
|
|
|
|
|
|
|
"use %s%s qw(\n", |
595
|
|
|
|
|
|
|
$self->module_name, |
596
|
|
|
|
|
|
|
$maybe_module_version, |
597
|
|
|
|
|
|
|
); |
598
|
0
|
|
|
|
|
0
|
for ( @{ $self->_imports } ) { |
|
0
|
|
|
|
|
0
|
|
599
|
0
|
|
|
|
|
0
|
$statement .= " $_\n"; |
600
|
|
|
|
|
|
|
} |
601
|
0
|
|
|
|
|
0
|
$statement .= ');'; |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
|
604
|
32
|
|
|
|
|
190
|
return $self->_maybe_get_new_include($statement); |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
## use critic |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
sub _imports_remain { |
610
|
868
|
|
|
868
|
|
1432
|
my $self = shift; |
611
|
868
|
|
|
|
|
1288
|
my $found = shift; |
612
|
868
|
|
|
|
|
1622
|
return keys %{$found} < $self->_explicit_export_count; |
|
868
|
|
|
|
|
2632
|
|
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
sub _maybe_get_new_include { |
616
|
47
|
|
|
47
|
|
293
|
my $self = shift; |
617
|
47
|
|
|
|
|
94
|
my $statement = shift; |
618
|
47
|
|
|
|
|
376
|
my $doc = PPI::Document->new( \$statement ); |
619
|
|
|
|
|
|
|
my $includes |
620
|
47
|
|
|
389
|
|
73935
|
= $doc->find( sub { $_[1]->isa('PPI::Statement::Include'); } ); |
|
389
|
|
|
|
|
5475
|
|
621
|
47
|
|
|
|
|
988
|
my $rewrite = $includes->[0]->clone; |
622
|
|
|
|
|
|
|
|
623
|
47
|
|
|
|
|
6752
|
my $a = $self->_include . q{}; |
624
|
47
|
|
|
|
|
1459
|
my $b = $rewrite . q{}; |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
# If the only difference is some whitespace before the quotes, we'll not |
627
|
|
|
|
|
|
|
# alter the include. This reduces some of the churn. What we want to avoid |
628
|
|
|
|
|
|
|
# is rewriting imports where the only change is to remove some whitespace |
629
|
|
|
|
|
|
|
# padding which was specifically added by perltidy. If we keep removing |
630
|
|
|
|
|
|
|
# changes made by perltidy this tool will be unfit to be used as a linter, |
631
|
|
|
|
|
|
|
# because it will either force a tidy after every run or it will introduce |
632
|
|
|
|
|
|
|
# tidying errors. |
633
|
|
|
|
|
|
|
# |
634
|
|
|
|
|
|
|
# So "use Foo qw( bar );" should be considered equivalent to |
635
|
|
|
|
|
|
|
# "use Foo qw( bar );" because it might be in the context of |
636
|
|
|
|
|
|
|
# |
637
|
|
|
|
|
|
|
# use AAAAAAA qw( thing ); |
638
|
|
|
|
|
|
|
# use Foo qw( bar ); |
639
|
|
|
|
|
|
|
# use FFFFFFF qw( other ); |
640
|
|
|
|
|
|
|
# |
641
|
|
|
|
|
|
|
# If the existing include is something like |
642
|
|
|
|
|
|
|
# "use Foo 123 qw( foo );" |
643
|
|
|
|
|
|
|
# we should probably rewrite that since perltidy will likely rewrite |
644
|
|
|
|
|
|
|
# this to |
645
|
|
|
|
|
|
|
# "use Foo 123 qw( foo );" |
646
|
|
|
|
|
|
|
|
647
|
47
|
|
|
|
|
1645
|
my $orig = $a; |
648
|
47
|
100
|
|
|
|
221
|
if ( _respace_include($orig) eq $b ) { |
649
|
14
|
|
|
|
|
103
|
return $self->_include; |
650
|
|
|
|
|
|
|
} |
651
|
|
|
|
|
|
|
|
652
|
33
|
100
|
|
|
|
940
|
return $rewrite if $self->_tidy_whitespace; |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
# We will return the rewritten include if a newline has been added or |
655
|
|
|
|
|
|
|
# removed. This is a formatting change that we *probably* want. |
656
|
|
|
|
|
|
|
|
657
|
4
|
|
|
|
|
52
|
$a =~ s{\s}{}g; |
658
|
4
|
|
|
|
|
17
|
$b =~ s{\s}{}g; |
659
|
|
|
|
|
|
|
|
660
|
4
|
50
|
|
|
|
24
|
return ( $a eq $b ) ? $self->_include : $rewrite; |
661
|
|
|
|
|
|
|
} |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
# This function takes the original include and strips away the extra spaces |
664
|
|
|
|
|
|
|
# which might have been added as formatting by perltidy. This makes it easier |
665
|
|
|
|
|
|
|
# to compare the old include with the new and decide if we really need to |
666
|
|
|
|
|
|
|
# replace it. |
667
|
|
|
|
|
|
|
sub _respace_include { |
668
|
50
|
|
|
50
|
|
1879
|
my $include = shift; |
669
|
50
|
|
|
|
|
451
|
$include =~ s{\s+(qw|\()}{ $1}; |
670
|
50
|
|
|
|
|
251
|
return $include; |
671
|
|
|
|
|
|
|
} |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
# If there's a different module in this document which has already imported |
674
|
|
|
|
|
|
|
# a symbol of the same name in its original imports, the we should make |
675
|
|
|
|
|
|
|
# sure we don't accidentally create a duplicate import here. For example, |
676
|
|
|
|
|
|
|
# Path::Tiny and Test::TempDir::Tiny both export a tempdir() function. |
677
|
|
|
|
|
|
|
# Without this check we'd add a "tempdir" to both modules if we find it |
678
|
|
|
|
|
|
|
# being used in the document. |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
sub _is_already_imported { |
681
|
51
|
|
|
51
|
|
116
|
my $self = shift; |
682
|
51
|
|
|
|
|
101
|
my $symbol = shift; |
683
|
51
|
|
|
|
|
94
|
my $duplicate = 0; |
684
|
|
|
|
|
|
|
|
685
|
51
|
|
|
|
|
94
|
foreach my $module ( |
686
|
98
|
|
|
|
|
2388
|
grep { $_ ne $self->module_name } |
687
|
51
|
|
|
|
|
1299
|
keys %{ $self->_document->original_imports } |
688
|
|
|
|
|
|
|
) { |
689
|
47
|
|
|
|
|
468
|
$self->logger->debug( |
690
|
|
|
|
|
|
|
"checking $module for previous imports of $symbol"); |
691
|
47
|
|
|
|
|
3042
|
my @imports; |
692
|
47
|
100
|
|
|
|
1026
|
if ( |
693
|
|
|
|
|
|
|
is_plain_arrayref( |
694
|
|
|
|
|
|
|
$self->_document->original_imports->{$module} |
695
|
|
|
|
|
|
|
) |
696
|
|
|
|
|
|
|
) { |
697
|
27
|
|
|
|
|
269
|
@imports = @{ $self->_document->original_imports->{$module} }; |
|
27
|
|
|
|
|
486
|
|
698
|
27
|
|
|
|
|
342
|
$self->logger->debug( |
699
|
|
|
|
|
|
|
'Explicit imports found: ' . Dumper( [ sort @imports ] ) ); |
700
|
|
|
|
|
|
|
} |
701
|
|
|
|
|
|
|
else { |
702
|
20
|
50
|
|
|
|
262
|
if ( my $inspector = $self->_document->inspector_for($module) ) { |
703
|
20
|
|
|
|
|
288
|
@imports = $inspector->implicit_export_names; |
704
|
20
|
|
|
|
|
530
|
$self->logger->debug( 'Implicit imports found: ' |
705
|
|
|
|
|
|
|
. Dumper( [ sort @imports ] ) ); |
706
|
|
|
|
|
|
|
} |
707
|
|
|
|
|
|
|
} |
708
|
|
|
|
|
|
|
|
709
|
47
|
100
|
|
298
|
|
6950
|
if ( any { $_ eq $symbol } @imports ) { |
|
298
|
|
|
|
|
474
|
|
710
|
6
|
|
|
|
|
12
|
$duplicate = 1; |
711
|
6
|
|
|
|
|
37
|
$self->logger->debug("$symbol already imported via $module"); |
712
|
6
|
|
|
|
|
232
|
last; |
713
|
|
|
|
|
|
|
} |
714
|
|
|
|
|
|
|
} |
715
|
|
|
|
|
|
|
|
716
|
51
|
|
|
|
|
495
|
return $duplicate; |
717
|
|
|
|
|
|
|
} |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
sub _sort_symbols { |
720
|
47
|
|
|
47
|
|
160
|
my @list = @_; |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
## no critic (BuiltinFunctions::RequireSimpleSortBlock) |
723
|
|
|
|
|
|
|
my @sorted = sort { |
724
|
47
|
|
|
|
|
206
|
my $A = _transform_before_cmp($a); |
|
27
|
|
|
|
|
82
|
|
725
|
27
|
|
|
|
|
73
|
my $B = _transform_before_cmp($b); |
726
|
27
|
|
|
|
|
137
|
"\L$A" cmp "\L$B"; |
727
|
|
|
|
|
|
|
} @list; |
728
|
47
|
|
|
|
|
272
|
return @sorted; |
729
|
|
|
|
|
|
|
} |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
# This looks a little weird, but basically we want to maintain a stable sort |
732
|
|
|
|
|
|
|
# order with lists that look like (foo, $foo, @foo, %foo). We use "-" to begin |
733
|
|
|
|
|
|
|
# the suffix because it comes earliest in a sorted list of letters and digits. |
734
|
|
|
|
|
|
|
sub _transform_before_cmp { |
735
|
54
|
|
|
54
|
|
93
|
my $thing = shift; |
736
|
54
|
100
|
|
|
|
261
|
if ( $thing =~ m{\A[\$]} ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
737
|
11
|
|
|
|
|
29
|
$thing = substr( $thing, 1 ) . '-0'; |
738
|
|
|
|
|
|
|
} |
739
|
|
|
|
|
|
|
elsif ( $thing =~ m{\A[@]} ) { |
740
|
7
|
|
|
|
|
30
|
$thing = substr( $thing, 1 ) . '-1'; |
741
|
|
|
|
|
|
|
} |
742
|
|
|
|
|
|
|
elsif ( $thing =~ m{\A[%]} ) { |
743
|
7
|
|
|
|
|
40
|
$thing = substr( $thing, 1 ) . '-2'; |
744
|
|
|
|
|
|
|
} |
745
|
54
|
|
|
|
|
124
|
return $thing; |
746
|
|
|
|
|
|
|
} |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
1; |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
# ABSTRACT: Encapsulate one use statement in a document |
751
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
__END__ |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
=pod |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
=encoding UTF-8 |
757
|
|
|
|
|
|
|
|
758
|
|
|
|
|
|
|
=head1 NAME |
759
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
App::perlimports::Include - Encapsulate one use statement in a document |
761
|
|
|
|
|
|
|
|
762
|
|
|
|
|
|
|
=head1 VERSION |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
version 0.000052 |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
=head1 METHODS |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
=head2 formatted_ppi_statement |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
Returns an L<PPI::Statement::Include> object. This can be stringified into an |
771
|
|
|
|
|
|
|
import statement or used to replace an existing L<PPI::Statement::Include>. |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
=head1 AUTHOR |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
Olaf Alders <olaf@wundercounter.com> |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
This software is copyright (c) 2020 by Olaf Alders. |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
782
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
=cut |