line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test::Mimic::Recorder; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
91794
|
use 5.006001; # For open( my $fh, ... |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
41
|
|
4
|
1
|
|
|
1
|
|
6
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
36
|
|
5
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
27
|
|
6
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
7206
|
use Devel::EvalError (); |
|
1
|
|
|
|
|
2666
|
|
|
1
|
|
|
|
|
24
|
|
8
|
1
|
|
|
1
|
|
7
|
use Cwd qw; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
60
|
|
9
|
1
|
|
|
1
|
|
6
|
use Scalar::Util qw; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
62
|
|
10
|
|
|
|
|
|
|
|
11
|
1
|
|
|
|
|
503
|
use Test::Mimic::Library qw( |
12
|
|
|
|
|
|
|
encode |
13
|
|
|
|
|
|
|
descend |
14
|
|
|
|
|
|
|
stringify |
15
|
|
|
|
|
|
|
gen_arg_key |
16
|
|
|
|
|
|
|
monitor_args |
17
|
|
|
|
|
|
|
init_records |
18
|
|
|
|
|
|
|
load_preferences |
19
|
|
|
|
|
|
|
write_records |
20
|
|
|
|
|
|
|
RETURN |
21
|
|
|
|
|
|
|
EXCEPTION |
22
|
|
|
|
|
|
|
CODE_E |
23
|
|
|
|
|
|
|
SCALAR_CONTEXT |
24
|
|
|
|
|
|
|
VOID_CONTEXT |
25
|
|
|
|
|
|
|
LIST_CONTEXT |
26
|
|
|
|
|
|
|
ARBITRARY |
27
|
1
|
|
|
1
|
|
5
|
); |
|
1
|
|
|
|
|
2
|
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
our $VERSION = 0.012_005; |
30
|
|
|
|
|
|
|
our $SuspendRecording = 0; # Turn off recording. |
31
|
|
|
|
|
|
|
my $done_writing = 0; |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Data to be stored. |
34
|
|
|
|
|
|
|
my %typeglobs; # Contains recorded data for scalars, arrays, hashes and subroutines in a structure analogous |
35
|
|
|
|
|
|
|
# to the symbol table. The key is the package name. |
36
|
|
|
|
|
|
|
my %extra; # Currently contains only a flattened class hierarchy for each recorded class at |
37
|
|
|
|
|
|
|
# $extra{$class}{'ISA'} as a hash ref. $extra{$recorded_class}{'ISA'}{$other_class} will |
38
|
|
|
|
|
|
|
# exist iff $recorded_class isa $other_class. |
39
|
|
|
|
|
|
|
my @operation_sequence; # An ordered list of recorded operations. The first operation happened first, the |
40
|
|
|
|
|
|
|
# second operation happened second and so forth. This currently only includes |
41
|
|
|
|
|
|
|
# subroutine calls in recorded packages. Orderings of various 'scopes' can later be |
42
|
|
|
|
|
|
|
# extracted from this. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# Transient data |
45
|
|
|
|
|
|
|
my $save_to; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub import { |
48
|
1
|
|
|
1
|
|
11
|
my ( $class, $preferences ) = @_; |
49
|
|
|
|
|
|
|
|
50
|
1
|
|
50
|
|
|
10
|
$save_to = $preferences->{'save'} || '.test_mimic_recorder_data'; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# If we are not being run from Test::Mimic... |
53
|
1
|
50
|
|
|
|
4
|
if ( ! defined( $preferences->{'test_mimic'} ) ) { # Perhaps use caller instead? |
54
|
1
|
|
|
|
|
5
|
init_records(); |
55
|
1
|
|
|
|
|
10
|
load_preferences($preferences); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# Call _record_package on each package passing along the package and a list of scalars to record. |
59
|
1
|
|
|
|
|
15
|
for my $package ( keys %{ $preferences->{'packages'} } ) { |
|
1
|
|
|
|
|
6
|
|
60
|
1
|
|
50
|
|
|
6
|
_record_package( $package, $preferences->{'packages'}->{$package}->{'scalars'} ||= [] ); |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# Writes recording to disk. Typically called automatically. |
65
|
|
|
|
|
|
|
sub finish { |
66
|
1
|
|
|
1
|
1
|
2064
|
$done_writing = 1; # Prevents the END block from overwriting what we just wrote. |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# Move the current directory to the specified directory, creating if needed. |
69
|
1
|
|
|
|
|
17
|
my $top_level = abs_path(); |
70
|
1
|
|
|
|
|
5
|
descend($save_to); |
71
|
|
|
|
|
|
|
|
72
|
1
|
50
|
|
|
|
199
|
open( my $fh, '>', 'additional_info.rec' ) or die "Unable to open file: $!"; |
73
|
1
|
50
|
|
|
|
8
|
print $fh stringify( [ \%typeglobs, \%extra, \@operation_sequence ] ) |
74
|
|
|
|
|
|
|
or die "Unable to write: $!"; |
75
|
1
|
50
|
|
|
|
8137
|
close($fh) or die "Unable to close file: $!"; |
76
|
1
|
|
|
|
|
8
|
write_records( 'history_from_recorder.rec' ); |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# Undo the change to the current working directory above. |
79
|
1
|
50
|
|
|
|
3545
|
chdir($top_level) or die "Unable to change the current working directory: $!"; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
# Accepts a package name and a list of scalars in the package to be recorded. Test::Mimic::Recorder will |
83
|
|
|
|
|
|
|
# begin monitoring this package including the passed scalars. |
84
|
|
|
|
|
|
|
sub _record_package { |
85
|
1
|
|
|
1
|
|
2
|
my ( $package, $user_selected_scalars ) = @_; |
86
|
|
|
|
|
|
|
|
87
|
1
|
50
|
|
|
|
429
|
eval("require $package; 1") |
88
|
|
|
|
|
|
|
or die "Failed to load package $package. $@"; |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# Consider every symbol in the package, tie arrays and tie hashes. |
91
|
1
|
|
|
|
|
4
|
my $symbol_table; |
92
|
|
|
|
|
|
|
{ |
93
|
1
|
|
|
1
|
|
5
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
427
|
|
|
1
|
|
|
|
|
2
|
|
94
|
1
|
|
|
|
|
2
|
$symbol_table = \%{ $package . '::' }; |
|
1
|
|
|
|
|
4
|
|
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
1
|
|
50
|
|
|
10
|
my $fake_package = ( $typeglobs{$package} ||= {} ); |
98
|
1
|
|
|
|
|
2
|
for my $symbol ( keys %{$symbol_table} ) { |
|
1
|
|
|
|
|
6
|
|
99
|
|
|
|
|
|
|
|
100
|
14
|
|
|
|
|
328
|
my $typeglob = \$symbol_table->{$symbol}; # According to Tye it is better to handle glob refs than |
101
|
|
|
|
|
|
|
# globs themselves. |
102
|
14
|
|
50
|
|
|
68
|
my $fake_typeglob = ( $fake_package->{$symbol} ||= {} ); |
103
|
|
|
|
|
|
|
|
104
|
14
|
|
|
|
|
18
|
my $symbol_type = reftype( ${$typeglob} ); |
|
14
|
|
|
|
|
31
|
|
105
|
14
|
100
|
66
|
|
|
37
|
if ( ! defined($symbol_type) ) { |
|
|
50
|
|
|
|
|
|
106
|
12
|
|
|
|
|
42
|
my $pointer_type = reftype($typeglob); |
107
|
12
|
50
|
|
|
|
22
|
if ( $pointer_type eq 'GLOB' ) { |
|
|
0
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# Tie arrays and hashes. |
109
|
12
|
|
|
|
|
21
|
my $reference = *{$typeglob}{'ARRAY'}; |
|
12
|
|
|
|
|
23
|
|
110
|
12
|
100
|
|
|
|
27
|
if ( defined($reference) ) { |
111
|
2
|
|
|
|
|
8
|
$fake_typeglob->{'ARRAY'} = encode( $reference, 0 ); |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
12
|
|
|
|
|
165
|
$reference = *{$typeglob}{'HASH'}; |
|
12
|
|
|
|
|
18
|
|
115
|
12
|
100
|
66
|
|
|
48
|
if ( defined($reference) && ! ($symbol =~ m/^\w+::$/) ) { #Avoid tying symbol tables! |
116
|
1
|
|
|
|
|
4
|
$fake_typeglob->{'HASH'} = encode( $reference, 0 ); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
# Perl apparently sometimes stores subroutine stub declarations as simple |
120
|
|
|
|
|
|
|
# scalars. We would like to leave these alone. (See the Perl 5.10 |
121
|
|
|
|
|
|
|
# delta for one reference.) |
122
|
|
|
|
|
|
|
elsif ( $pointer_type ne 'SCALAR' ) { |
123
|
0
|
|
|
|
|
0
|
warn "The symbol <$symbol> in package <$package> with type <$pointer_type> is neither a glob," |
124
|
|
|
|
|
|
|
. ' constant optimization or subroutine stub declaration. Ignoring and proceeding.'; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
# Perl 5.10 optimizes constants by storing them as plain references, not globs initially, so |
128
|
|
|
|
|
|
|
# we handle that here by watching the 'constant' value. This is needed because although the |
129
|
|
|
|
|
|
|
# value itself is constant, the contents of the value may not be. If it is an array reference, |
130
|
|
|
|
|
|
|
# for example, we can modify the backing array. |
131
|
|
|
|
|
|
|
elsif ( $symbol_type eq 'REF' || $symbol_type eq 'SCALAR' ) { |
132
|
|
|
|
|
|
|
# If we are dealing with a simple scalar then it won't be tied anyways. Otherwise, an $at_level |
133
|
|
|
|
|
|
|
# of 1 will start the monitoring/tying on the elements of the aggregate/dereferenced value rather |
134
|
|
|
|
|
|
|
# than the aggregate/reference itself. |
135
|
2
|
|
|
|
|
4
|
$fake_typeglob->{'CONSTANT'} = encode( ${${$typeglob}}, 1 ); |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
8
|
|
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
else { |
138
|
0
|
|
|
|
|
0
|
warn "The symbol <$symbol> in package <$package> with reftype <$symbol_type> is neither a glob," |
139
|
|
|
|
|
|
|
. ' constant optimization or subroutine stub declaration. Ignoring and proceeding.'; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
} |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Combine the user selected scalars with the the exported scalars. |
144
|
1
|
|
|
|
|
4
|
my %all_scalars; |
145
|
1
|
50
|
|
|
|
14
|
if ( $package->isa('Exporter') ) { |
146
|
1
|
|
|
1
|
|
5
|
no strict 'refs'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
1136
|
|
147
|
0
|
|
|
|
|
0
|
for my $symbol ( @{ $package . '::EXPORT' }, @{ $package . '::EXPORT_OK' } ) { |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
148
|
0
|
0
|
|
|
|
0
|
if ( substr( $symbol, 0, 1 ) eq '$' ) { |
149
|
0
|
|
|
|
|
0
|
$all_scalars{ substr( $symbol, 1 ) } = ARBITRARY; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
} |
153
|
1
|
|
|
|
|
9
|
for my $scalar ( @{$user_selected_scalars} ) { |
|
1
|
|
|
|
|
3
|
|
154
|
1
|
|
|
|
|
4
|
$all_scalars{$scalar} = ARBITRARY; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# Tie all scalars. |
158
|
1
|
|
|
|
|
3
|
for my $scalar ( keys %all_scalars ) { |
159
|
1
|
|
|
|
|
3
|
my $typeglob = \$symbol_table->{$scalar}; |
160
|
|
|
|
|
|
|
|
161
|
1
|
50
|
|
|
|
5
|
if ( reftype($typeglob) eq 'GLOB' ) { # Ignore constant optimizations, handled above in array/hash code. |
162
|
1
|
|
|
|
|
1
|
$fake_package->{$scalar}->{'SCALAR'} = encode( *{$typeglob}{'SCALAR'}, 0 ); |
|
1
|
|
|
|
|
6
|
|
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
#Handle inheritance issues regarding both isa and can. |
167
|
1
|
|
|
|
|
58
|
my ( $full_ISA, $all_subs ) = _get_hierarchy_info($package); |
168
|
1
|
|
|
|
|
3
|
$extra{$package}{'ISA'} = $full_ISA; |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# Wrap all subroutines. (Or rather, redefine each subroutine to record the operation of the original.) |
171
|
1
|
|
|
|
|
2
|
for my $sub ( keys %{$all_subs} ) { |
|
1
|
|
|
|
|
4
|
|
172
|
11
|
|
|
|
|
61
|
my $original_sub = $package->can($sub); |
173
|
11
|
|
50
|
|
|
69
|
my $record_to = ( $fake_package->{$sub}->{'CODE'} ||= {} ); |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# Define the new subroutine |
176
|
|
|
|
|
|
|
my $wrapper_sub = sub { |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# Discard calls while recording is suspended, i.e. make the call, but don't record it. |
179
|
25
|
50
|
|
25
|
|
65
|
if ($Test::Mimic::Recorder::SuspendRecording) { |
180
|
0
|
|
|
|
|
0
|
goto &{$original_sub}; |
|
0
|
|
|
|
|
0
|
|
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# Set up the recording storage for this call. |
184
|
25
|
|
|
|
|
77
|
my $arg_key = gen_arg_key($package, $sub, \@_); |
185
|
25
|
|
100
|
|
|
393
|
my $context_to_result = ( $record_to->{$arg_key} ||= [] ); |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# TODO: Query user settings regarding the volatility of the arguments. |
188
|
25
|
|
|
|
|
79
|
my $arg_signature = monitor_args( $package, $sub, \@_ ); |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# Make actual call, trap exceptions or store return. |
191
|
25
|
|
|
|
|
989
|
local $Test::Mimic::Recorder::SuspendRecording = 1; # Suspend recording. We don't wan't to record |
192
|
|
|
|
|
|
|
# internal calls or state modifications. |
193
|
25
|
|
|
|
|
38
|
my $context = wantarray(); |
194
|
25
|
|
|
|
|
33
|
my $context_index; |
195
|
|
|
|
|
|
|
my $exception; |
196
|
0
|
|
|
|
|
0
|
my @results; |
197
|
0
|
|
|
|
|
0
|
my $stored_result; |
198
|
0
|
|
|
|
|
0
|
my $failed; |
199
|
25
|
|
|
|
|
82
|
my $eval_error = Devel::EvalError->new(); |
200
|
|
|
|
|
|
|
$eval_error->ExpectOne( |
201
|
25
|
|
|
|
|
544
|
eval { |
202
|
25
|
100
|
|
|
|
68
|
if ($context) { |
|
|
100
|
|
|
|
|
|
203
|
1
|
|
|
|
|
2
|
$context_index = LIST_CONTEXT; |
204
|
1
|
|
|
|
|
2
|
@results = &{$original_sub}; |
|
1
|
|
|
|
|
4
|
|
205
|
1
|
|
|
|
|
7
|
$stored_result = [ RETURN, encode( \@results, 1) ]; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
elsif (defined $context) { |
208
|
12
|
|
|
|
|
17
|
$context_index = SCALAR_CONTEXT; |
209
|
12
|
|
|
|
|
15
|
$results[0] = &{$original_sub}; |
|
12
|
|
|
|
|
34
|
|
210
|
11
|
|
|
|
|
149
|
$stored_result = [ RETURN, encode( $results[0], 0 ) ]; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
else { |
213
|
12
|
|
|
|
|
21
|
$context_index = VOID_CONTEXT; |
214
|
12
|
|
|
|
|
13
|
&{$original_sub}; |
|
12
|
|
|
|
|
34
|
|
215
|
12
|
|
|
|
|
715
|
$stored_result = [RETURN]; |
216
|
|
|
|
|
|
|
} |
217
|
24
|
|
|
|
|
412
|
1; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
); |
220
|
25
|
|
|
|
|
910
|
$failed = $eval_error->Failed(); |
221
|
25
|
100
|
|
|
|
272
|
if ( $failed ) { |
222
|
1
|
|
|
|
|
4
|
$exception = ( $eval_error->AllReasons() )[-1]; |
223
|
1
|
|
|
|
|
10
|
$stored_result = [ EXCEPTION, encode( $exception, 0 ) ]; |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# Maintain records |
227
|
25
|
|
|
|
|
82
|
push( @operation_sequence, [ $package, CODE_E, $sub, $arg_key, $context_index ] ); |
228
|
25
|
|
100
|
|
|
36
|
push( @{ $context_to_result->[$context_index] ||= [] }, ( $arg_signature, $stored_result ) ); |
|
25
|
|
|
|
|
108
|
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# Propagate original behavior |
231
|
25
|
100
|
|
|
|
91
|
if ( $failed ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
232
|
1
|
|
|
|
|
7
|
die $exception; |
233
|
|
|
|
|
|
|
} |
234
|
|
|
|
|
|
|
elsif ($context) { |
235
|
1
|
|
|
|
|
13
|
return @results; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
elsif ( defined $context ) { |
238
|
11
|
|
|
|
|
40
|
return $results[0]; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
else { |
241
|
12
|
|
|
|
|
41
|
return; |
242
|
|
|
|
|
|
|
} |
243
|
11
|
|
|
|
|
70
|
}; |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# Handle prototypes |
246
|
11
|
|
|
|
|
14
|
my $replacement; |
247
|
11
|
|
|
|
|
25
|
my $proto = prototype($original_sub); |
248
|
11
|
100
|
|
1
|
|
933
|
$replacement = eval "package $package; sub " . ( defined($proto) ? "($proto) " : '' ) |
|
1
|
|
|
|
|
58
|
|
|
1
|
|
|
|
|
296
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
3
|
|
|
|
|
165
|
|
|
2
|
|
|
|
|
140
|
|
|
0
|
|
|
|
|
0
|
|
|
9
|
|
|
|
|
969
|
|
|
2
|
|
|
|
|
100
|
|
|
0
|
|
|
|
|
0
|
|
|
7
|
|
|
|
|
1220
|
|
249
|
|
|
|
|
|
|
. "{ return \$wrapper_sub->(\@_); };"; |
250
|
|
|
|
|
|
|
# Saying 'package' in the eval allows us to record subroutines used by sort. If we don't $a and $b |
251
|
|
|
|
|
|
|
# are not imported properly. |
252
|
11
|
|
|
|
|
39
|
$extra{$package}{'PROTOTYPES'}{$sub} = $proto; |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# Redefine the original subroutine |
255
|
|
|
|
|
|
|
{ |
256
|
1
|
|
|
1
|
|
14
|
no warnings 'redefine'; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
84
|
|
|
11
|
|
|
|
|
20
|
|
257
|
1
|
|
|
1
|
|
11
|
no strict 'refs'; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
197
|
|
258
|
11
|
|
|
|
|
12
|
*{ $package . '::' . $sub } = $replacement; |
|
11
|
|
|
|
|
67
|
|
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# Accepts a class name. Returns the class hierarchy flattened into a hash ref and a list of all subroutines |
264
|
|
|
|
|
|
|
# the class responds too (including inherited subroutines, excluding AUTOLOADED subroutines) also as a hash |
265
|
|
|
|
|
|
|
# ref. An arbitrary element will exist in the proper hash iff the class isa element or the class can element |
266
|
|
|
|
|
|
|
# for classes and subroutines respectively. The subroutine names are not fully qualified. |
267
|
|
|
|
|
|
|
sub _get_hierarchy_info { |
268
|
5
|
|
|
5
|
|
7
|
my ($class) = @_; |
269
|
|
|
|
|
|
|
|
270
|
5
|
|
|
|
|
11
|
my %full_ISA = ( $class => ARBITRARY ); # Certainly $class isa $class. |
271
|
5
|
|
|
|
|
7
|
my %full_subs; |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
# Find all the subroutines declared in the class. |
274
|
|
|
|
|
|
|
my $symbol_table; |
275
|
|
|
|
|
|
|
{ |
276
|
1
|
|
|
1
|
|
5
|
no strict 'refs'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
121
|
|
|
5
|
|
|
|
|
6
|
|
277
|
5
|
|
|
|
|
4
|
$symbol_table = \%{ $class . '::' }; |
|
5
|
|
|
|
|
15
|
|
278
|
|
|
|
|
|
|
} |
279
|
5
|
|
|
|
|
7
|
for my $symbol ( keys %{$symbol_table} ) { |
|
5
|
|
|
|
|
13
|
|
280
|
28
|
|
|
|
|
38
|
my $typeglob = \$symbol_table->{$symbol}; |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
# Note if the symbol contains a subroutine. |
283
|
|
|
|
|
|
|
# Ignore constant optimizations, handled in _record_package except for the |
284
|
|
|
|
|
|
|
# case of inherited constants. Do we need to take care of this case? |
285
|
28
|
100
|
100
|
|
|
87
|
if ( ( reftype($typeglob) eq 'GLOB' ) && defined( *{$typeglob}{'CODE'} ) ) { |
|
26
|
|
|
|
|
103
|
|
286
|
11
|
|
|
|
|
161
|
$full_subs{$symbol} = ARBITRARY; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# Get a copy of the actual @ISA array. |
291
|
5
|
|
|
|
|
10
|
my @true_ISA; |
292
|
|
|
|
|
|
|
{ |
293
|
1
|
|
|
1
|
|
10
|
no strict 'refs'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
178
|
|
|
5
|
|
|
|
|
4
|
|
294
|
5
|
|
|
|
|
6
|
@true_ISA = @{ $class . '::ISA' }; |
|
5
|
|
|
|
|
29
|
|
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
# Look through the class hierarchy for all ancestor classes and inherited subroutines. |
298
|
5
|
|
|
|
|
64
|
for my $parent (@true_ISA) { |
299
|
4
|
50
|
|
|
|
9
|
if ( ! exists $full_ISA{$parent} ) { |
300
|
4
|
|
|
|
|
22
|
my ( $parent_full_ISA, $parent_full_subs ) = _get_hierarchy_info($parent); |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# Merge in the parent information. |
303
|
4
|
|
|
|
|
5
|
@full_ISA{ keys %{$parent_full_ISA} } = values %{$parent_full_ISA}; |
|
4
|
|
|
|
|
11
|
|
|
4
|
|
|
|
|
9
|
|
304
|
4
|
|
|
|
|
6
|
@full_subs{ keys %{$parent_full_subs} } = values %{$parent_full_subs}; |
|
4
|
|
|
|
|
19
|
|
|
4
|
|
|
|
|
8
|
|
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
5
|
|
|
|
|
14
|
return ( \%full_ISA, \%full_subs ); |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# Write recording to disk |
312
|
|
|
|
|
|
|
END { |
313
|
1
|
50
|
|
1
|
|
33087
|
finish() |
314
|
|
|
|
|
|
|
if ( ! $done_writing ); |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
1; |
318
|
|
|
|
|
|
|
__END__ |