File Coverage

blib/lib/Perl/Tidy/FileWriter.pm
Criterion Covered Total %
statement 148 216 68.5
branch 31 62 50.0
condition 15 24 62.5
subroutine 24 30 80.0
pod 0 19 0.0
total 218 351 62.1


line stmt bran cond sub pod time code
1             package Perl::Tidy::FileWriter;
2              
3             #####################################################################
4             #
5             # The Perl::Tidy::FileWriter class writes the output file created
6             # by the formatter. It receives each output line and performs some
7             # important monitoring services. These include:
8             #
9             # - Verifying that lines do not go out with tokens in the wrong order
10             # - Checking for obvious iteration convergence when all output tokens
11             # match all input tokens
12             # - Keeping track of consecutive blank and non-blank lines
13             # - Looking for line lengths which exceed the maximum requested length
14             # - Reporting results to the log file
15             #
16             #####################################################################
17              
18 44     44   238 use strict;
  44         66  
  44         1270  
19 44     44   149 use warnings;
  44         86  
  44         2405  
20             our $VERSION = '20260705';
21 44     44   202 use Carp;
  44         81  
  44         2749  
22              
23 44     44   243 use constant DEVEL_MODE => 0;
  44         75  
  44         2382  
24 44     44   180 use constant EMPTY_STRING => q{};
  44         53  
  44         1884  
25              
26             # Maximum number of little messages; probably need not be changed.
27 44     44   158 use constant MAX_NAG_MESSAGES => 6;
  44         86  
  44         11570  
