fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / t / codingstd / c_macro_args.t
blob8b3d3b97455406bdae98899d9e937c5219803b9c
1 #! perl
2 # Copyright (C) 2008-2010, Parrot Foundation.
3 # $Id$
5 use strict;
6 use warnings;
8 use lib qw( . lib ../lib ../../lib );
9 use Test::More tests => 1;
10 use Parrot::Distribution;
12 =head1 NAME
14 t/codingstd/c_macro_args.t
16 =head1 SYNOPSIS
18     # test all files
19     % prove t/codingstd/c_macro_args.t
21     # test specific files
22     % perl t/codingstd/c_macro_args.t src/foo.t include/parrot/bar.h
24 =head1 DESCRIPTION
26 Checks that no C source file in the distribution has unsafe macro args.
28 =head1 SEE ALSO
30 L<docs/pdds/pdd07_codingstd.pod>
32 =cut
34 my $DIST = Parrot::Distribution->new();
35 my @files = @ARGV ? <@ARGV> : $DIST->get_c_language_files();
37 check_macro_args(@files);
39 sub check_macro_args {
40     my @files = @_;
42     my @defines;
43     foreach my $file (@files) {
44         my $path = @ARGV ? $file : $file->path();
45         my $buf = $DIST->slurp($path);
46         $buf =~ s{ (?:
47                        (?: ' (?: \\\\ | \\' | [^'] )* ' )  # remove ' string
48                      | (?: " (?: \\\\ | \\" | [^"] )* " )  # remove " string
49                      | /\*[^@] .*? \*/                     # remove C comment
50                    )
51                 }{}gsx;
53         # combine lines extended with \\n
54         $buf =~ s/\\\n//g;
56         while ( $buf =~ m{ ^ \s* \# \s* define \s+ ([a-zA-Z_]+)  \( ([^)]+) \)  ([^\n]*) }smgx ) {
57             my ($macro,$args,$definition) = ($1, $2, $3);
58             # for each of these args, verify it's wrapped in parens each time
59             # it's referenced in the definition.
60             if ($definition ne "") {
61                 foreach my $arg (split /\s*,\s*/, $args) {
63                     # skip args that are code blocks
64                     next if $arg eq '_code';
66                     # eliminate any properly formed usage of the macro arg
67                     $definition =~ s/\Q($arg)//g;
68                     $definition =~ s/\Q[$arg]//g;
69                     $definition =~ s/\Q<$arg>//g;
71                     # eliminate concatenations
72                     $definition =~ s/\Q$arg ##//g;
73                     $definition =~ s/\Q## $arg//g;
75                     # eliminate stringifications
76                     $definition =~ s/\Q#$arg//g;
78                     # eliminate args used as types
79                     $definition =~ s/\Q$arg\E[ ]+\*//g;
81                     # eliminate all function argument instrumentation macros
82                     next if $definition =~ m/\*@[\w ]+@\*/;
84                     # eliminate args used as function names
85                     # (this match is naive, but it catches the one place where
86                     # this is used)
87                     $definition =~ s/\Q$arg\E\([^)]*\)//g;
89                     # eliminate macros that deal with flags, since they're special
90                     next if $macro =~ m/(TEST|SET|CLEAR)$/;
92                     # skip those two varargs macros, already called as TRACE_PRINTF((args))
93                     next if $macro =~ m/^TRACE_PRINTF(_VAL|_ALIGN)?$/;
95                     # Any remaining usage must be improper
96                     if ($definition =~ m/\b\Q$arg\E\b/) {
97                         push (@defines, "$path: $macro has unwrapped arg: $arg\n");
98                     }
99                 }
100             }
101         }
102     }
104     my $ndefines = scalar @defines;
105     is( $ndefines, 0, 'Check for unwrapped macro arguments' )
106         or diag( "$ndefines unsafe macro args found:\n@defines\nThat's $ndefines of 'em!" );
109 # Local Variables:
110 #   mode: cperl
111 #   cperl-indent-level: 4
112 #   fill-column: 100
113 # End:
114 # vim: expandtab shiftwidth=4: