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   2033 use 5.010001;
  40         157  
4 40     40   229 use strict;
  40         98  
  40         850  
5 40     40   207 use warnings;
  40         99  
  40         1072  
6              
7 40     40   235 use Readonly;
  40         115  
  40         2308  
8              
9 40     40   284 use File::Basename qw< basename >;
  40         97  
  40         2776  
10 40     40   326 use Scalar::Util qw< blessed >;
  40         127  
  40         2185  
11 40     40   1747 use String::Format qw< stringf >;
  40         2377  
  40         2405  
12              
13 40     40   1464 use overload ( q{""} => 'to_string', cmp => '_compare' );
  40         1167  
  40         325  
14              
15 40     40   4583 use Perl::Critic::Utils qw< :characters :internal_lookup >;
  40         103  
  40         2180  
16 40         2400 use Perl::Critic::Utils::POD qw<
17             get_pod_section_for_module
18             trim_pod_section
19 40     40   12621 >;
  40         209  
20 40     40   1542 use Perl::Critic::Exception::Fatal::Internal qw< throw_internal >;
  40         93  
  40         60860  
21              
22             our $VERSION = '1.146';
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 37046 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       8850 if ( @_ != $CONSTRUCTOR_ARG_COUNT ) {
46 1         8 throw_internal 'Wrong number of args to Violation->new()';
47             }
48              
49 3225 100       6888 if ( eval { $elem->isa( 'Perl::Critic::Document' ) } ) {
  3225         16656  
50             # break the facade, return the real PPI::Document
51 11         52 $elem = $elem->ppi_document();
52             }
53              
54 3225 100       5954 if ( not eval { $elem->isa( 'PPI::Element' ) } ) {
  3225         11429  
55 1         5 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         9423 ($desc, $expl) = _chomp_periods($desc, $expl);
61              
62             # Create object
63 3224         8455 my $self = bless {}, $class;
64 3224         9739 $self->{_description} = $desc;
65 3224         6296 $self->{_explanation} = $expl;
66 3224         6499 $self->{_severity} = $sev;
67 3224         10128 $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         13934 $self->{_element_class} = blessed $elem;
73              
74 3224         12408 my $top = $elem->top();
75 3224 100       55788 $self->{_filename} = $top->can('filename') ? $top->filename() : undef;
76 3224         17291 $self->{_source} = _line_containing_violation( $elem );
77             $self->{_location} =
78 3224   50     7417 $elem->location() || [ 0, 0, 0, 0, $self->filename() ];
79              
80 3224         53105 return $self;
81             }
82              
83             #-----------------------------------------------------------------------------
84              
85 20     20 1 8189 sub set_format { return $format = verbosity_to_format( $_[0] ); } ## no critic(ArgUnpacking)
86 6     6 1 32 sub get_format { return $format; }
87              
88             #-----------------------------------------------------------------------------
89              
90             sub sort_by_location { ## no critic(ArgUnpacking)
91              
92 2725 50   2725 1 7561 ref $_[0] || shift; # Can call as object or class method
93 2725 100       7998 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         12907 map {$_->[0]}
98 2931 50       6216 sort { ($a->[1] <=> $b->[1]) || ($a->[2] <=> $b->[2]) }
99 2669   50     21039 map {[$_, $_->location->[0] || 0, $_->location->[1] || 0]}
  2963   100     5841  
100             @_;
101             }
102              
103             #-----------------------------------------------------------------------------
104              
105             sub sort_by_severity { ## no critic(ArgUnpacking)
106              
107 1 50   1 1 24 ref $_[0] || shift; # Can call as object or class method
108 1 50       16 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         25 map {$_->[0]}
113 9         20 sort { $a->[1] <=> $b->[1] }
114 1   100     8 map {[$_, $_->severity() || 0]}
  6         14  
115             @_;
116             }
117              
118             #-----------------------------------------------------------------------------
119              
120             sub location {
121 9443     9443 1 13688 my $self = shift;
122              
123 9443         27300 return $self->{_location};
124             }
125              
126             #-----------------------------------------------------------------------------
127              
128             sub line_number {
129 4     4 1 12 my ($self) = @_;
130              
131 4         11 return $self->location()->[$LOCATION_LINE_NUMBER];
132             }
133              
134             #-----------------------------------------------------------------------------
135              
136             sub logical_line_number {
137 169     169 1 375 my ($self) = @_;
138              
139 169         413 return $self->location()->[$LOCATION_LOGICAL_LINE_NUMBER];
140             }
141              
142             #-----------------------------------------------------------------------------
143              
144             sub column_number {
145 2     2 1 6 my ($self) = @_;
146              
147 2         7 return $self->location()->[$LOCATION_COLUMN_NUMBER];
148             }
149              
150             #-----------------------------------------------------------------------------
151              
152             sub visual_column_number {
153 167     167 1 338 my ($self) = @_;
154              
155 167         348 return $self->location()->[$LOCATION_VISUAL_COLUMN_NUMBER];
156             }
157              
158             #-----------------------------------------------------------------------------
159              
160             sub diagnostics {
161 7     7 1 70 my ($self) = @_;
162 7         20 my $policy = $self->policy();
163              
164 7 100       19 if ( not $diagnostics{$policy} ) {
165 3         7 eval { ## no critic (RequireCheckingReturnValueOfEval)
166 3   33     16 my $module_name = ref $policy || $policy;
167 3         13 $diagnostics{$policy} =
168             trim_pod_section(
169             get_pod_section_for_module( $module_name, 'DESCRIPTION' )
170             );
171             };
172 3   100     17 $diagnostics{$policy} ||= " No diagnostics available\n";
173             }
174 7         97 return $diagnostics{$policy};
175             }
176              
177             #-----------------------------------------------------------------------------
178              
179             sub description {
180 179     179 1 438 my $self = shift;
181 179         600 return $self->{_description};
182             }
183              
184             #-----------------------------------------------------------------------------
185              
186             sub explanation {
187 181     181 1 311 my $self = shift;
188 181         360 my $expl = $self->{_explanation};
189 181 100       522 if ( !$expl ) {
190 20         35 $expl = '(no explanation)';
191             }
192 181 100       547 if ( ref $expl eq 'ARRAY' ) {
193 109 100       192 my $page = @{$expl} > 1 ? 'pages' : 'page';
  109         510  
194 109         784 $page .= $SPACE . join $COMMA, @{$expl};
  109         296  
195 109         1607 $expl = "See $page of PBP";
196             }
197 181         591 return $expl;
198             }
199              
200             #-----------------------------------------------------------------------------
201              
202             sub severity {
203 3229     3229 1 8845 my $self = shift;
204 3229         10064 return $self->{_severity};
205             }
206              
207             #-----------------------------------------------------------------------------
208              
209             sub policy {
210 3224     3224 1 5084 my $self = shift;
211 3224         7358 return $self->{_policy};
212             }
213              
214             #-----------------------------------------------------------------------------
215              
216             sub filename {
217 4     4 1 10 my $self = shift;
218 4         63 return $self->{_filename};
219             }
220              
221             #-----------------------------------------------------------------------------
222              
223             sub logical_filename {
224 4     4 1 11 my ($self) = @_;
225              
226 4         10 return $self->location()->[$LOCATION_LOGICAL_FILENAME];
227             }
228              
229             #-----------------------------------------------------------------------------
230              
231             sub source {
232 159     159 1 324 my $self = shift;
233 159         470 return $self->{_source};
234             }
235              
236             #-----------------------------------------------------------------------------
237              
238             sub element_class {
239 2     2 1 7 my ($self) = @_;
240              
241 2         11 return $self->{_element_class};
242             }
243              
244             #-----------------------------------------------------------------------------
245              
246             sub to_string {
247 177     177 1 4705 my $self = shift;
248              
249 177         515 my $long_policy = $self->policy();
250 177         1283 (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   96 'f' => sub { $self->logical_filename() },
255 2     2   100 'F' => sub { basename( $self->logical_filename() ) },
256 2     2   97 'g' => sub { $self->filename() },
257 2     2   97 'G' => sub { basename( $self->filename() ) },
258 167     167   11969 'l' => sub { $self->logical_line_number() },
259 2     2   113 'L' => sub { $self->line_number() },
260 165     165   4963 '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   316 'd' => sub { $self->diagnostics() },
266 157     157   4942 'r' => sub { $self->source() },
267 177         2131 'P' => $long_policy,
268             'p' => $short_policy,
269             );
270 177         1119 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   5986 my ( $elem ) = @_;
291              
292 3224   66     8732 my $stmnt = $elem->statement() || $elem;
293 3224   33     57992 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         177710 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     13253 my $inx = ( $elem->line_number() || 0 ) -
      50        
306             ( $stmnt->line_number() || 0 );
307 3224 50       138393 $inx > @lines and return $EMPTY;
308 3224         10287 return $lines[$inx];
309             }
310              
311             #-----------------------------------------------------------------------------
312              
313             sub _chomp_periods {
314 3225     3225   7510 my @args = @_;
315              
316 3225         7245 for (@args) {
317 6454 100 100     22667 next if not defined or ref;
318 4282         10857 s{ [.]+ \z }{}xms
319             }
320              
321 3225         11232 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 :