diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go index 8212a14f03..4f3cca8f6d 100644 --- a/src/cmd/vet/main.go +++ b/src/cmd/vet/main.go @@ -182,6 +182,9 @@ type File struct { file *ast.File b bytes.Buffer // for use by methods + // Parsed package "foo" when checking package "foo_test" + basePkg *Package + // The objects that are receivers of a "String() string" method. // This is used by the recursiveStringer method in print.go. stringers map[*ast.Object]bool @@ -238,7 +241,7 @@ func main() { } os.Exit(exitCode) } - if !doPackage(".", flag.Args()) { + if doPackage(".", flag.Args(), nil) == nil { warnf("no files checked") } os.Exit(exitCode) @@ -278,12 +281,12 @@ func doPackageDir(directory string) { names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package. names = append(names, pkg.SFiles...) prefixDirectory(directory, names) - doPackage(directory, names) + basePkg := doPackage(directory, names, nil) // Is there also a "foo_test" package? If so, do that one as well. if len(pkg.XTestGoFiles) > 0 { names = pkg.XTestGoFiles prefixDirectory(directory, names) - doPackage(directory, names) + doPackage(directory, names, basePkg) } } @@ -299,8 +302,8 @@ type Package struct { } // doPackage analyzes the single package constructed from the named files. -// It returns whether any files were checked. -func doPackage(directory string, names []string) bool { +// It returns the parsed Package or nil if none of the files have been checked. +func doPackage(directory string, names []string, basePkg *Package) *Package { var files []*File var astFiles []*ast.File fs := token.NewFileSet() @@ -309,7 +312,7 @@ func doPackage(directory string, names []string) bool { if err != nil { // Warn but continue to next package. warnf("%s: %s", name, err) - return false + return nil } checkBuildTag(name, data) var parsedFile *ast.File @@ -317,14 +320,14 @@ func doPackage(directory string, names []string) bool { parsedFile, err = parser.ParseFile(fs, name, data, 0) if err != nil { warnf("%s: %s", name, err) - return false + return nil } astFiles = append(astFiles, parsedFile) } files = append(files, &File{fset: fs, content: data, name: name, file: parsedFile}) } if len(astFiles) == 0 { - return false + return nil } pkg := new(Package) pkg.path = astFiles[0].Name.Name @@ -346,13 +349,14 @@ func doPackage(directory string, names []string) bool { } for _, file := range files { file.pkg = pkg + file.basePkg = basePkg file.checkers = chk if file.file != nil { file.walkFile(file.name, file.file) } } asmCheck(pkg) - return true + return pkg } func visit(path string, f os.FileInfo, err error) error { diff --git a/src/cmd/vet/testdata/divergent/buf_test.go b/src/cmd/vet/testdata/divergent/buf_test.go index 6b9cba3f01..b75d55eaf4 100644 --- a/src/cmd/vet/testdata/divergent/buf_test.go +++ b/src/cmd/vet/testdata/divergent/buf_test.go @@ -4,11 +4,11 @@ package buf_test func Example() {} // OK because is package-level. -func Example_suffix() // OK because refers to suffix annotation. +func Example_suffix() {} // OK because refers to suffix annotation. -func Example_BadSuffix() // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix" +func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix" -func ExampleBuf() // OK because refers to known top-level type. +func ExampleBuf() {} // OK because refers to known top-level type. func ExampleBuf_Append() {} // OK because refers to known method. @@ -28,8 +28,8 @@ func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic" // "Puffer" is German for "Buffer". -func ExamplePuffer() // ERROR "ExamplePuffer refers to unknown identifier: Puffer" +func ExamplePuffer() {} // ERROR "ExamplePuffer refers to unknown identifier: Puffer" -func ExamplePuffer_Append() // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer" +func ExamplePuffer_Append() {} // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer" -func ExamplePuffer_suffix() // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer" +func ExamplePuffer_suffix() {} // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer" diff --git a/src/cmd/vet/tests.go b/src/cmd/vet/tests.go index 076835b980..8c051f1336 100644 --- a/src/cmd/vet/tests.go +++ b/src/cmd/vet/tests.go @@ -59,23 +59,28 @@ func lookup(name string, scopes []*types.Scope) types.Object { return nil } -func extendedScope(pkg *Package) []*types.Scope { - scopes := []*types.Scope{pkg.typesPkg.Scope()} - - pkgName := pkg.typesPkg.Name() - if strings.HasSuffix(pkgName, "_test") { - basePkg := strings.TrimSuffix(pkgName, "_test") - for _, p := range pkg.typesPkg.Imports() { - if p.Name() == basePkg { - scopes = append(scopes, p.Scope()) - break +func extendedScope(f *File) []*types.Scope { + scopes := []*types.Scope{f.pkg.typesPkg.Scope()} + if f.basePkg != nil { + scopes = append(scopes, f.basePkg.typesPkg.Scope()) + } else { + // If basePkg is not specified (e.g. when checking a single file) try to + // find it among imports. + pkgName := f.pkg.typesPkg.Name() + if strings.HasSuffix(pkgName, "_test") { + basePkgName := strings.TrimSuffix(pkgName, "_test") + for _, p := range f.pkg.typesPkg.Imports() { + if p.Name() == basePkgName { + scopes = append(scopes, p.Scope()) + break + } } } } return scopes } -func checkExample(fn *ast.FuncDecl, pkg *Package, report reporter) { +func checkExample(fn *ast.FuncDecl, f *File, report reporter) { fnName := fn.Name.Name if params := fn.Type.Params; len(params.List) != 0 { report("%s should be niladic", fnName) @@ -100,7 +105,7 @@ func checkExample(fn *ast.FuncDecl, pkg *Package, report reporter) { exName = strings.TrimPrefix(fnName, "Example") elems = strings.SplitN(exName, "_", 3) ident = elems[0] - obj = lookup(ident, extendedScope(pkg)) + obj = lookup(ident, extendedScope(f)) ) if ident != "" && obj == nil { // Check ExampleFoo and ExampleBadFoo. @@ -173,7 +178,7 @@ func checkTestFunctions(f *File, node ast.Node) { switch { case strings.HasPrefix(fn.Name.Name, "Example"): - checkExample(fn, f.pkg, report) + checkExample(fn, f, report) case strings.HasPrefix(fn.Name.Name, "Test"): checkTest(fn, "Test", report) case strings.HasPrefix(fn.Name.Name, "Benchmark"): diff --git a/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go index 2dd8ae4053..31d4b9001d 100644 --- a/src/cmd/vet/vet_test.go +++ b/src/cmd/vet/vet_test.go @@ -102,7 +102,7 @@ func TestVet(t *testing.T) { func TestDivergentPackagesExamples(t *testing.T) { Build(t) // errchk ./testvet - Vet(t, []string{"testdata/divergent/buf.go", "testdata/divergent/buf_test.go"}) + Vet(t, []string{"testdata/divergent"}) } func TestIncompleteExamples(t *testing.T) { diff --git a/test/errchk b/test/errchk index b07bbc739d..bc8ef19cb0 100755 --- a/test/errchk +++ b/test/errchk @@ -37,6 +37,17 @@ foreach(reverse 0 .. @ARGV-1) { } } +# 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} = [];