| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package App::perlimports::Include; |
|
2
|
|
|
|
|
|
|
|
|
3
|
74
|
|
|
74
|
|
1728
|
use Moo; |
|
|
74
|
|
|
|
|
9071
|
|
|
|
74
|
|
|
|
|
679
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
our $VERSION = '0.000051'; |
|
6
|
|
|
|
|
|
|
|
|
7
|
74
|
|
|
74
|
|
69892
|
use Data::Dumper qw( Dumper ); |
|
|
74
|
|
|
|
|
405635
|
|
|
|
74
|
|
|
|
|
6357
|
|
|
8
|
74
|
|
|
74
|
|
666
|
use List::Util qw( any none uniq ); |
|
|
74
|
|
|
|
|
218
|
|
|
|
74
|
|
|
|
|
6402
|
|
|
9
|
74
|
|
|
74
|
|
48608
|
use Memoize qw( flush_cache memoize ); |
|
|
74
|
|
|
|
|
188780
|
|
|
|
74
|
|
|
|
|
4782
|
|
|
10
|
74
|
|
|
74
|
|
31741
|
use MooX::StrictConstructor; |
|
|
74
|
|
|
|
|
358627
|
|
|
|
74
|
|
|
|
|
454
|
|
|
11
|
74
|
|
|
74
|
|
331578
|
use PPI::Document (); |
|
|
74
|
|
|
|
|
8413621
|
|
|
|
74
|
|
|
|
|
2991
|
|
|
12
|
74
|
|
|
74
|
|
43637
|
use PPIx::Utils::Classification qw( is_function_call is_perl_builtin ); |
|
|
74
|
|
|
|
|
1012081
|
|
|
|
74
|
|
|
|
|
7055
|
|
|
13
|
74
|
|
|
74
|
|
38910
|
use Ref::Util qw( is_plain_arrayref is_plain_hashref ); |
|
|
74
|
|
|
|
|
43936
|
|
|
|
74
|
|
|
|
|
5226
|
|
|
14
|
74
|
|
|
74
|
|
1162
|
use Sub::HandlesVia; |
|
|
74
|
|
|
|
|
7265
|
|
|
|
74
|
|
|
|
|
987
|
|
|
15
|
74
|
|
|
74
|
|
213906
|
use Try::Tiny qw( catch try ); |
|
|
74
|
|
|
|
|
248
|
|
|
|
74
|
|
|
|
|
4461
|
|
|
16
|
74
|
|
|
74
|
|
552
|
use Types::Standard qw(ArrayRef Bool HashRef InstanceOf Maybe Object Str); |
|
|
74
|
|
|
|
|
217
|
|
|
|
74
|
|
|
|
|
838
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
with 'App::perlimports::Role::Logger'; |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
memoize('is_function_call'); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub BUILD { |
|
23
|
50
|
|
|
50
|
0
|
233232
|
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
|
|
5019
|
my $self = shift; |
|
152
|
49
|
|
|
|
|
959
|
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
|
|
3689
|
my $self = shift; |
|
159
|
47
|
100
|
|
|
|
922
|
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
|
|
3161
|
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
|
|
|
|
847
|
$self->_delete_export('verbose') if $self->module_name eq 'Carp'; |
|
171
|
|
|
|
|
|
|
|
|
172
|
47
|
|
|
|
|
1396
|
my %found; |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Stolen from Perl::Critic::Policy::TooMuchCode::ProhibitUnfoundImport |
|
175
|
47
|
|
|
|
|
131
|
for my $word ( @{ $self->_document->possible_imports } ) { |
|
|
47
|
|
|
|
|
1031
|
|
|
176
|
726
|
50
|
|
|
|
3313
|
next if exists $found{"$word"}; |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# No need to keep looking if we've found everything that can be |
|
179
|
|
|
|
|
|
|
# imported |
|
180
|
726
|
100
|
|
|
|
4161
|
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
|
722
|
|
|
|
|
21852
|
my $is_function_call = is_function_call($word); |
|
197
|
722
|
100
|
66
|
|
|
123076
|
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
|
210
|
|
|
|
|
15100
|
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
|
|
|
8192
|
if ( defined $self->_original_imports |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
211
|
292
|
|
|
292
|
|
2067
|
&& ( none { $_ eq $word } @{ $self->_original_imports } ) |
|
|
236
|
|
|
|
|
946
|
|
|
212
|
|
|
|
|
|
|
&& $is_function_call |
|
213
|
|
|
|
|
|
|
&& is_perl_builtin($word) ) { |
|
214
|
129
|
|
|
|
|
4082
|
next; |
|
215
|
|
|
|
|
|
|
} |
|
216
|
|
|
|
|
|
|
|
|
217
|
383
|
|
|
|
|
2689
|
my @found_import; |
|
218
|
383
|
|
|
|
|
1254
|
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
|
|
|
1112
|
if ( $isa_symbol && $word->content =~ m{\A(@|%|$)} ) { |
|
222
|
25
|
|
|
|
|
226
|
my $previous_sibling = $word->sprevious_sibling; |
|
223
|
25
|
100
|
66
|
|
|
722
|
if ( $previous_sibling && $previous_sibling->content eq 'my' ) { |
|
224
|
9
|
|
|
|
|
60
|
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
|
|
|
2319
|
if ( $isa_symbol |
|
|
|
50
|
66
|
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
50
|
100
|
|
|
|
|
|
|
|
50
|
100
|
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
231
|
|
|
|
|
|
|
&& $self->_is_importable( $word->symbol ) ) { |
|
232
|
9
|
|
|
|
|
774
|
@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
|
|
|
|
|
17841
|
@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
|
|
|
|
|
53
|
@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
|
|
|
|
|
71653
|
for my $found (@found_import) { |
|
317
|
51
|
100
|
|
|
|
215
|
if ( !$self->_is_already_imported($found) ) { |
|
318
|
45
|
|
|
|
|
181
|
$found{$found}++; |
|
319
|
|
|
|
|
|
|
} |
|
320
|
|
|
|
|
|
|
} |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# A used import might be a variable interpolated into quotes. |
|
324
|
47
|
100
|
|
|
|
491
|
if ( $self->_imports_remain( \%found ) ) { |
|
325
|
43
|
|
|
|
|
492
|
for my $var ( keys %{ $self->_document->interpolated_symbols } ) { |
|
|
43
|
|
|
|
|
1212
|
|
|
326
|
9
|
100
|
|
|
|
285
|
if ( $self->_is_importable($var) ) { |
|
327
|
6
|
|
|
|
|
174
|
$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
|
|
|
1257
|
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
|
|
|
|
1906
|
if ( $self->_imports_remain( \%found ) ) { |
|
352
|
43
|
|
|
|
|
938
|
for my $func ( $self->_document->sub_exporter_export_list ) { |
|
353
|
2
|
100
|
|
|
|
37
|
if ( $self->_is_importable($func) ) { |
|
354
|
1
|
|
|
|
|
30
|
$found{$func}++; |
|
355
|
|
|
|
|
|
|
} |
|
356
|
|
|
|
|
|
|
} |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
|
|
359
|
47
|
|
|
|
|
1336
|
my @found = map { $self->_import_name($_) } keys %found; |
|
|
52
|
|
|
|
|
430
|
|
|
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
|
|
|
|
1434
|
if ( $self->_export_inspector->has_import_flags ) { |
|
365
|
10
|
|
|
|
|
308
|
for my $arg ( @{ $self->_export_inspector->import_flags } ) { |
|
|
10
|
|
|
|
|
222
|
|
|
366
|
10
|
100
|
100
|
|
|
539
|
if ( defined $self->_original_imports |
|
367
|
9
|
|
|
9
|
|
50
|
&& ( any { $_ eq $arg } @{ $self->_original_imports } ) ) { |
|
|
6
|
|
|
|
|
37
|
|
|
368
|
3
|
|
|
|
|
19
|
push @found, $arg; |
|
369
|
|
|
|
|
|
|
} |
|
370
|
|
|
|
|
|
|
} |
|
371
|
|
|
|
|
|
|
} |
|
372
|
|
|
|
|
|
|
|
|
373
|
47
|
|
|
|
|
1236
|
@found = uniq _sort_symbols(@found); |
|
374
|
47
|
100
|
|
|
|
286
|
if ( $self->_original_imports ) { |
|
375
|
18
|
|
|
|
|
43
|
my @preserved = grep { m{\A[!_]} } @{ $self->_original_imports }; |
|
|
28
|
|
|
|
|
111
|
|
|
|
18
|
|
|
|
|
64
|
|
|
376
|
18
|
|
|
|
|
100
|
@found = uniq( @preserved, @found ); |
|
377
|
|
|
|
|
|
|
} |
|
378
|
47
|
|
|
|
|
1120
|
return \@found; |
|
379
|
|
|
|
|
|
|
} |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
## use critic |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub _build_is_ignored { |
|
384
|
50
|
|
|
50
|
|
3728
|
my $self = shift; |
|
385
|
|
|
|
|
|
|
|
|
386
|
50
|
50
|
|
|
|
298
|
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
|
|
|
|
2589
|
return 0 if $self->_will_never_export; |
|
392
|
|
|
|
|
|
|
|
|
393
|
49
|
50
|
|
|
|
6065
|
return 1 if $self->_export_inspector->has_fatal_error; |
|
394
|
|
|
|
|
|
|
|
|
395
|
49
|
50
|
|
|
|
5068
|
return 0 if $self->_export_inspector->is_oo_class; |
|
396
|
|
|
|
|
|
|
|
|
397
|
49
|
100
|
|
|
|
2241
|
return 1 if $self->_export_inspector->is_moose_class; |
|
398
|
|
|
|
|
|
|
|
|
399
|
48
|
50
|
|
|
|
6195
|
return 1 if $self->_export_inspector->uses_moose; |
|
400
|
|
|
|
|
|
|
|
|
401
|
48
|
50
|
|
|
|
4498
|
return 1 if $self->_export_inspector->is_moo_class; |
|
402
|
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
return 1 |
|
404
|
48
|
100
|
|
1
|
|
1894
|
if any { $_ eq 'Moo::Object' } @{ $self->_export_inspector->pkg_isa }; |
|
|
1
|
|
|
|
|
51
|
|
|
|
48
|
|
|
|
|
1019
|
|
|
405
|
|
|
|
|
|
|
|
|
406
|
47
|
|
|
|
|
2519
|
return 0; |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub _build_is_translatable { |
|
410
|
47
|
|
|
47
|
|
1860
|
my $self = shift; |
|
411
|
|
|
|
|
|
|
|
|
412
|
47
|
50
|
|
|
|
258
|
return 0 if !$self->_include->type; |
|
413
|
47
|
50
|
|
|
|
1500
|
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
|
|
7389
|
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
|
|
|
|
1003
|
return $self->_include if $self->_is_ignored; |
|
453
|
|
|
|
|
|
|
|
|
454
|
48
|
50
|
|
|
|
1733
|
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
|
|
|
4164
|
if ( $self->_will_never_export |
|
|
|
|
100
|
|
|
|
|
|
464
|
|
|
|
|
|
|
|| $self->_is_translatable |
|
465
|
47
|
|
|
|
|
4045
|
|| !@{ $self->_imports } ) { |
|
466
|
15
|
|
|
|
|
726
|
return $self->_maybe_get_new_include( |
|
467
|
|
|
|
|
|
|
sprintf( |
|
468
|
|
|
|
|
|
|
'use %s%s ();', $self->module_name, $maybe_module_version |
|
469
|
|
|
|
|
|
|
) |
|
470
|
|
|
|
|
|
|
); |
|
471
|
|
|
|
|
|
|
} |
|
472
|
|
|
|
|
|
|
|
|
473
|
33
|
|
|
|
|
1040
|
my $statement; |
|
474
|
|
|
|
|
|
|
|
|
475
|
33
|
|
|
|
|
255
|
my @args = $self->_include->arguments; |
|
476
|
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
# Don't touch a do { } block. |
|
478
|
33
|
100
|
100
|
|
|
2064
|
if ( $self->_isa_test_builder_module && @args && $args[0] eq 'do' ) { |
|
|
|
|
66
|
|
|
|
|
|
479
|
1
|
|
|
|
|
110
|
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
|
|
|
2741
|
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
|
|
|
|
549
|
my $padding = $self->_pad_imports ? q{ } : q{}; |
|
573
|
32
|
100
|
|
|
|
591
|
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
|
|
|
|
|
921
|
@{ $self->_imports } |
|
|
32
|
|
|
|
|
851
|
|
|
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
|
|
|
612
|
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
|
|
|
|
|
150
|
return $self->_maybe_get_new_include($statement); |
|
605
|
|
|
|
|
|
|
} |
|
606
|
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
## use critic |
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
sub _imports_remain { |
|
610
|
867
|
|
|
867
|
|
1528
|
my $self = shift; |
|
611
|
867
|
|
|
|
|
1230
|
my $found = shift; |
|
612
|
867
|
|
|
|
|
1231
|
return keys %{$found} < $self->_explicit_export_count; |
|
|
867
|
|
|
|
|
2706
|
|
|
613
|
|
|
|
|
|
|
} |
|
614
|
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
sub _maybe_get_new_include { |
|
616
|
47
|
|
|
47
|
|
321
|
my $self = shift; |
|
617
|
47
|
|
|
|
|
110
|
my $statement = shift; |
|
618
|
47
|
|
|
|
|
370
|
my $doc = PPI::Document->new( \$statement ); |
|
619
|
|
|
|
|
|
|
my $includes |
|
620
|
47
|
|
|
389
|
|
75122
|
= $doc->find( sub { $_[1]->isa('PPI::Statement::Include'); } ); |
|
|
389
|
|
|
|
|
5382
|
|
|
621
|
47
|
|
|
|
|
1008
|
my $rewrite = $includes->[0]->clone; |
|
622
|
|
|
|
|
|
|
|
|
623
|
47
|
|
|
|
|
6831
|
my $a = $self->_include . q{}; |
|
624
|
47
|
|
|
|
|
1450
|
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
|
|
|
|
|
1676
|
my $orig = $a; |
|
648
|
47
|
100
|
|
|
|
208
|
if ( _respace_include($orig) eq $b ) { |
|
649
|
14
|
|
|
|
|
106
|
return $self->_include; |
|
650
|
|
|
|
|
|
|
} |
|
651
|
|
|
|
|
|
|
|
|
652
|
33
|
100
|
|
|
|
927
|
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
|
|
|
|
|
64
|
$a =~ s{\s}{}g; |
|
658
|
4
|
|
|
|
|
20
|
$b =~ s{\s}{}g; |
|
659
|
|
|
|
|
|
|
|
|
660
|
4
|
50
|
|
|
|
32
|
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
|
|
1852
|
my $include = shift; |
|
669
|
50
|
|
|
|
|
418
|
$include =~ s{\s+(qw|\()}{ $1}; |
|
670
|
50
|
|
|
|
|
284
|
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
|
|
107
|
my $self = shift; |
|
682
|
51
|
|
|
|
|
98
|
my $symbol = shift; |
|
683
|
51
|
|
|
|
|
94
|
my $duplicate = 0; |
|
684
|
|
|
|
|
|
|
|
|
685
|
51
|
|
|
|
|
99
|
foreach my $module ( |
|
686
|
98
|
|
|
|
|
2391
|
grep { $_ ne $self->module_name } |
|
687
|
51
|
|
|
|
|
1292
|
keys %{ $self->_document->original_imports } |
|
688
|
|
|
|
|
|
|
) { |
|
689
|
47
|
|
|
|
|
475
|
$self->logger->debug( |
|
690
|
|
|
|
|
|
|
"checking $module for previous imports of $symbol"); |
|
691
|
47
|
|
|
|
|
3095
|
my @imports; |
|
692
|
47
|
100
|
|
|
|
1014
|
if ( |
|
693
|
|
|
|
|
|
|
is_plain_arrayref( |
|
694
|
|
|
|
|
|
|
$self->_document->original_imports->{$module} |
|
695
|
|
|
|
|
|
|
) |
|
696
|
|
|
|
|
|
|
) { |
|
697
|
27
|
|
|
|
|
302
|
@imports = @{ $self->_document->original_imports->{$module} }; |
|
|
27
|
|
|
|
|
434
|
|
|
698
|
27
|
|
|
|
|
329
|
$self->logger->debug( |
|
699
|
|
|
|
|
|
|
'Explicit imports found: ' . Dumper( [ sort @imports ] ) ); |
|
700
|
|
|
|
|
|
|
} |
|
701
|
|
|
|
|
|
|
else { |
|
702
|
20
|
50
|
|
|
|
271
|
if ( my $inspector = $self->_document->inspector_for($module) ) { |
|
703
|
20
|
|
|
|
|
267
|
@imports = $inspector->implicit_export_names; |
|
704
|
20
|
|
|
|
|
564
|
$self->logger->debug( 'Implicit imports found: ' |
|
705
|
|
|
|
|
|
|
. Dumper( [ sort @imports ] ) ); |
|
706
|
|
|
|
|
|
|
} |
|
707
|
|
|
|
|
|
|
} |
|
708
|
|
|
|
|
|
|
|
|
709
|
47
|
100
|
|
270
|
|
7013
|
if ( any { $_ eq $symbol } @imports ) { |
|
|
270
|
|
|
|
|
466
|
|
|
710
|
6
|
|
|
|
|
12
|
$duplicate = 1; |
|
711
|
6
|
|
|
|
|
34
|
$self->logger->debug("$symbol already imported via $module"); |
|
712
|
6
|
|
|
|
|
233
|
last; |
|
713
|
|
|
|
|
|
|
} |
|
714
|
|
|
|
|
|
|
} |
|
715
|
|
|
|
|
|
|
|
|
716
|
51
|
|
|
|
|
459
|
return $duplicate; |
|
717
|
|
|
|
|
|
|
} |
|
718
|
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
sub _sort_symbols { |
|
720
|
47
|
|
|
47
|
|
189
|
my @list = @_; |
|
721
|
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
## no critic (BuiltinFunctions::RequireSimpleSortBlock) |
|
723
|
|
|
|
|
|
|
my @sorted = sort { |
|
724
|
47
|
|
|
|
|
222
|
my $A = _transform_before_cmp($a); |
|
|
27
|
|
|
|
|
107
|
|
|
725
|
27
|
|
|
|
|
85
|
my $B = _transform_before_cmp($b); |
|
726
|
27
|
|
|
|
|
124
|
"\L$A" cmp "\L$B"; |
|
727
|
|
|
|
|
|
|
} @list; |
|
728
|
47
|
|
|
|
|
328
|
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
|
|
101
|
my $thing = shift; |
|
736
|
54
|
100
|
|
|
|
283
|
if ( $thing =~ m{\A[\$]} ) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
737
|
11
|
|
|
|
|
38
|
$thing = substr( $thing, 1 ) . '-0'; |
|
738
|
|
|
|
|
|
|
} |
|
739
|
|
|
|
|
|
|
elsif ( $thing =~ m{\A[@]} ) { |
|
740
|
9
|
|
|
|
|
25
|
$thing = substr( $thing, 1 ) . '-1'; |
|
741
|
|
|
|
|
|
|
} |
|
742
|
|
|
|
|
|
|
elsif ( $thing =~ m{\A[%]} ) { |
|
743
|
3
|
|
|
|
|
18
|
$thing = substr( $thing, 1 ) . '-2'; |
|
744
|
|
|
|
|
|
|
} |
|
745
|
54
|
|
|
|
|
133
|
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.000051 |
|
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 |