File Coverage

blib/lib/Perl/Critic/Violation.pm
Criterion Covered Total %
statement 136 138 98.5
branch 25 30 83.3
condition 17 26 65.3
subroutine 42 44 95.4
pod 20 20 100.0
total 240 258 93.0


line stmt bran cond sub pod time code
1             package Perl::Critic::Violation;
2              
3 40     40   2085 use 5.010001;
  40         150  
4 40     40   241 use strict;
  40         83  
  40         803  
5 40     40   225 use warnings;
  40         97  
  40         1153  
6              
7 40     40   255 use Readonly;
  40         86  
  40         2126  
8              
9 40     40   283 use File::Basename qw< basename >;
  40         96  
  40         2684  
10 40     40   277 use Scalar::Util qw< blessed >;
  40         136  
  40         2284  
11 40     40   1777 use String::Format qw< stringf >;
  40         2486  
  40         2316  
12              
13 40     40   1576 use overload ( q{""} => 'to_string', cmp => '_compare' );
  40         1179  
  40         345  
14              
15 40     40   4513 use Perl::Critic::Utils qw< :characters :internal_lookup >;
  40         111  
  40         2336  
16 40         2214 use Perl::Critic::Utils::POD qw<
17             get_pod_section_for_module
18             trim_pod_section
19 40     40   12269 >;
  40         184  
20 40     40   1474 use Perl::Critic::Exception::Fatal::Internal qw< throw_internal >;
  40         169  
  40         60877  
21              
22             our $VERSION = '1.148';
23              
24             Readonly::Scalar my $NO_EXCEPTION_NO_SPLIT_LIMIT => -1;
25             Readonly::Scalar my $LOCATION_LINE_NUMBER => 0;
26             Readonly::Scalar my $LOCATION_COLUMN_NUMBER => 1;
27             Readonly::Scalar my $LOCATION_VISUAL_COLUMN_NUMBER => 2;
28             Readonly::Scalar my $LOCATION_LOGICAL_LINE_NUMBER => 3;
29             Readonly::Scalar my $LOCATION_LOGICAL_FILENAME => 4;
30              
31             # Class variables...
32             my $format = "%m at line %l, column %c. %e.\n"; # Default stringy format
33             my %diagnostics = (); # Cache of diagnostic messages
34              
35             #-----------------------------------------------------------------------------
36              
37             Readonly::Scalar my $CONSTRUCTOR_ARG_COUNT => 5;
38              
39             sub new {
40 3226     3226 1 40195 my ( $class, $desc, $expl, $elem, $sev ) = @_;
41              
42             # Check arguments to help out developers who might
43             # be creating new Perl::Critic::Policy modules.
44              
45 3226 100       8786 if ( @_ != $CONSTRUCTOR_ARG_COUNT ) {
46 1         6 throw_internal 'Wrong number of args to Violation->new()';
47             }
48              
49 3225 100       5650 if ( eval { $elem->isa( 'Perl::Critic::Document' ) } ) {
  3225         16128  
50             # break the facade, return the real PPI::Document
51 11         50 $elem = $elem->ppi_document();
52             }
53              
54 3225 100       6073 if ( not eval { $elem->isa( 'PPI::Element' ) } ) {
  3225         11861  
55 1         4 throw_internal '3rd arg to Violation->new() must be a PPI::Element';
56             }
57              
58             # Strip punctuation. These are controlled by the user via the
59             # formats. He/She can use whatever makes sense to them.
60 3224         9561 ($desc, $expl) = _chomp_periods($desc, $expl);
61              
62             # Create object
63 3224         8440 my $self = bless {}, $class;
64 3224         8490 $self->{_description} = $desc;
65 3224         6571 $self->{_explanation} = $expl;
66 3224         7187 $self->{_severity} = $sev;
67 3224         8104 $self->{_policy} = caller;
68              
69             # PPI eviscerates the Elements in a Document when the Document gets
70             # DESTROY()ed, and thus they aren't useful after it is gone. So we have
71             # to preemptively grab everything we could possibly want.
72 3224         12300 $self->{_element_class} = blessed $elem;
73              
74 3224         11386 my $top = $elem->top();
75 3224 100       52747 $self->{_filename} = $top->can('filename') ? $top->filename() : undef;
76 3224         15352 $self->{_source} = _line_containing_violation( $elem );
77             $self->{_location} =
78 3224   50     7379 $elem->location() || [ 0, 0, 0, 0, $self->filename() ];
79              
80 3224         52777 return $self;
81             }
82              
83             #-----------------------------------------------------------------------------
84              
85 20     20 1 9659 sub set_format { return $format = verbosity_to_format( $_[0] ); } ## no critic(ArgUnpacking)
86 6     6 1 33 sub get_format { return $format; }
87              
88             #-----------------------------------------------------------------------------
89              
90             sub sort_by_location { ## no critic(ArgUnpacking)
91              
92 2725 50   2725 1 7628 ref $_[0] || shift; # Can call as object or class method
93 2725 100       8455 return scalar @_ if ! wantarray; # In case we are called in scalar context
94              
95             ## TODO: What if $a and $b are not Violation objects?
96             return
97 2963         12485 map {$_->[0]}
98 2931 50       6755 sort { ($a->[1] <=> $b->[1]) || ($a->[2] <=> $b->[2]) }
99 2669   50     18988 map {[$_, $_->location->[0] || 0, $_->location->[1] || 0]}
  2963   100     6281  
100             @_;
101             }
102              
103             #-----------------------------------------------------------------------------
104              
105             sub sort_by_severity { ## no critic(ArgUnpacking)
106              
107 1 50   1 1 14 ref $_[0] || shift; # Can call as object or class method
108 1 50       379 return scalar @_ if ! wantarray; # In case we are called in scalar context
109              
110             ## TODO: What if $a and $b are not Violation objects?
111             return
112 6         20 map {$_->[0]}
113 9         17 sort { $a->[1] <=> $b->[1] }
114 1   100     7 map {[$_, $_->severity() || 0]}
  6         14  
115             @_;
116             }
117              
118             #-----------------------------------------------------------------------------
119              
120             sub location {
121 9443     9443 1 13673 my $self = shift;
122              
123 9443         28793 return $self->{_location};
124             }
125              
126             #-----------------------------------------------------------------------------
127              
128             sub line_number {
129 4     4 1 12 my ($self) = @_;
130              
131 4         13 return $self->location()->[$LOCATION_LINE_NUMBER];
132             }
133              
134             #-----------------------------------------------------------------------------
135              
136             sub logical_line_number {
137 169     169 1 383 my ($self) = @_;
138              
139 169         428 return $self->location()->[$LOCATION_LOGICAL_LINE_NUMBER];
140             }
141              
142             #-----------------------------------------------------------------------------
143              
144             sub column_number {
145 2     2 1 9 my ($self) = @_;
146              
147 2         6 return $self->location()->[$LOCATION_COLUMN_NUMBER];
148             }
149              
150             #-----------------------------------------------------------------------------
151              
152             sub visual_column_number {
153 167     167 1 327 my ($self) = @_;
154              
155 167         351 return $self->location()->[$LOCATION_VISUAL_COLUMN_NUMBER];
156             }
157              
158             #-----------------------------------------------------------------------------
159              
160             sub diagnostics {
161 7     7 1 76 my ($self) = @_;
162 7         17 my $policy = $self->policy();
163              
164 7 100       22 if ( not $diagnostics{$policy} ) {
165 3         9 eval { ## no critic (RequireCheckingReturnValueOfEval)
166 3   33     15 my $module_name = ref $policy || $policy;
167 3         14 $diagnostics{$policy} =
168             trim_pod_section(
169             get_pod_section_for_module( $module_name, 'DESCRIPTION' )
170             );
171             };
172 3   100     15 $diagnostics{$policy} ||= " No diagnostics available\n";
173             }
174 7         99 return $diagnostics{$policy};
175             }
176              
177             #-----------------------------------------------------------------------------
178              
179             sub description {
180 179     179 1 445 my $self = shift;
181 179         551 return $self->{_description};
182             }
183              
184             #-----------------------------------------------------------------------------
185              
186             sub explanation {
187 181     181 1 359 my $self = shift;
188 181         342 my $expl = $self->{_explanation};
189 181 100       522 if ( !$expl ) {
190 20         36 $expl = '(no explanation)';
191             }
192 181 100       627 if ( ref $expl eq 'ARRAY' ) {
193 109 100       182 my $page = @{$expl} > 1 ? 'pages' : 'page';
  109         464  
194 109         746 $page .= $SPACE . join $COMMA, @{$expl};
  109         316  
195 109         1692 $expl = "See $page of PBP";
196             }
197 181         528 return $expl;
198             }
199              
200             #-----------------------------------------------------------------------------
201              
202             sub severity {
203 3229     3229 1 5154 my $self = shift;
204 3229         11410 return $self->{_severity};
205             }
206              
207             #-----------------------------------------------------------------------------
208              
209             sub policy {
210 3224     3224 1 5221 my $self = shift;
211 3224         7656 return $self->{_policy};
212             }
213              
214             #-----------------------------------------------------------------------------
215              
216             sub filename {
217 4     4 1 10 my $self = shift;
218 4         61 return $self->{_filename};
219             }
220              
221             #-----------------------------------------------------------------------------
222              
223             sub logical_filename {
224 4     4 1 9 my ($self) = @_;
225              
226 4         10 return $self->location()->[$LOCATION_LOGICAL_FILENAME];
227             }
228              
229             #-----------------------------------------------------------------------------
230              
231             sub source {
232 159     159 1 273 my $self = shift;
233 159         419 return $self->{_source};
234             }
235              
236             #-----------------------------------------------------------------------------
237              
238             sub element_class {
239 2     2 1 7 my ($self) = @_;
240              
241 2         12 return $self->{_element_class};
242             }
243              
244             #-----------------------------------------------------------------------------
245              
246             sub to_string {
247 177     177 1 5096 my $self = shift;
248              
249 177         466 my $long_policy = $self->policy();
250 177         931 (my $short_policy = $long_policy) =~ s/ \A Perl::Critic::Policy:: //xms;
251              
252             # Wrap the more expensive ones in sub{} to postpone evaluation
253             my %fspec = (
254 2     2   95 'f' => sub { $self->logical_filename() },
255 2     2   101 'F' => sub { basename( $self->logical_filename() ) },
256 2     2   94 'g' => sub { $self->filename() },
257 2     2   100 'G' => sub { basename( $self->filename() ) },
258 167     167   11746 'l' => sub { $self->logical_line_number() },
259 2     2   102 'L' => sub { $self->line_number() },
260 165     165   5022 'c' => sub { $self->visual_column_number() },
261 0     0   0 'C' => sub { $self->element_class() },
262             'm' => $self->description(),
263             'e' => $self->explanation(),
264             's' => $self->severity(),
265 4     4   358 'd' => sub { $self->diagnostics() },
266 157     157   4670 'r' => sub { $self->source() },
267 177         1926 'P' => $long_policy,
268             'p' => $short_policy,
269             );
270 177         1042 return stringf($format, %fspec);
271             }
272              
273             #-----------------------------------------------------------------------------
274             # Apparently, some perls do not implicitly stringify overloading
275             # objects before doing a comparison. This causes a couple of our
276             # sorting tests to fail. To work around this, we overload C<cmp> to
277             # do it explicitly.
278             #
279             # 20060503 - More information: This problem has been traced to
280             # Test::Simple versions <= 0.60, not perl itself. Upgrading to
281             # Test::Simple v0.62 will fix the problem. But rather than forcing
282             # everyone to upgrade, I have decided to leave this workaround in
283             # place.
284              
285 0     0   0 sub _compare { return "$_[0]" cmp "$_[1]" }
286              
287             #-----------------------------------------------------------------------------
288              
289             sub _line_containing_violation {
290 3224     3224   6161 my ( $elem ) = @_;
291              
292 3224   66     8314 my $stmnt = $elem->statement() || $elem;
293 3224   33     52835 my $code_string = $stmnt->content() || $EMPTY;
294              
295             # Split into individual lines
296             # From `perldoc -f split`:
297             # If LIMIT is negative, it is treated as if it were instead
298             # arbitrarily large; as many fields as possible are produced.
299             #
300             # If it's omitted, it's the same except trailing empty fields, so we need
301             # without a limit for the split and without an exception
302 3224         172529 my @lines = split qr{ \n }xms, $code_string, $NO_EXCEPTION_NO_SPLIT_LIMIT;
303              
304             # Take the line containing the element that is in violation
305 3224   50     13149 my $inx = ( $elem->line_number() || 0 ) -
      50        
306             ( $stmnt->line_number() || 0 );
307 3224 50       137000 $inx > @lines and return $EMPTY;
308 3224         10967 return $lines[$inx];
309             }
310              
311             #-----------------------------------------------------------------------------
312              
313             sub _chomp_periods {
314 3225     3225   7825 my @args = @_;
315              
316 3225         7290 for (@args) {
317 6454 100 100     22419 next if not defined or ref;
318 4282         11155 s{ [.]+ \z }{}xms
319             }
320              
321 3225         10091 return @args;
322             }
323              
324             #-----------------------------------------------------------------------------
325              
326             1;
327              
328             #-----------------------------------------------------------------------------
329              
330             __END__
331              
332             =head1 NAME
333              
334             Perl::Critic::Violation - A violation of a Policy found in some source code.
335              
336              
337             =head1 SYNOPSIS
338              
339             use PPI;
340             use Perl::Critic::Violation;
341              
342             my $elem = $doc->child(0); # $doc is a PPI::Document object
343             my $desc = 'Offending code'; # Describe the violation
344             my $expl = [1,45,67]; # Page numbers from PBP
345             my $sev = 5; # Severity level of this violation
346              
347             my $vio = Perl::Critic::Violation->new($desc, $expl, $node, $sev);
348              
349              
350             =head1 DESCRIPTION
351              
352             Perl::Critic::Violation is the generic representation of an individual
353             Policy violation. Its primary purpose is to provide an abstraction
354             layer so that clients of L<Perl::Critic|Perl::Critic> don't have to
355             know anything about L<PPI|PPI>. The C<violations> method of all
356             L<Perl::Critic::Policy|Perl::Critic::Policy> subclasses must return a
357             list of these Perl::Critic::Violation objects.
358              
359              
360             =head1 INTERFACE SUPPORT
361              
362             This is considered to be a public class. Any changes to its interface
363             will go through a deprecation cycle.
364              
365              
366             =head1 CONSTRUCTOR
367              
368             =over
369              
370             =item C<new( $description, $explanation, $element, $severity )>
371              
372             Returns a reference to a new C<Perl::Critic::Violation> object. The
373             arguments are a description of the violation (as string), an
374             explanation for the policy (as string) or a series of page numbers in
375             PBP (as an ARRAY ref), a reference to the L<PPI|PPI> element that
376             caused the violation, and the severity of the violation (as an
377             integer).
378              
379              
380             =back
381              
382              
383             =head1 METHODS
384              
385             =over
386              
387             =item C<description()>
388              
389             Returns a brief description of the specific violation. In other
390             words, this value may change on a per violation basis.
391              
392              
393             =item C<explanation()>
394              
395             Returns an explanation of the policy as a string or as reference to an
396             array of page numbers in PBP. This value will generally not change
397             based upon the specific code violating the policy.
398              
399              
400             =item C<location()>
401              
402             Don't use this method. Use the C<line_number()>,
403             C<logical_line_number()>, C<column_number()>,
404             C<visual_column_number()>, and C<logical_filename()> methods instead.
405              
406             Returns a five-element array reference containing the line and real &
407             virtual column and logical numbers and logical file name where this
408             Violation occurred, as in L<PPI::Element|PPI::Element>.
409              
410              
411             =item C<line_number()>
412              
413             Returns the physical line number that the violation was found on.
414              
415              
416             =item C<logical_line_number()>
417              
418             Returns the logical line number that the violation was found on. This
419             can differ from the physical line number when there were C<#line>
420             directives in the code.
421              
422              
423             =item C<column_number()>
424              
425             Returns the physical column that the violation was found at. This
426             means that hard tab characters count as a single character.
427              
428              
429             =item C<visual_column_number()>
430              
431             Returns the column that the violation was found at, as it would appear
432             if hard tab characters were expanded, based upon the value of
433             L<PPI::Document/"tab_width [ $width ]">.
434              
435              
436             =item C<filename()>
437              
438             Returns the path to the file where this Violation occurred. In some
439             cases, the path may be undefined because the source code was not read
440             directly from a file.
441              
442              
443             =item C<logical_filename()>
444              
445             Returns the logical path to the file where the Violation occurred.
446             This can differ from C<filename()> when there was a C<#line> directive
447             in the code.
448              
449              
450             =item C<severity()>
451              
452             Returns the severity of this Violation as an integer ranging from 1 to
453             5, where 5 is the "most" severe.
454              
455              
456             =item C<sort_by_severity( @violation_objects )>
457              
458             If you need to sort Violations by severity, use this handy routine:
459              
460             @sorted = Perl::Critic::Violation::sort_by_severity(@violations);
461              
462              
463             =item C<sort_by_location( @violation_objects )>
464              
465             If you need to sort Violations by location, use this handy routine:
466              
467             @sorted = Perl::Critic::Violation::sort_by_location(@violations);
468              
469              
470             =item C<diagnostics()>
471              
472             Returns a formatted string containing a full discussion of the
473             motivation for and details of the Policy module that created this
474             Violation. This information is automatically extracted from the
475             C<DESCRIPTION> section of the Policy module's POD.
476              
477              
478             =item C<policy()>
479              
480             Returns the name of the L<Perl::Critic::Policy|Perl::Critic::Policy>
481             that created this Violation.
482              
483              
484             =item C<source()>
485              
486             Returns the string of source code that caused this exception. If the
487             code spans multiple lines (e.g. multi-line statements, subroutines or
488             other blocks), then only the line containing the violation will be
489             returned.
490              
491              
492             =item C<element_class()>
493              
494             Returns the L<PPI::Element|PPI::Element> subclass of the code that caused this
495             exception.
496              
497              
498             =item C<set_format( $format )>
499              
500             Class method. Sets the format for all Violation objects when they are
501             evaluated in string context. The default is C<'%d at line %l, column
502             %c. %e'>. See L<"OVERLOADS"> for formatting options.
503              
504              
505             =item C<get_format()>
506              
507             Class method. Returns the current format for all Violation objects
508             when they are evaluated in string context.
509              
510              
511             =item C<to_string()>
512              
513             Returns a string representation of this violation. The content of the
514             string depends on the current value of the C<$format> package
515             variable. See L<"OVERLOADS"> for the details.
516              
517              
518             =back
519              
520              
521             =head1 OVERLOADS
522              
523             Perl::Critic::Violation overloads the C<""> operator to produce neat
524             little messages when evaluated in string context.
525              
526             Formats are a combination of literal and escape characters similar to
527             the way C<sprintf> works. If you want to know the specific formatting
528             capabilities, look at L<String::Format|String::Format>. Valid escape
529             characters are:
530              
531             Escape Meaning
532             ------- ----------------------------------------------------------------
533             %c Column number where the violation occurred
534             %d Full diagnostic discussion of the violation (DESCRIPTION in POD)
535             %e Explanation of violation or page numbers in PBP
536             %F Just the name of the logical file where the violation occurred.
537             %f Path to the logical file where the violation occurred.
538             %G Just the name of the physical file where the violation occurred.
539             %g Path to the physical file where the violation occurred.
540             %l Logical line number where the violation occurred
541             %L Physical line number where the violation occurred
542             %m Brief description of the violation
543             %P Full name of the Policy module that created the violation
544             %p Name of the Policy without the Perl::Critic::Policy:: prefix
545             %r The string of source code that caused the violation
546             %C The class of the PPI::Element that caused the violation
547             %s The severity level of the violation
548              
549             Explanation of the C<%F>, C<%f>, C<%G>, C<%G>, C<%l>, and C<%L> formats:
550             Using C<#line> directives, you can affect what perl thinks the current line
551             number and file name are; see L<perlsyn/Plain Old Comments (Not!)> for
552             the details. Under normal circumstances, the values of C<%F>, C<%f>, and
553             C<%l> will match the values of C<%G>, C<%g>, and C<%L>, respectively. In the
554             presence of a C<#line> directive, the values of C<%F>, C<%f>, and C<%l> will
555             change to take that directive into account. The values of C<%G>, C<%g>, and
556             C<%L> are unaffected by those directives.
557              
558             Here are some examples:
559              
560             Perl::Critic::Violation::set_format("%m at line %l, column %c.\n");
561             # looks like "Mixed case variable name at line 6, column 23."
562              
563             Perl::Critic::Violation::set_format("%m near '%r'\n");
564             # looks like "Mixed case variable name near 'my $theGreatAnswer = 42;'"
565              
566             Perl::Critic::Violation::set_format("%l:%c:%p\n");
567             # looks like "6:23:NamingConventions::Capitalization"
568              
569             Perl::Critic::Violation::set_format("%m at line %l. %e. \n%d\n");
570             # looks like "Mixed case variable name at line 6. See page 44 of PBP.
571             Conway's recommended naming convention is to use lower-case words
572             separated by underscores. Well-recognized acronyms can be in ALL
573             CAPS, but must be separated by underscores from other parts of the
574             name."
575              
576              
577             =head1 AUTHOR
578              
579             Jeffrey Ryan Thalhammer <jeff@imaginative-software.com>
580              
581              
582             =head1 COPYRIGHT
583              
584             Copyright (c) 2005-2011 Imaginative Software Systems. All rights reserved.
585              
586             This program is free software; you can redistribute it and/or modify
587             it under the same terms as Perl itself. The full text of this license
588             can be found in the LICENSE file included with this module.
589              
590             =cut
591              
592             # Local Variables:
593             # mode: cperl
594             # cperl-indent-level: 4
595             # fill-column: 78
596             # indent-tabs-mode: nil
597             # c-indentation-style: bsd
598             # End:
599             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :