2 # Copyright (C) 2008-2010, Parrot Foundation.
8 use lib qw( . lib ../lib ../../lib );
9 use Test::More tests => 1;
10 use Parrot::Distribution;
14 t/codingstd/c_macro_args.t
19 % prove t/codingstd/c_macro_args.t
22 % perl t/codingstd/c_macro_args.t src/foo.t include/parrot/bar.h
26 Checks that no C source file in the distribution has unsafe macro args.
30 L<docs/pdds/pdd07_codingstd.pod>
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 {
43 foreach my $file (@files) {
44 my $path = @ARGV ? $file : $file->path();
45 my $buf = $DIST->slurp($path);
47 (?: ' (?: \\\\ | \\' | [^'] )* ' ) # remove ' string
48 | (?: " (?: \\\\ | \\" | [^"] )* " ) # remove " string
49 | /\*[^@] .*? \*/ # remove C comment
53 # combine lines extended with \\n
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
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");
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!" );
111 # cperl-indent-level: 4
114 # vim: expandtab shiftwidth=4: