mirror of
https://github.com/golang/go
synced 2024-11-19 17:04:41 -07:00
cmd/vet: accept package config from go command
This CL adds support for accepting package config from the go command. Paired with CL 74356 this lets us make sure vet has complete information about package sources. This fixes many issues (see CL 74356 for the list), including mishandling of cgo and vendoring. Change-Id: Ia4a1dce6f9b1b0a8ef5fdf9005a20a8b294969f1 Reviewed-on: https://go-review.googlesource.com/74355 Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
f1fa663b6d
commit
4fe42799a8
@ -8,14 +8,17 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/importer"
|
||||
"go/parser"
|
||||
"go/printer"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -30,6 +33,8 @@ var (
|
||||
source = flag.Bool("source", false, "import from source instead of compiled object files")
|
||||
tags = flag.String("tags", "", "space-separated list of build tags to apply when parsing")
|
||||
tagList = []string{} // exploded version of tags flag; set in main
|
||||
|
||||
mustTypecheck bool
|
||||
)
|
||||
|
||||
var exitCode = 0
|
||||
@ -226,6 +231,18 @@ func main() {
|
||||
if flag.NArg() == 0 {
|
||||
Usage()
|
||||
}
|
||||
|
||||
// Special case for "go vet" passing an explicit configuration:
|
||||
// single argument ending in vet.cfg.
|
||||
// Once we have a more general mechanism for obtaining this
|
||||
// information from build tools like the go command,
|
||||
// vet should be changed to use it. This vet.cfg hack is an
|
||||
// experiment to learn about what form that information should take.
|
||||
if flag.NArg() == 1 && strings.HasSuffix(flag.Arg(0), "vet.cfg") {
|
||||
doPackageCfg(flag.Arg(0))
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
for _, name := range flag.Args() {
|
||||
// Is it a directory?
|
||||
fi, err := os.Stat(name)
|
||||
@ -266,6 +283,65 @@ func prefixDirectory(directory string, names []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// vetConfig is the JSON config struct prepared by the Go command.
|
||||
type vetConfig struct {
|
||||
Compiler string
|
||||
Dir string
|
||||
GoFiles []string
|
||||
ImportMap map[string]string
|
||||
PackageFile map[string]string
|
||||
|
||||
imp types.Importer
|
||||
}
|
||||
|
||||
func (v *vetConfig) Import(path string) (*types.Package, error) {
|
||||
if v.imp == nil {
|
||||
v.imp = importer.For(v.Compiler, v.openPackageFile)
|
||||
}
|
||||
if path == "unsafe" {
|
||||
return v.imp.Import("unsafe")
|
||||
}
|
||||
p := v.ImportMap[path]
|
||||
if p == "" {
|
||||
return nil, fmt.Errorf("unknown import path %q", path)
|
||||
}
|
||||
if v.PackageFile[p] == "" {
|
||||
return nil, fmt.Errorf("unknown package file for import %q", path)
|
||||
}
|
||||
return v.imp.Import(p)
|
||||
}
|
||||
|
||||
func (v *vetConfig) openPackageFile(path string) (io.ReadCloser, error) {
|
||||
file := v.PackageFile[path]
|
||||
if file == "" {
|
||||
// Note that path here has been translated via v.ImportMap,
|
||||
// unlike in the error in Import above. We prefer the error in
|
||||
// Import, but it's worth diagnosing this one too, just in case.
|
||||
return nil, fmt.Errorf("unknown package file for %q", path)
|
||||
}
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// doPackageCfg analyzes a single package described in a config file.
|
||||
func doPackageCfg(cfgFile string) {
|
||||
js, err := ioutil.ReadFile(cfgFile)
|
||||
if err != nil {
|
||||
errorf("%v", err)
|
||||
}
|
||||
var vcfg vetConfig
|
||||
if err := json.Unmarshal(js, &vcfg); err != nil {
|
||||
errorf("parsing vet config %s: %v", cfgFile, err)
|
||||
}
|
||||
stdImporter = &vcfg
|
||||
inittypes()
|
||||
mustTypecheck = true
|
||||
doPackage(vcfg.GoFiles, nil)
|
||||
}
|
||||
|
||||
// doPackageDir analyzes the single package found in the directory, if there is one,
|
||||
// plus a test package, if there is one.
|
||||
func doPackageDir(directory string) {
|
||||
@ -353,6 +429,9 @@ func doPackage(names []string, basePkg *Package) *Package {
|
||||
if err != nil {
|
||||
// Note that we only report this error when *verbose.
|
||||
Println(err)
|
||||
if mustTypecheck {
|
||||
errorf("%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Check.
|
||||
|
Loading…
Reference in New Issue
Block a user