| #!/usr/bin/env perl | |
| # Copyright 2009 The Go Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style | |
| # license that can be found in the LICENSE file. | |
| # This script checks that the compilers emit the errors which we expect. | |
| # Usage: errchk COMPILER [OPTS] SOURCEFILES. This will run the command | |
| # COMPILER [OPTS] SOURCEFILES. The compilation is expected to fail; if | |
| # it succeeds, this script will report an error. The stderr output of | |
| # the compiler will be matched against comments in SOURCEFILES. For each | |
| # line of the source files which should generate an error, there should | |
| # be a comment of the form // ERROR "regexp". If the compiler generates | |
| # an error for a line which has no such comment, this script will report | |
| # an error. Likewise if the compiler does not generate an error for a | |
| # line which has a comment, or if the error message does not match the | |
| # <regexp>. The <regexp> syntax is Perl but its best to stick to egrep. | |
| use POSIX; | |
| my $exitcode = 1; | |
| if(@ARGV >= 1 && $ARGV[0] eq "-0") { | |
| $exitcode = 0; | |
| shift; | |
| } | |
| if(@ARGV < 1) { | |
| print STDERR "Usage: errchk COMPILER [OPTS] SOURCEFILES\n"; | |
| exit 1; | |
| } | |
| # Grab SOURCEFILES | |
| foreach(reverse 0 .. @ARGV-1) { | |
| unless($ARGV[$_] =~ /\.(go|s)$/) { | |
| @file = @ARGV[$_+1 .. @ARGV-1]; | |
| last; | |
| } | |
| } | |
| # If no files have been specified try to grab SOURCEFILES from the last | |
| # argument that is an existing directory if any | |
| unless(@file) { | |
| foreach(reverse 0 .. @ARGV-1) { | |
| if(-d $ARGV[$_]) { | |
| @file = glob($ARGV[$_] . "/*.go"); | |
| last; | |
| } | |
| } | |
| } | |
| foreach $file (@file) { | |
| open(SRC, $file) || die "BUG: errchk: open $file: $!"; | |
| $src{$file} = [<SRC>]; | |
| close(SRC); | |
| } | |
| # Run command | |
| $cmd = join(' ', @ARGV); | |
| open(CMD, "exec $cmd </dev/null 2>&1 |") || die "BUG: errchk: run $cmd: $!"; | |
| # gc error messages continue onto additional lines with leading tabs. | |
| # Split the output at the beginning of each line that doesn't begin with a tab. | |
| $out = join('', <CMD>); | |
| @out = split(/^(?!\t)/m, $out); | |
| close CMD; | |
| if($exitcode != 0 && $? == 0) { | |
| print STDERR "BUG: errchk: command succeeded unexpectedly\n"; | |
| print STDERR @out; | |
| exit 0; | |
| } | |
| if($exitcode == 0 && $? != 0) { | |
| print STDERR "BUG: errchk: command failed unexpectedly\n"; | |
| print STDERR @out; | |
| exit 0; | |
| } | |
| if(!WIFEXITED($?)) { | |
| print STDERR "BUG: errchk: compiler crashed\n"; | |
| print STDERR @out, "\n"; | |
| exit 0; | |
| } | |
| sub bug() { | |
| if(!$bug++) { | |
| print STDERR "BUG: "; | |
| } | |
| } | |
| sub chk { | |
| my $file = shift; | |
| my $line = 0; | |
| my $regexp; | |
| my @errmsg; | |
| my @match; | |
| foreach my $src (@{$src{$file}}) { | |
| $line++; | |
| next if $src =~ m|////|; # double comment disables ERROR | |
| next unless $src =~ m|// (GC_)?ERROR (.*)|; | |
| my $all = $2; | |
| if($all !~ /^"([^"]*)"/) { | |
| print STDERR "$file:$line: malformed regexp\n"; | |
| next; | |
| } | |
| @errmsg = grep { /$file:$line[:[]/ } @out; | |
| @out = grep { !/$file:$line[:[]/ } @out; | |
| if(@errmsg == 0) { | |
| bug(); | |
| print STDERR "errchk: $file:$line: missing expected error: '$all'\n"; | |
| next; | |
| } | |
| foreach my $regexp ($all =~ /"([^"]*)"/g) { | |
| # Turn relative line number in message into absolute line number. | |
| if($regexp =~ /LINE(([+-])([0-9]+))?/) { | |
| my $n = $line; | |
| if(defined($1)) { | |
| if($2 eq "+") { | |
| $n += int($3); | |
| } else { | |
| $n -= int($3); | |
| } | |
| } | |
| $regexp = "$`$file:$n$'"; | |
| } | |
| @match = grep { /$regexp/ } @errmsg; | |
| if(@match == 0) { | |
| bug(); | |
| print STDERR "errchk: $file:$line: error messages do not match '$regexp'\n"; | |
| next; | |
| } | |
| @errmsg = grep { !/$regexp/ } @errmsg; | |
| } | |
| if(@errmsg != 0) { | |
| bug(); | |
| print STDERR "errchk: $file:$line: unmatched error messages:\n"; | |
| foreach my $l (@errmsg) { | |
| print STDERR "> $l"; | |
| } | |
| } | |
| } | |
| } | |
| foreach $file (@file) { | |
| chk($file) | |
| } | |
| if(@out != 0) { | |
| bug(); | |
| print STDERR "errchk: unmatched error messages:\n"; | |
| print STDERR "==================================================\n"; | |
| print STDERR @out; | |
| print STDERR "==================================================\n"; | |
| } | |
| exit 0; |