File Coverage

blib/lib/Perl5/Build/Warnings.pm
Criterion Covered Total %
statement 60 60 100.0
branch 16 18 88.8
condition 3 3 100.0
subroutine 12 12 100.0
pod 6 6 100.0
total 97 99 97.9


line stmt bran cond sub pod time code
1             package Perl5::Build::Warnings;
2 1     1   101314 use 5.14.0;
  1         4  
3 1     1   5 use warnings;
  1         2  
  1         37  
4             our $VERSION = '0.05';
5 1     1   5 use Carp;
  1         2  
  1         48  
6 1     1   528 use IO::File;
  1         1052  
  1         111  
7 1     1   645 use IO::Zlib;
  1         63285  
  1         7  
8              
9             =encoding utf8
10              
11             =head1 NAME
12              
13             Perl5::Build::Warnings - Parse make output for build-time warnings
14              
15             =head1 SYNOPSIS
16              
17             use Perl5::Build::Warnings;
18              
19             my $self = Perl5::Build::Warnings->new( { file => '/path/to/make.log' } );
20              
21             my $hashref = $self->get_warnings_groups;
22              
23             my $arrayref = $self->get_warnings;
24              
25             $self->report_warnings_groups;
26              
27             $arrayref = $self->get_warnings_for_group('Wunused-variable');
28              
29             $arrayref = $self->get_warnings_for_source('op.c');
30              
31              
32             =head1 DESCRIPTION
33              
34             Perl5::Build::Warnings is a module for use in studying build-time warnings
35             emitted by F when building the Perl 5 core distribution from source
36             code.
37              
38             =head2 Prerequisites
39              
40             CPAN module F is used in this library's test suite, but not in
41             the module itself. There are currently no other prerequisites not found in
42             the Perl 5 core distribution.
43              
44             =head2 Assumptions
45              
46             =head3 Logging of F Output
47              
48             The module assumes that the user has logged the output of F (or
49             F -- but not F -- or Windows equivalents) to a
50             plain-text file. Something like:
51              
52             make test_prep 2>&1 > /path/to/make.log
53              
54             The build log may be gzipped-compressed, I
55              
56             make test_prep 2>&1 | gzip -c > /path/to/make.log.gz
57              
58             =head3 Format for Build-Time Warnings
59              
60             The module assumes that within such a logfile, warnings are recorded in this
61             format:
62              
63             op.c:5468:34: warning: argument ‘o’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Wclobbered]
64              
65             That is,
66              
67             ::: warning: [-]
68              
69             Note that the first field recorded, C may be either the basename of
70             a file in the top-level of the source code or a relative path to a file
71             beneath the top-level.
72              
73             Note further that the last field recorded, the class of warning, starts with
74             an open bracket (C<[>), followed by a hyphen and an upper-case 'W' (C<-W>),
75             followed by the warning class, followed by a close bracket (C<]>). In this
76             module we will ignore the open and close brackets and the hyphen, but we will
77             capture and report the upper-case 'W'. Hence, whereas the log will record
78              
79             [-Wclobbered]
80              
81             ... this module will store and report that information as:
82              
83             Wclobbered
84              
85             This is done in part because we may wish to use this data on the command-line
86             and the hyphen is likely to be significant to the shell.
87              
88             =head1 METHODS
89              
90             =head2 C
91              
92             =over 4
93              
94             =item * Purpose
95              
96             Perl5::Build::Warnings constructor.
97              
98             =item * Arguments
99              
100             $file = "./t/data/make.g++-8-list-util-fallthrough.output.txt";
101             $self = Perl5::Build::Warnings->new( { file => $file } );
102              
103             Single hash reference with one required element, C, whose value is a
104             path to a file holding a log of F's output.
105              
106             =item * Return Value
107              
108             Perl5::Build::Warnings object.
109              
110             =back
111              
112             =cut
113              
114             sub new {
115 8     8 1 6331 my ($class, $params) = @_;
116 8 100 100     448 croak "Argument to constructor must be hashref"
117             unless (ref($params) && ref($params) eq "HASH");
118             croak "Argument to constructor must contain 'file' element"
119 5 100       105 unless exists $params->{file};
120 4 100       194 croak "Cannot locate $params->{file}" unless -f $params->{file};
121              
122 3         11 my $data = {};
123 3         8 while (my ($k,$v) = each %{$params}) {
  6         27  
124 3         14 $data->{$k} = $params->{$k};
125             }
126              
127 3         9 my $init = _parse_log_for_warnings($data);
128              
129 3         43 return bless $init, $class;
130             }
131              
132             sub _parse_log_for_warnings {
133 3     3   7 my $data = shift;
134 3         5 my @warnings = ();
135 3         8 my %warnings_groups = ();
136 3         5 my $IN;
137 3 100       15 if ($data->{file} =~ m/\.gz/) {
138 2         19 $IN = IO::Zlib->new($data->{file}, "rb");
139             }
140             else {
141 1         8 $IN = IO::File->new($data->{file}, "r");
142             }
143 3 50       6997 croak "Could not open filehandle to $data->file" unless defined $IN;
144 3         43 while (my $l = <$IN>) {
145 10253         818210 chomp $l;
146             # op.c:5468:34: warning: argument ‘o’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Wclobbered]
147 10253 100       36462 next unless $l =~ m{^
148             ([^:]+):
149             (\d+):
150             (\d+):\s+warning:\s+
151             (.*?)\s+\[-
152             (W.*)]$
153             }x;
154 394         2029 my ($source_file, $line, $char, $warning_text, $warnings_group) =
155             ($1, $2, $3, $4, $5);
156 394         757 $warnings_groups{$warnings_group}++;
157 394         2365 push @warnings, {
158             source => $source_file,
159             line => $line,
160             char => $char,
161             text => $warning_text,
162             group => $warnings_group,
163             };
164             }
165 3 50       410 $IN->close or croak "Unable to close handle after reading";
166 3         555 $data->{warnings_groups} = \%warnings_groups;
167 3         11 $data->{warnings} = \@warnings;
168 3         19 return $data;
169             }
170              
171             =head2 C
172              
173             =over 4
174              
175             =item * Purpose
176              
177             Identify the types of build-time warnings found in the F log and the number of each such type.
178              
179             =item * Arguments
180              
181             $hashref = $self->get_warnings_groups();
182              
183             None.
184              
185             =item * Return Value
186              
187             Reference to a hash whose elements are keyed on warnings classes (I
188             C). The value of each element is the number of times such class
189             appeared in the file.
190              
191             =back
192              
193             =cut
194              
195             sub get_warnings_groups {
196 3     3 1 7054 my $self = shift;
197 3         18 return $self->{warnings_groups};
198             }
199              
200             =head2 C
201              
202             =over 4
203              
204             =item * Purpose
205              
206             Pretty-print to STDOUT the information returned by C.
207              
208             =item * Arguments
209              
210             $self->report_warnings_groups;
211              
212             None.
213              
214             =item * Return Value
215              
216             Implicitly returns a Perl-true value.
217              
218             =item * Comment
219              
220             The information reported will appear as below (2 leading whitespaces), but may
221             change in the future.
222              
223             Wcast-function-type 6
224             Wclobbered 2
225             Wformat-overflow= 2
226             Wignored-qualifiers 4
227             Wimplicit-fallthrough= 32
228             Wmultistatement-macros 1
229             Wpragmas 3
230              
231             =back
232              
233             =cut
234              
235             sub report_warnings_groups {
236 3     3 1 5645 my $self = shift;
237 3         7 for my $w (sort keys %{$self->{warnings_groups}}) {
  3         53  
238 21         426 say sprintf " %-40s %3s" => $w, $self->{warnings_groups}{$w};
239             }
240             }
241              
242             =head2 C
243              
244             =over 4
245              
246             =item * Purpose
247              
248             Generate a list of all warnings.
249              
250             =item * Arguments
251              
252             $arrayref = $self->get_warnings();
253              
254             =item * Return Value
255              
256             Array reference, each element of which is a reference to a hash holding a parsing
257             of the elements of an individual warning.
258              
259             =back
260              
261             =cut
262              
263             sub get_warnings {
264 3     3 1 6408 my $self = shift;
265 3         90 return $self->{warnings};
266             }
267              
268             =head2 C
269              
270             =over 4
271              
272             =item * Purpose
273              
274             Get a list of all the warnings for one specified warnings group.
275              
276             =item * Arguments
277              
278             $arrayref = $self->get_warnings_for_group("Wduplicate-decl-specifier");
279              
280             String holding name of one group of warnings. Each such string must begin with an upper-case C. As mentioned above, we drop the leading hyphen to avoid confusing the shell.
281              
282             =item * Return Value
283              
284             Array reference, each element of which is a reference to a hash holding a parsing
285             of the elements of an individual warning of the specified warnings group.
286              
287             =back
288              
289             =cut
290              
291             sub get_warnings_for_group {
292 3     3 1 2297 my ($self, $wg) = @_;
293 3 100       180 croak "Name of warnings group must begin with 'W'" unless $wg =~ m/^W/;
294             croak "Warnings group '$wg' not found"
295 2 100       82 unless $self->{warnings_groups}->{$wg};
296              
297 1         2 return [ grep { $_->{group} eq $wg } @{$self->{warnings}} ];
  293         532  
  1         5  
298             }
299              
300             =head2 C
301              
302             =over 4
303              
304             =item * Purpose
305              
306             Get a list of all the warnings generated from one specified source file.
307              
308             =item * Arguments
309              
310             $arrayref = $self->get_warnings_for_source('op.c');
311              
312             String holding name of one source file. Note that there may be some ambiguity here. Use with caution.
313              
314             =item * Return Value
315              
316             Array reference, each element of which is a reference to a hash holding a parsing
317             of the elements of an individual warning of the specified warnings source.
318              
319             =back
320              
321             =cut
322              
323             sub get_warnings_for_source {
324 1     1 1 533 my ($self, $sf) = @_;
325              
326 1         3 return [ grep { $_->{source} eq $sf } @{$self->{warnings}} ];
  293         492  
  1         5  
327             }
328              
329             1;
330              
331             =head1 BUGS
332              
333             None reported so far. The author prefers patches filed at
334             L rather than pull requests at github.
335              
336             =head1 AUTHOR
337              
338             James E Keenan
339             CPAN ID: JKEENAN
340             jkeenan@cpan.org
341             http://thenceforward.net/perl/modules/Perl5-Build-Warnings/
342              
343             =head1 COPYRIGHT
344              
345             This program is free software; you can redistribute
346             it and/or modify it under the same terms as Perl itself.
347              
348             The full text of the license can be found in the
349             LICENSE file included with this module.
350              
351             =head1 SEE ALSO
352              
353             perl(1).
354              
355             =cut
356