From: Nicholas Clark Date: Fri, 20 Nov 2009 13:43:00 +0000 (+0000) Subject: Parse embed.fnc first, then cross-check consistency between it and =for apidoc X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=5ce5779215ef1e2ae554b5ea5a8c90b62c0729aa;p=p5sagit%2Fp5-mst-13.2.git Parse embed.fnc first, then cross-check consistency between it and =for apidoc --- diff --git a/autodoc.pl b/autodoc.pl index 37d40bd..28ca96e 100644 --- a/autodoc.pl +++ b/autodoc.pl @@ -26,8 +26,14 @@ use strict; # my %docs; -my %docfuncs; -my %seenfuncs; +my %funcflags; +my %macro = ( + ax => 1, + items => 1, + ix => 1, + svtype => 1, + ); +my %missing; my $curheader = "Unknown section"; @@ -36,6 +42,11 @@ sub autodoc ($$) { # parse a file and extract documentation info my($in, $doc, $line); FUNC: while (defined($in = <$fh>)) { + if ($in =~ /^#\s*define\s+([A-Za-z_][A-Za-z_0-9]+)\(/ && + ($file ne 'embed.h' || $file ne 'proto.h')) { + $macro{$1} = $file; + next FUNC; + } if ($in=~ /^=head1 (.*)/) { $curheader = $1; next FUNC; @@ -57,15 +68,49 @@ DOC: $docs .= $doc; } $docs = "\n$docs" if $docs and $docs !~ /^\n/; - if ($flags =~ /m/) { - my $where = $flags =~ /A/ ? 'api' : 'guts'; - $docs{$where}{$curheader}{$name} - = [$flags, $docs, $ret, $file, @args]; + + # Check the consistency of the flags + my ($embed_where, $inline_where); + my ($embed_may_change, $inline_may_change); + + my $docref = delete $funcflags{$name}; + if ($docref and %$docref) { + $embed_where = $docref->{flags} =~ /A/ ? 'api' : 'guts'; + $embed_may_change = $docref->{flags} =~ /M/; + } else { + $missing{$name} = $file; } - else { - $docfuncs{$name} = [$flags, $docs, $ret, $file, $curheader, @args]; + if ($flags =~ /m/) { + $inline_where = $flags =~ /A/ ? 'api' : 'guts'; + $inline_may_change = $flags =~ /x/; + + if (defined $embed_where && $inline_where ne $embed_where) { + warn "Function '$name' inconsistency: embed.fnc says $embed_where, Pod says $inline_where"; + } + + if (defined $embed_may_change + && $inline_may_change ne $embed_may_change) { + my $message = "Function '$name' inconsistency: "; + if ($embed_may_change) { + $message .= "embed.fnc says 'may change', Pod does not"; + } else { + $message .= "Pod says 'may change', embed.fnc does not"; + } + warn $message; + } + } elsif (!defined $embed_where) { + warn "Unable to place $name!\n"; + next; + } else { + $inline_where = $embed_where; + $flags .= 'x' if $embed_may_change; + @args = @{$docref->{args}}; + $ret = $docref->{retval}; } - $seenfuncs{$name} = 1; + + $docs{$inline_where}{$curheader}{$name} + = [$flags, $docs, $ret, $file, @args]; + if (defined $doc) { if ($doc =~ /^=(?:for|head)/) { $in = $doc; @@ -145,27 +190,8 @@ if (@ARGV) { or die "Couldn't chdir to '$workdir': $!"; } -my $file; -# glob() picks up docs from extra .c or .h files that may be in unclean -# development trees. -my $MANIFEST = do { - local ($/, *FH); - open FH, "MANIFEST" or die "Can't open MANIFEST: $!"; - ; -}; - -for $file (($MANIFEST =~ /^(\S+\.c)\t/gm), ($MANIFEST =~ /^(\S+\.h)\t/gm)) { - open F, "< $file" or die "Cannot open $file for docs: $!\n"; - $curheader = "Functions in file $file\n"; - autodoc(\*F,$file); - close F or die "Error closing $file: $!\n"; -} - open IN, "embed.fnc" or die $!; -# walk table providing an array of components in each line to -# subroutine, printing the result - while () { chomp; next if /^:/; @@ -178,37 +204,52 @@ while () { my ($flags, $retval, $func, @args) = split /\s*\|\s*/, $_; - next unless $flags =~ /d/; next unless $func; s/\b(NN|NULLOK)\b\s+//g for @args; $func =~ s/\t//g; # clean up fields from embed.pl $retval =~ s/\t//; - my $docref = delete $docfuncs{$func}; - if ($docref and @$docref) { - my $where; - if ($flags =~ /A/) { - $where = 'api'; - $docref->[0].="x" if $flags =~ /M/; - $docref->[0] .= 'A'; - } else { - $where = 'guts'; - } - $docs{$where}{$docref->[4]}{$func} = - [$docref->[0], $docref->[1], $retval, $docref->[3], @args]; - } - else { - warn "no docs for $func\n" unless $seenfuncs{$func}; - } + $funcflags{$func} = { + flags => $flags, + retval => $retval, + args => \@args, + }; +} + +my $file; +# glob() picks up docs from extra .c or .h files that may be in unclean +# development trees. +my $MANIFEST = do { + local ($/, *FH); + open FH, "MANIFEST" or die "Can't open MANIFEST: $!"; + ; +}; + +for $file (($MANIFEST =~ /^(\S+\.c)\t/gm), ($MANIFEST =~ /^(\S+\.h)\t/gm)) { + open F, "< $file" or die "Cannot open $file for docs: $!\n"; + $curheader = "Functions in file $file\n"; + autodoc(\*F,$file); + close F or die "Error closing $file: $!\n"; +} + +for (sort keys %funcflags) { + next unless $funcflags{$_}{flags} =~ /d/; + warn "no docs for $_\n" } -for (sort keys %docfuncs) { - # Have you used a full for apidoc or just a func name? - # Have you used Ap instead of Am in the for apidoc? - warn "Unable to place $_!\n"; +foreach (sort keys %missing) { + next if $macro{$_}; + # Heuristics for known not-a-function macros: + next if /^[A-Z]/; + next if /^dj?[A-Z]/; + + warn "Function '$_', documented in $missing{$_}, not listed in embed.fnc"; } +# walk table providing an array of components in each line to +# subroutine, printing the result + output('perlapi', <<'_EOB_', $docs{api}, <<'_EOE_'); =head1 NAME