diff --git a/cmd/vet/Makefile b/cmd/vet/Makefile index 7b3a6da4..3e0a4182 100644 --- a/cmd/vet/Makefile +++ b/cmd/vet/Makefile @@ -4,11 +4,11 @@ # Assumes go/types is installed test testshort: - go build -tags 'vet_test gotypes' + go build $(GOROOT)/test/errchk ./vet -printfuncs='Warn:1,Warnf:1' test_*.go test_*.s -test_notypes: - go build -tags 'vet_test' - # Only those tests that do not depend on types. - # Excluded: test_print.go - $(GOROOT)/test/errchk ./vet -printfuncs='Warn:1,Warnf:1' test_asm.go test_assign.go test_atomic.go test_buildtag.go test_buildtag_bad.go test_deadcode.go test_method.go test_rangeloop.go test_structtag.go test_taglit.go test_*.s +# Install command where the go tool can find it. +install: + go build -o _vet + cp _vet $(GOROOT)/pkg/tool/$(GOOS)_$(GOARCH)/vet + rm -f _vet diff --git a/cmd/vet/main.go b/cmd/vet/main.go index b3d12d09..c8b6fe70 100644 --- a/cmd/vet/main.go +++ b/cmd/vet/main.go @@ -20,6 +20,9 @@ import ( "path/filepath" "strconv" "strings" + + "code.google.com/p/go.tools/go/exact" + "code.google.com/p/go.tools/go/types" ) var verbose = flag.Bool("v", false, "verbose") @@ -41,6 +44,8 @@ var report = map[string]*bool{ "unreachable": flag.Bool("unreachable", false, "check for unreachable code"), } +// TODO: Need a flag to set build tags when parsing the package. + // vet tells whether to report errors for the named check, a flag name. func vet(name string) bool { return *report["all"] || *report[name] @@ -136,7 +141,7 @@ func main() { } return } - doPackage(flag.Args()) + doPackage(".", flag.Args()) os.Exit(exitCode) } @@ -168,23 +173,24 @@ 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(names) + doPackage(directory, names) // 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(names) + doPackage(directory, names) } } type Package struct { - types map[ast.Expr]Type - values map[ast.Expr]ExactValue + path string + types map[ast.Expr]types.Type + values map[ast.Expr]exact.Value files []*File } // doPackage analyzes the single package constructed from the named files. -func doPackage(names []string) { +func doPackage(directory string, names []string) { var files []*File var astFiles []*ast.File fs := token.NewFileSet() @@ -214,6 +220,7 @@ func doPackage(names []string) { files = append(files, &File{fset: fs, content: data, name: name, file: parsedFile}) } pkg := new(Package) + pkg.path = directory pkg.files = files // Type check the package. err := pkg.check(fs, astFiles) diff --git a/cmd/vet/types.go b/cmd/vet/types.go index f3f0f0a9..d42a1d55 100644 --- a/cmd/vet/types.go +++ b/cmd/vet/types.go @@ -2,11 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build gotypes - -// This file contains the pieces of the tool that require the go/types package. -// To compile this file, you must first run -// $ go get code.google.com/p/go.tools/go/types +// This file contains the pieces of the tool that use typechecking from the go/types package. package main @@ -18,22 +14,9 @@ import ( "code.google.com/p/go.tools/go/types" ) -// Type is equivalent to types.Type. Repeating it here allows us to avoid -// having main depend on the go/types package. -type Type interface { - String() string -} - -// ExactValue is equivalent to exact.Value. Repeating it here allows us to -// avoid having main depend on the go/exact package. -type ExactValue interface { - Kind() exact.Kind - String() string -} - func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error { - pkg.types = make(map[ast.Expr]Type) - pkg.values = make(map[ast.Expr]ExactValue) + pkg.types = make(map[ast.Expr]types.Type) + pkg.values = make(map[ast.Expr]exact.Value) exprFn := func(x ast.Expr, typ types.Type, val exact.Value) { pkg.types[x] = typ if val != nil { @@ -46,7 +29,7 @@ func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error { Expr: exprFn, Error: func(error) {}, } - _, err := context.Check(fs, astFiles) + _, err := context.Check(pkg.path, fs, astFiles...) return err } @@ -55,10 +38,11 @@ func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error { func (pkg *Package) isStruct(c *ast.CompositeLit) (bool, string) { // Check that the CompositeLit's type is a slice or array (which needs no tag), if possible. typ := pkg.types[c] - // If it's a named type, pull out the underlying type. + // If it's a named type, pull out the underlying type. If it's not, the Underlying + // method returns the type itself. actual := typ - if namedType, ok := typ.(*types.NamedType); ok { - actual = namedType.Underlying + if actual != nil { + actual = actual.Underlying() } if actual == nil { // No type information available. Assume true, so we do the check. @@ -82,7 +66,7 @@ func (f *File) matchArgType(t printfArgType, arg ast.Expr) bool { if !ok { return true } - switch basic.Kind { + switch basic.Kind() { case types.Bool: return t&argBool != 0 case types.Int, types.Int8, types.Int16, types.Int32, types.Int64: @@ -136,7 +120,7 @@ func (f *File) numArgsInSignature(call *ast.CallExpr) int { if !ok { return 0 } - return len(sig.Params) + return sig.Params().Len() } // isErrorMethodCall reports whether the call is of a method with signature @@ -168,16 +152,16 @@ func (f *File) isErrorMethodCall(call *ast.CallExpr) bool { return false } // There must be no arguments. Already verified by type checking, but be thorough. - if len(sig.Params) > 0 { + if sig.Params().Len() > 0 { return false } // Finally the real questions. // There must be one result. - if len(sig.Results) != 1 { + if sig.Results().Len() != 1 { return false } // It must have return type "string" from the universe. - result := sig.Results[0].Type + result := sig.Results().At(0).Type() if types.IsIdentical(result, types.Typ[types.String]) { return true } diff --git a/cmd/vet/typestub.go b/cmd/vet/typestub.go deleted file mode 100644 index 74a3b13e..00000000 --- a/cmd/vet/typestub.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2010 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. - -// +build !gotypes - -// This file contains stubs for the pieces of the tool that require the go/types package, -// to be used if go/types is not available. - -package main - -import ( - "go/ast" - "go/token" -) - -// Type is equivalent to go/types.Type. Repeating it here allows us to avoid -// having main depend on the go/types package. -type Type interface { - String() string -} - -// ExactValue is a stub for exact.Value. Stubbing it here allows us to -// avoid having main depend on the go/exact package. -type ExactValue interface { -} - -func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error { - return nil -} - -func (pkg *Package) isStruct(c *ast.CompositeLit) (bool, string) { - return true, "" // Assume true, so we do the check. -} - -func (f *File) matchArgType(t printfArgType, arg ast.Expr) bool { - return true // We can't tell without types. -} - -func (f *File) numArgsInSignature(call *ast.CallExpr) int { - return 0 // We don't know. -} - -func (f *File) isErrorMethodCall(call *ast.CallExpr) bool { - // Is it a selector expression? Otherwise it's a function call, not a method call. - if _, ok := call.Fun.(*ast.SelectorExpr); !ok { - return false - } - return true // Best guess we can make without types. -}