Author: infinoid Date: Wed Dec 31 11:18:48 2008 New Revision: 34719 Added: trunk/t/codingstd/c_arg_assert.t Modified: trunk/t/codingstd/c_indent.t trunk/tools/build/headerizer.pl
Log: [headerizer] From a suggestion from Nicholas Clark in http://www.nntp.perl.org/group/perl.perl6.internals/2008/12/msg49677.html , adapt headerizer to emit macros which assert() the definedness of arguments that should never be NULL. If I'm understanding c_functions.pod correctly, this means ARGIN(), ARGOUT(), ARGMOD() and NOTNULL(), but not the ARG*_NULLOK() variants. Also add t/codingstd/c_arg_assert.t to verify the resulting defines actually get used. And whitelist the generated #defines so they don't trigger failures in t/codingstd/c_indent.t. Added: trunk/t/codingstd/c_arg_assert.t ============================================================================== --- (empty file) +++ trunk/t/codingstd/c_arg_assert.t Wed Dec 31 11:18:48 2008 @@ -0,0 +1,73 @@ +#! perl +# Copyright (C) 2008, The Perl Foundation. +# $Id$ + +use strict; +use warnings; + +use lib qw( . lib ../lib ../../lib ); +use Test::More tests => 1; +use Parrot::Distribution; + +=head1 NAME + +t/codingstd/c_arg_assert.t - checks that all the headerizer asserts are used + +=head1 SYNOPSIS + + # test all files + % prove t/codingstd/c_arg_assert.t + +=head1 DESCRIPTION + +Finds all the argument guards generated by headerizer (asserts to enforce the +non-NULLness of specially marked pointers) are actually used. + +=head1 SEE ALSO + +L<docs/pdds/pdd07_codingstd.pod> + +=cut + +my @files = Parrot::Distribution->new()->get_c_language_files(); + +check_asserts(@files); + +sub check_asserts { + my @files = @_; + my @defines; + my %usages; + + # first, find the definitions and the usages + diag("finding definitions"); + foreach my $file (@files) { + my $path = $file->path(); + my @lines = ($file->read()); + foreach my $line (@lines) { + if($line =~ /^#define ASSERT_ARGS_([_a-zA-Z0-9]+)\s/s) { + push(@defines, $1); + } + if($line =~ /^\s+ASSERT_ARGS\(([_a-zA-Z0-9]+)\);/) { + $usages{$1} = 1; + } + } + } + + # next, cross reference them. + my @missing = grep { !exists($usages{$_}) } @defines; + ok(!scalar @missing); + if(scalar @missing) { + diag("unused assert macros found:"); + foreach my $missing (sort @missing) { + diag($missing); + } + diag(scalar(@missing) . " unused assert macros found in total."); + } +} + +# Local Variables: +# mode: cperl +# cperl-indent-level: 4 +# fill-column: 100 +# End: +# vim: expandtab shiftwidth=4: Modified: trunk/t/codingstd/c_indent.t ============================================================================== --- trunk/t/codingstd/c_indent.t (original) +++ trunk/t/codingstd/c_indent.t Wed Dec 31 11:18:48 2008 @@ -138,6 +138,7 @@ /x ) { + next if (m/ASSERT_ARGS_/); # autogenerated by headerizer my $indent = q{ } x (@stack); if ( $1 ne $indent ) { push @pp_indent => "$path:$line_cnt\n" Modified: trunk/tools/build/headerizer.pl ============================================================================== --- trunk/tools/build/headerizer.pl (original) +++ trunk/tools/build/headerizer.pl Wed Dec 31 11:18:48 2008 @@ -295,6 +295,32 @@ return (@attrs,@mods); } +sub asserts_from_args { + my @args = @_; + my @asserts; + + for my $arg (@args) { + if ( $arg =~ m{(ARGIN|ARGOUT|ARGMOD|NOTNULL)\((.+)\)} ) { + my $var = $2; + if($var =~ /\(*\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\)\s*\(/) { + # argument is a function pointer + $var = $1; + } + else { + # try to isolate the variable's name; + # strip off everything before the final space or asterisk. + $var =~ s[.+[* ]([^* ]+)$][$1]; + } + push( @asserts, "assert($var);" ); + } + if( $arg eq 'PARROT_INTERP' ) { + push( @asserts, "assert(interp);" ); + } + } + + return (@asserts); +} + sub make_function_decls { my @funcs = @_; @@ -305,8 +331,8 @@ my $decl = sprintf( "%s %s(", $func->{return_type}, $func->{name} ); $decl = "static $decl" if $func->{is_static}; - my @args = @{ $func->{args} }; - my @attrs = attrs_from_args( $func, @args ); + my @args = @{ $func->{args} }; + my @attrs = attrs_from_args( $func, @args ); for my $arg (@args) { if ( $arg =~ m{SHIM\((.+)\)} ) { @@ -348,6 +374,18 @@ push( @decls, $decl ); } + foreach my $func (@funcs) { + my @args = @{ $func->{args} }; + my @asserts = asserts_from_args( @args ); + + my $assert = "#define ASSERT_ARGS_" . $func->{name}; + if(@asserts) { + $assert .= ' '; + $assert .= join(" \\\n" . ' ' x length($assert), @asserts); + } + push(@decls, $assert); + } + return @decls; }