28              
29             # List of hash keys to prevent -duk from listing them.
30             my @unique_hash_keys_uu = qw( indent-columns );
31              
32             sub AUTOLOAD {
33              
34             # Catch any undefined sub calls so that we are sure to get
35             # some diagnostic information. This sub should never be called
36             # except for a programming error.
37 0     0   0 our $AUTOLOAD;
38 0 0       0 return if ( $AUTOLOAD =~ /\bDESTROY$/ );
39 0         0 my ( $pkg, $fname, $lno ) = caller();
40 0         0 my $my_package = __PACKAGE__;
41 0         0 print {*STDERR} <<EOM;
  0         0  
42             ======================================================================
43             Error detected in package '$my_package', version $VERSION
44             Received unexpected AUTOLOAD call for sub '$AUTOLOAD'
45             Called from package: '$pkg'
46             Called from File '$fname' at line '$lno'
47             This error is probably due to a recent programming change
48             ======================================================================
49             EOM
50 0         0 exit 1;
51             } ## end sub AUTOLOAD
52              
53       0     sub DESTROY {
54              
55             # required to avoid call to AUTOLOAD in some versions of perl
56             }
57              
58 0         0 BEGIN {
59              
60             # Array index names for variables.
61             # Do not combine with other BEGIN blocks (c101).
62 44     44   57124 my $i = 0;
63             use constant {
64 44         13201 _logger_object_ => $i++,
65             _rOpts_ => $i++,
66             _output_line_number_ => $i++,
67             _consecutive_blank_lines_ => $i++,
68             _consecutive_nonblank_lines_ => $i++,
69             _consecutive_new_blank_lines_ => $i++,
70             _first_line_length_error_ => $i++,
71             _max_line_length_error_ => $i++,
72             _last_line_length_error_ => $i++,
73             _first_line_length_error_at_ => $i++,
74             _max_line_length_error_at_ => $i++,
75             _last_line_length_error_at_ => $i++,
76             _line_length_error_count_ => $i++,
77             _max_output_line_length_ => $i++,
78             _max_output_line_length_at_ => $i++,
79             _rK_checklist_ => $i++,
80             _K_arrival_order_matches_ => $i++,
81             _K_sequence_error_msg_ => $i++,
82             _K_last_arrival_ => $i++,
83             _save_logfile_ => $i++,
84             _routput_string_ => $i++,
85 44     44   245 };
  44         64  
86             } ## end BEGIN
87              
88             sub Die {
89 0     0 0 0 my ($msg) = @_;
90 0         0 Perl::Tidy::Die($msg);
91 0         0 croak "unexpected return from Perl::Tidy::Die";
92             }
93              
94             sub Fault {
95 0     0 0 0 my ($msg) = @_;
96              
97             # This routine is called for errors that really should not occur
98             # except if there has been a bug introduced by a recent program change.
99             # Please add comments at calls to Fault to explain why the call
100             # should not occur, and where to look to fix it.
101 0         0 my ( $package0_uu, $filename0_uu, $line0, $subroutine0_uu ) = caller(0);
102 0         0 my ( $package1_uu, $filename1, $line1, $subroutine1 ) = caller(1);
103 0         0 my ( $package2_uu, $filename2_uu, $line2_uu, $subroutine2 ) = caller(2);
104 0         0 my $pkg = __PACKAGE__;
105 0         0 my $input_stream_name = Perl::Tidy::get_input_stream_name();
106              
107 0         0 Die(<<EOM);
108             ==============================================================================
109             While operating on input stream with name: '$input_stream_name'
110             A fault was detected at line $line0 of sub '$subroutine1'
111             in file '$filename1'
112             which was called from line $line1 of sub '$subroutine2'
113             Message: '$msg'
114             This is probably an error introduced by a recent programming change.
115             $pkg reports VERSION='$VERSION'.
116             ==============================================================================
117             EOM
118              
119 0         0 croak "unexpected return from sub Die";
120             } ## end sub Fault
121              
122             sub warning {
123 0     0 0 0 my ( $self, $msg ) = @_;
124              
125             # log a warning message from any caller
126 0         0 my $logger_object = $self->[_logger_object_];
127 0 0       0 if ($logger_object) { $logger_object->warning($msg); }
  0         0  
128 0         0 return;
129             } ## end sub warning
130              
131             sub write_logfile_entry {
132 1316     1316 0 2118 my ( $self, $msg ) = @_;
133 1316         1893 my $logger_object = $self->[_logger_object_];
134 1316 100       2180 if ($logger_object) {
135 1312         2340 $logger_object->write_logfile_entry($msg);
136             }
137 1316         1819 return;
138             } ## end sub write_logfile_entry
139              
140             sub new {
141 658     658 0 1692 my ( $class, $line_sink_object, $rOpts, $logger_object ) = @_;
142              
143 658         1125 my $self = [];
144 658         1259 bless $self, $class;
145 658         1613 $self->[_logger_object_] = $logger_object;
146 658         1183 $self->[_rOpts_] = $rOpts;
147 658         1122 $self->[_output_line_number_] = 1;
148 658         1097 $self->[_consecutive_blank_lines_] = 0;
149 658         1490 $self->[_consecutive_nonblank_lines_] = 0;
150 658         1275 $self->[_consecutive_new_blank_lines_] = 0;
151 658         1191 $self->[_first_line_length_error_] = 0;
152 658         1009 $self->[_max_line_length_error_] = 0;
153 658         1229 $self->[_last_line_length_error_] = 0;
154 658         1103 $self->[_first_line_length_error_at_] = 0;
155 658         1194 $self->[_max_line_length_error_at_] = 0;
156 658         1055 $self->[_last_line_length_error_at_] = 0;
157 658         1077 $self->[_line_length_error_count_] = 0;
158 658         1058 $self->[_max_output_line_length_] = 0;
159 658         1054 $self->[_max_output_line_length_at_] = 0;
160 658         1435 $self->[_rK_checklist_] = [];
161 658         1109 $self->[_K_arrival_order_matches_] = 0;
162 658         1422 $self->[_K_sequence_error_msg_] = EMPTY_STRING;
163 658         1405 $self->[_K_last_arrival_] = -1;
164 658   100     3635 $self->[_save_logfile_] =
165             defined($logger_object) && $logger_object->get_save_logfile();
166              
167             # '$line_sink_object' is a SCALAR ref which receives the lines.
168 658         1397 my $ref = ref($line_sink_object);
169 658 50       2222 if ( !$ref ) {
    50          
170 0         0 Fault("FileWriter expects line_sink_object to be a ref\n");
171             }
172             elsif ( $ref eq 'SCALAR' ) {
173 658         1191 $self->[_routput_string_] = $line_sink_object;
174             }
175             else {
176 0         0 my $str = $ref;
177 0 0       0 if ( length($str) > 63 ) { $str = substr( $str, 0, 60 ) . '...' }
  0         0  
178 0         0 Fault(<<EOM);
179             FileWriter expects 'line_sink_object' to be ref to SCALAR but it is ref to:
180             $str
181             EOM
182             }
183              
184 658         1427 return $self;
185             } ## end sub new
186              
187             sub setup_convergence_test {
188 655     655 0 1428 my ( $self, $rlist ) = @_;
189              
190             # Setup the convergence test,
191              
192             # Given:
193             # $rlist = a reference to a list of line-ending token indexes 'K' of
194             # the input stream. We will compare these with the line-ending token
195             # indexes of the output stream. If they are identical, then we have
196             # convergence.
197 655 100       939 if ( @{$rlist} ) {
  655         1583  
198              
199             # We are going to destroy the list, so make a copy and put in
200             # reverse order so we can pop values as they arrive
201 644         946 my @list = @{$rlist};
  644         1911  
202 644 100       2100 if ( $list[0] < $list[-1] ) {
203 567         1496 @list = reverse(@list);
204             }
205 644         2063 $self->[_rK_checklist_] = \@list;
206             }
207              
208             # We will zero this flag on any error in arrival order:
209 655         2296 $self->[_K_arrival_order_matches_] = 1;
210 655         1735 $self->[_K_sequence_error_msg_] = EMPTY_STRING;
211 655         1102 $self->[_K_last_arrival_] = -1;
212 655         1401 return;
213             } ## end sub setup_convergence_test
214              
215             sub get_convergence_check {
216 658     658 0 1263 my ($self) = @_;
217              
218             # converged if:
219             # - all expected indexes arrived
220             # - and in correct order
221 658   66     861 return !@{ $self->[_rK_checklist_] }
222             && $self->[_K_arrival_order_matches_];
223              
224             } ## end sub get_convergence_check
225              
226             sub get_output_line_number {
227 562     562 0 753 my $self = shift;
228 562         1129 return $self->[_output_line_number_];
229             }
230              
231             sub decrement_output_line_number {
232 658     658 0 1071 my $self = shift;
233 658         1234 $self->[_output_line_number_]--;
234 658         976 return;
235             }
236              
237             sub get_consecutive_nonblank_lines {
238 1     1 0 3 my $self = shift;
239 1         6 return $self->[_consecutive_nonblank_lines_];
240             }
241              
242             sub get_consecutive_blank_lines {
243 0     0 0 0 my $self = shift;
244 0         0 return $self->[_consecutive_blank_lines_];
245             }
246              
247             sub reset_consecutive_blank_lines {
248 175     175 0 225 my $self = shift;
249 175         237 $self->[_consecutive_blank_lines_] = 0;
250 175         229 return;
251             }
252              
253             sub want_blank_line {
254 22     22 0 40 my $self = shift;
255 22 100       60 if ( !$self->[_consecutive_blank_lines_] ) {
256 13         40 $self->write_blank_code_line();
257             }
258 22         39 return;
259             } ## end sub want_blank_line
260              
261             sub require_blank_code_lines {
262 51     51 0 120 my ( $self, $count ) = @_;
263              
264             # Given:
265             # $count = number of blank lines to write
266             # Write out $count blank lines regardless of the value of -mbl
267             # unless -mbl=0. This allows extra blank lines to be written for subs and
268             # packages even with the default -mbl=1
269 51         79 my $need = $count - $self->[_consecutive_blank_lines_];
270 51         79 my $rOpts = $self->[_rOpts_];
271 51         93 my $forced = $rOpts->{'maximum-consecutive-blank-lines'} > 0;
272 51         129 foreach ( 0 .. $need - 1 ) {
273 32         74 $self->write_blank_code_line($forced);
274             }
275 51         103 return;
276             } ## end sub require_blank_code_lines
277              
278             sub write_blank_code_line {
279 1113     1113 0 1915 my ( $self, ($forced) ) = @_;
280              
281             # Write a blank line of code, given:
282             # $forced = optional flag which, if set, forces the blank line
283             # to be written. This allows the -mbl flag to be temporarily
284             # exceeded.
285              
286 1113         1674 my $rOpts = $self->[_rOpts_];
287             return
288             if (!$forced
289             && $self->[_consecutive_blank_lines_] >=
290 1113 100 100     4361 $rOpts->{'maximum-consecutive-blank-lines'} );
291              
292 999         1465 $self->[_consecutive_nonblank_lines_] = 0;
293              
294             # Balance old blanks against new (forced) blanks instead of writing them.
295             # This fixes case b1073.
296 999 50 66     3241 if ( !$forced && $self->[_consecutive_new_blank_lines_] > 0 ) {
297 0         0 $self->[_consecutive_new_blank_lines_]--;
298 0         0 return;
299             }
300              
301 999         1189 ${ $self->[_routput_string_] } .= "\n";
  999         1801  
302              
303 999         1377 $self->[_output_line_number_]++;
304 999         1263 $self->[_consecutive_blank_lines_]++;
305 999 100       1769 $self->[_consecutive_new_blank_lines_]++ if ($forced);
306              
307 999         1587 return;
308             } ## end sub write_blank_code_line
309              
310 44     44   3544 use constant MAX_PRINTED_CHARS => 80;
  44         1729  
  44         51264  
311              
312             sub write_code_line {
313 8512     8512 0 13391 my ( $self, $str, $K ) = @_;
314              
315             # Write a line of code, given
316             # $str = the line of code
317             # $K = an optional check integer which, if given, must
318             # increase monotonically. This was added to catch cache
319             # sequence errors in the vertical aligner.
320              
321 8512         10847 $self->[_consecutive_blank_lines_] = 0;
322 8512         9635 $self->[_consecutive_new_blank_lines_] = 0;
323 8512         9417 $self->[_consecutive_nonblank_lines_]++;
324 8512         8865 $self->[_output_line_number_]++;
325              
326 8512         8570 ${ $self->[_routput_string_] } .= $str;
  8512         18912  
327              
328 8512 100       14185 if ( $self->[_save_logfile_] ) { $self->check_line_lengths($str) }
  2         5  
329              
330             #----------------------------
331             # Convergence and error check
332             #----------------------------
333 8512 100       12562 if ( defined($K) ) {
334              
335             # Convergence check: we are checking if all defined K values arrive in
336             # the order which was defined by the caller. Quit checking if any
337             # unexpected K value arrives.
338 7618 100       11639 if ( $self->[_K_arrival_order_matches_] ) {
339 4048         4108 my $Kt = pop @{ $self->[_rK_checklist_] };
  4048         6350  
340 4048 100 66     13418 if ( !defined($Kt) || $Kt != $K ) {
341 295         615 $self->[_K_arrival_order_matches_] = 0;
342             }
343             }
344              
345             # Check for out-of-order arrivals of index K. The K values are the
346             # token indexes of the last token of code lines, and they should come
347             # out in increasing order. Otherwise something is seriously wrong.
348             # Most likely a recent programming change to VerticalAligner.pm has
349             # caused lines to go out in the wrong order. This could happen if
350             # either the cache or buffer that it uses are emptied in the wrong
351             # order.
352 7618 50 33     13864 if ( $K < $self->[_K_last_arrival_]
353             && !$self->[_K_sequence_error_msg_] )
354             {
355 0         0 my $K_prev = $self->[_K_last_arrival_];
356              
357 0         0 chomp $str;
358 0 0       0 if ( length($str) > MAX_PRINTED_CHARS ) {
359 0         0 $str = substr( $str, 0, MAX_PRINTED_CHARS ) . "...";
360             }
361              
362 0         0 my $msg = <<EOM;
363             Lines have arrived out of order in sub 'write_code_line'
364             as detected by token index K=$K arriving after index K=$K_prev in the following line:
365             $str
366             This is probably due to a recent programming change and needs to be fixed.
367             EOM
368              
369             # Always die during development, this needs to be fixed
370 0         0 if (DEVEL_MODE) { Fault($msg) }
371              
372             # Otherwise warn if string is not empty (added for b1378)
373 0 0       0 $self->warning($msg) if ( length($str) );
374              
375             # Only issue this warning once
376 0         0 $self->[_K_sequence_error_msg_] = $msg;
377              
378             }
379 7618         9003 $self->[_K_last_arrival_] = $K;
380             }
381 8512         14027 return;
382             } ## end sub write_code_line
383              
384             sub write_line {
385 399     399 0 562 my ( $self, $str ) = @_;
386              
387             # Write a line directly to the output, without any counting of blank or
388             # non-blank lines.
389              
390             # Given:
391             # $str = line of text to write
392              
393 399         427 ${ $self->[_routput_string_] } .= $str;
  399         1739  
394              
395 399 50       748 if ( chomp $str ) { $self->[_output_line_number_]++; }
  399         471  
396 399 50       587 if ( $self->[_save_logfile_] ) { $self->check_line_lengths($str) }
  0         0  
397              
398 399         493 return;
399             } ## end sub write_line
400              
401             sub check_line_lengths {
402 2     2 0 4 my ( $self, $str ) = @_;
403              
404             # Collect info on line lengths for logfile
405             # Given:
406             # $str = line of text being written
407              
408             # This calculation of excess line length ignores any internal tabs
409 2         2 my $rOpts = $self->[_rOpts_];
410 2         3 chomp $str;
411 2         3 my $len_str = length($str);
412 2         4 my $exceed = $len_str - $rOpts->{'maximum-line-length'};
413 2 50 33     8 if ( $str && substr( $str, 0, 1 ) eq "\t" && $str =~ /^\t+/g ) {
      33        
414 0         0 $exceed += pos($str) * $rOpts->{'indent-columns'};
415             }
416              
417             # Note that we just incremented output line number to future value
418             # so we must subtract 1 for current line number
419 2 100       3 if ( $len_str > $self->[_max_output_line_length_] ) {
420 1         1 $self->[_max_output_line_length_] = $len_str;
421 1         2 $self->[_max_output_line_length_at_] =
422             $self->[_output_line_number_] - 1;
423             }
424              
425 2 50       4 if ( $exceed > 0 ) {
426 0         0 my $output_line_number = $self->[_output_line_number_];
427 0         0 $self->[_last_line_length_error_] = $exceed;
428 0         0 $self->[_last_line_length_error_at_] = $output_line_number - 1;
429 0 0       0 if ( $self->[_line_length_error_count_] == 0 ) {
430 0         0 $self->[_first_line_length_error_] = $exceed;
431 0         0 $self->[_first_line_length_error_at_] = $output_line_number - 1;
432             }
433              
434 0 0       0 if ( $self->[_last_line_length_error_] >
435             $self->[_max_line_length_error_] )
436             {
437 0         0 $self->[_max_line_length_error_] = $exceed;
438 0         0 $self->[_max_line_length_error_at_] = $output_line_number - 1;
439             }
440              
441 0 0       0 if ( $self->[_line_length_error_count_] < MAX_NAG_MESSAGES ) {
442 0         0 $self->write_logfile_entry(
443             "Line length exceeded by $exceed characters\n");
444             }
445 0         0 $self->[_line_length_error_count_]++;
446             }
447 2         3 return;
448             } ## end sub check_line_lengths
449              
450             sub report_line_length_errors {
451 658     658 0 981 my $self = shift;
452              
453             # Write summary info about line lengths to the log file
454              
455 658         1111 my $rOpts = $self->[_rOpts_];
456 658         1244 my $line_length_error_count = $self->[_line_length_error_count_];
457 658 50       1449 if ( $line_length_error_count == 0 ) {
458 658         3371 $self->write_logfile_entry(
459             "No lines exceeded $rOpts->{'maximum-line-length'} characters\n");
460 658         1059 my $max_output_line_length = $self->[_max_output_line_length_];
461 658         1066 my $max_output_line_length_at = $self->[_max_output_line_length_at_];
462 658         1962 $self->write_logfile_entry(
463             " Maximum output line length was $max_output_line_length at line $max_output_line_length_at\n"
464             );
465              
466             }
467             else {
468              
469 0 0       0 my $word = ( $line_length_error_count > 1 ) ? "s" : EMPTY_STRING;
470 0         0 $self->write_logfile_entry(
471             "$line_length_error_count output line$word exceeded $rOpts->{'maximum-line-length'} characters:\n"
472             );
473              
474 0 0       0 $word = ( $line_length_error_count > 1 ) ? "First" : EMPTY_STRING;
475 0         0 my $first_line_length_error = $self->[_first_line_length_error_];
476 0         0 my $first_line_length_error_at = $self->[_first_line_length_error_at_];
477 0         0 $self->write_logfile_entry(
478             " $word at line $first_line_length_error_at by $first_line_length_error characters\n"
479             );
480              
481 0 0       0 if ( $line_length_error_count > 1 ) {
482 0         0 my $max_line_length_error = $self->[_max_line_length_error_];
483 0         0 my $max_line_length_error_at = $self->[_max_line_length_error_at_];
484 0         0 my $last_line_length_error = $self->[_last_line_length_error_];
485 0         0 my $last_line_length_error_at =
486             $self->[_last_line_length_error_at_];
487 0         0 $self->write_logfile_entry(
488             " Maximum at line $max_line_length_error_at by $max_line_length_error characters\n"
489             );
490 0         0 $self->write_logfile_entry(
491             " Last at line $last_line_length_error_at by $last_line_length_error characters\n"
492             );
493             }
494             }
495 658         1154 return;
496             } ## end sub report_line_length_errors
497             1;