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
}
os.Exit(exitCode)
}
- if !doPackage(".", flag.Args()) {
+ if doPackage(".", flag.Args(), nil) == nil {
warnf("no files checked")
}
os.Exit(exitCode)
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)
}
}
}
// 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()
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
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
}
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 {
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.
// "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"
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)
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.
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"):
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) {
}
}
+# 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>];