summaryrefslogtreecommitdiff
path: root/libgo/go/golang.org/x/tools
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-09-06 18:12:46 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-09-06 18:12:46 +0000
commitaa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13 (patch)
tree7e63b06d1eec92beec6997c9d3ab47a5d6a835be /libgo/go/golang.org/x/tools
parent920ea3b8ba3164b61ac9490dfdfceb6936eda6dd (diff)
downloadgcc-aa8901e9bb0399d2c16f988ba2fe46eb0c0c5d13.tar.gz
libgo: update to Go 1.13beta1 release
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/193497 From-SVN: r275473
Diffstat (limited to 'libgo/go/golang.org/x/tools')
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/analysis.go40
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/doc.go2
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go59
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/help.go3
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/patch.go7
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go39
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/bools/bools.go21
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go8
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/composite/composite.go11
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go75
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/inspect/inspect.go6
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go17
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go45
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/printf/types.go5
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/shift/shift.go31
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go17
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/structtag/structtag.go76
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/tests/tests.go49
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go7
-rw-r--r--libgo/go/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go1
-rw-r--r--libgo/go/golang.org/x/tools/go/ast/inspector/inspector.go2
21 files changed, 383 insertions, 138 deletions
diff --git a/libgo/go/golang.org/x/tools/go/analysis/analysis.go b/libgo/go/golang.org/x/tools/go/analysis/analysis.go
index 21baa02a8de..19e1e421a38 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/analysis.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/analysis.go
@@ -87,6 +87,7 @@ type Pass struct {
OtherFiles []string // names of non-Go files of this package
Pkg *types.Package // type information about the package
TypesInfo *types.Info // type information about the syntax trees
+ TypesSizes types.Sizes // function for computing sizes of types
// Report reports a Diagnostic, a finding about a specific location
// in the analyzed source code such as a potential mistake.
@@ -127,10 +128,32 @@ type Pass struct {
// See comments for ExportObjectFact.
ExportPackageFact func(fact Fact)
+ // AllPackageFacts returns a new slice containing all package facts in unspecified order.
+ // WARNING: This is an experimental API and may change in the future.
+ AllPackageFacts func() []PackageFact
+
+ // AllObjectFacts returns a new slice containing all object facts in unspecified order.
+ // WARNING: This is an experimental API and may change in the future.
+ AllObjectFacts func() []ObjectFact
+
/* Further fields may be added in future. */
// For example, suggested or applied refactorings.
}
+// PackageFact is a package together with an associated fact.
+// WARNING: This is an experimental API and may change in the future.
+type PackageFact struct {
+ Package *types.Package
+ Fact Fact
+}
+
+// ObjectFact is an object together with an associated fact.
+// WARNING: This is an experimental API and may change in the future.
+type ObjectFact struct {
+ Object types.Object
+ Fact Fact
+}
+
// Reportf is a helper function that reports a Diagnostic using the
// specified position and formatted error message.
func (pass *Pass) Reportf(pos token.Pos, format string, args ...interface{}) {
@@ -138,6 +161,15 @@ func (pass *Pass) Reportf(pos token.Pos, format string, args ...interface{}) {
pass.Report(Diagnostic{Pos: pos, Message: msg})
}
+// reportNodef is a helper function that reports a Diagnostic using the
+// range denoted by the AST node.
+//
+// WARNING: This is an experimental API and may change in the future.
+func (pass *Pass) reportNodef(node ast.Node, format string, args ...interface{}) {
+ msg := fmt.Sprintf(format, args...)
+ pass.Report(Diagnostic{Pos: node.Pos(), End: node.End(), Message: msg})
+}
+
func (pass *Pass) String() string {
return fmt.Sprintf("%s@%s", pass.Analyzer.Name, pass.Pkg.Path())
}
@@ -180,13 +212,17 @@ type Fact interface {
AFact() // dummy method to avoid type errors
}
-// A Diagnostic is a message associated with a source location.
+// A Diagnostic is a message associated with a source location or range.
//
// An Analyzer may return a variety of diagnostics; the optional Category,
// which should be a constant, may be used to classify them.
// It is primarily intended to make it easy to look up documentation.
+//
+// If End is provided, the diagnostic is specified to apply to the range between
+// Pos and End.
type Diagnostic struct {
Pos token.Pos
- Category string // optional
+ End token.Pos // optional
+ Category string // optional
Message string
}
diff --git a/libgo/go/golang.org/x/tools/go/analysis/doc.go b/libgo/go/golang.org/x/tools/go/analysis/doc.go
index f925849ab50..2d44b0458a9 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/doc.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/doc.go
@@ -246,7 +246,7 @@ An Analyzer that uses facts must declare their types:
var Analyzer = &analysis.Analyzer{
Name: "printf",
- FactTypes: []reflect.Type{reflect.TypeOf(new(isWrapper))},
+ FactTypes: []analysis.Fact{new(isWrapper)},
...
}
diff --git a/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go b/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go
index 729ac3b4176..a3c2f096300 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/flags.go
@@ -8,6 +8,7 @@ package analysisflags
import (
"crypto/sha256"
+ "encoding/gob"
"encoding/json"
"flag"
"fmt"
@@ -32,6 +33,14 @@ var (
// including (in multi mode) a flag named after the analyzer,
// parses the flags, then filters and returns the list of
// analyzers enabled by flags.
+//
+// The result is intended to be passed to unitchecker.Run or checker.Run.
+// Use in unitchecker.Run will gob.Register all fact types for the returned
+// graph of analyzers but of course not the ones only reachable from
+// dropped analyzers. To avoid inconsistency about which gob types are
+// registered from run to run, Parse itself gob.Registers all the facts
+// only reachable from dropped analyzers.
+// This is not a particularly elegant API, but this is an internal package.
func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer {
// Connect each analysis flag to the command line as -analysis.flag.
enabled := make(map[*analysis.Analyzer]*triState)
@@ -88,6 +97,8 @@ func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer {
os.Exit(0)
}
+ everything := expand(analyzers)
+
// If any -NAME flag is true, run only those analyzers. Otherwise,
// if any -NAME flag is false, run all but those analyzers.
if multi {
@@ -119,9 +130,35 @@ func Parse(analyzers []*analysis.Analyzer, multi bool) []*analysis.Analyzer {
}
}
+ // Register fact types of skipped analyzers
+ // in case we encounter them in imported files.
+ kept := expand(analyzers)
+ for a := range everything {
+ if !kept[a] {
+ for _, f := range a.FactTypes {
+ gob.Register(f)
+ }
+ }
+ }
+
return analyzers
}
+func expand(analyzers []*analysis.Analyzer) map[*analysis.Analyzer]bool {
+ seen := make(map[*analysis.Analyzer]bool)
+ var visitAll func([]*analysis.Analyzer)
+ visitAll = func(analyzers []*analysis.Analyzer) {
+ for _, a := range analyzers {
+ if !seen[a] {
+ seen[a] = true
+ visitAll(a.Requires)
+ }
+ }
+ }
+ visitAll(analyzers)
+ return seen
+}
+
func printFlags() {
type jsonFlag struct {
Name string
@@ -152,12 +189,13 @@ func printFlags() {
// addVersionFlag registers a -V flag that, if set,
// prints the executable version and exits 0.
//
-// It is a variable not a function to permit easy
-// overriding in the copy vendored in $GOROOT/src/cmd/vet:
-//
-// func init() { addVersionFlag = objabi.AddVersionFlag }
-var addVersionFlag = func() {
- flag.Var(versionFlag{}, "V", "print version and exit")
+// If the -V flag already exists — for example, because it was already
+// registered by a call to cmd/internal/objabi.AddVersionFlag — then
+// addVersionFlag does nothing.
+func addVersionFlag() {
+ if flag.Lookup("V") == nil {
+ flag.Var(versionFlag{}, "V", "print version and exit")
+ }
}
// versionFlag minimally complies with the -V protocol required by "go vet".
@@ -285,9 +323,14 @@ func PrintPlain(fset *token.FileSet, diag analysis.Diagnostic) {
// -c=N: show offending line plus N lines of context.
if Context >= 0 {
+ posn := fset.Position(diag.Pos)
+ end := fset.Position(diag.End)
+ if !end.IsValid() {
+ end = posn
+ }
data, _ := ioutil.ReadFile(posn.Filename)
lines := strings.Split(string(data), "\n")
- for i := posn.Line - Context; i <= posn.Line+Context; i++ {
+ for i := posn.Line - Context; i <= end.Line+Context; i++ {
if 1 <= i && i <= len(lines) {
fmt.Fprintf(os.Stderr, "%d\t%s\n", i, lines[i-1])
}
@@ -315,6 +358,8 @@ func (tree JSONTree) Add(fset *token.FileSet, id, name string, diags []analysis.
Message string `json:"message"`
}
var diagnostics []jsonDiagnostic
+ // TODO(matloob): Should the JSON diagnostics contain ranges?
+ // If so, how should they be formatted?
for _, f := range diags {
diagnostics = append(diagnostics, jsonDiagnostic{
Category: f.Category,
diff --git a/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/help.go b/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/help.go
index 043b97896dd..c5a70f3b7d6 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/help.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/help.go
@@ -4,6 +4,7 @@ import (
"flag"
"fmt"
"log"
+ "os"
"sort"
"strings"
@@ -47,6 +48,7 @@ func Help(progname string, analyzers []*analysis.Analyzer, args []string) {
fs.Var(f.Value, f.Name, f.Usage)
}
})
+ fs.SetOutput(os.Stdout)
fs.PrintDefaults()
fmt.Printf("\nTo see details and flags of a specific analyzer, run '%s help name'.\n", progname)
@@ -75,6 +77,7 @@ outer:
}
fs.Var(f.Value, a.Name+"."+f.Name, f.Usage)
})
+ fs.SetOutput(os.Stdout)
fs.PrintDefaults()
if len(paras) > 1 {
diff --git a/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/patch.go b/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/patch.go
deleted file mode 100644
index 8f9741055cb..00000000000
--- a/libgo/go/golang.org/x/tools/go/analysis/internal/analysisflags/patch.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package analysisflags
-
-import "cmd/internal/objabi"
-
-// This additional file changes the behavior of the vendored code.
-
-func init() { addVersionFlag = objabi.AddVersionFlag }
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go b/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
index dce1ef7bd5e..d41c4e97e32 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
@@ -114,7 +114,8 @@ func init() {
// library we cannot assume types.SizesFor is consistent with arches.
// For now, assume 64-bit norms and print a warning.
// But this warning should really be deferred until we attempt to use
- // arch, which is very unlikely.
+ // arch, which is very unlikely. Better would be
+ // to defer size computation until we have Pass.TypesSizes.
arch.sizes = types.SizesFor("gc", "amd64")
log.Printf("unknown architecture %s", arch.name)
}
@@ -129,7 +130,7 @@ var (
asmPlusBuild = re(`//\s+\+build\s+([^\n]+)`)
asmTEXT = re(`\bTEXT\b(.*)·([^\(]+)\(SB\)(?:\s*,\s*([0-9A-Z|+()]+))?(?:\s*,\s*\$(-?[0-9]+)(?:-([0-9]+))?)?`)
asmDATA = re(`\b(DATA|GLOBL)\b`)
- asmNamedFP = re(`([a-zA-Z0-9_\xFF-\x{10FFFF}]+)(?:\+([0-9]+))\(FP\)`)
+ asmNamedFP = re(`\$?([a-zA-Z0-9_\xFF-\x{10FFFF}]+)(?:\+([0-9]+))\(FP\)`)
asmUnnamedFP = re(`[^+\-0-9](([0-9]+)\(FP\))`)
asmSP = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`)
asmOpcode = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`)
@@ -183,6 +184,7 @@ Files:
fnName string
localSize, argSize int
wroteSP bool
+ noframe bool
haveRetArg bool
retLine []int
)
@@ -230,6 +232,11 @@ Files:
}
}
+ // Ignore comments and commented-out code.
+ if i := strings.Index(line, "//"); i >= 0 {
+ line = line[:i]
+ }
+
if m := asmTEXT.FindStringSubmatch(line); m != nil {
flushRet()
if arch == "" {
@@ -253,7 +260,7 @@ Files:
// identifiers to represent the directory separator.
pkgPath = strings.Replace(pkgPath, "∕", "/", -1)
if pkgPath != pass.Pkg.Path() {
- log.Printf("%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", fname, lineno, arch, fnName, pkgPath)
+ // log.Printf("%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", fname, lineno, arch, fnName, pkgPath)
fn = nil
fnName = ""
continue
@@ -274,7 +281,8 @@ Files:
localSize += archDef.intSize
}
argSize, _ = strconv.Atoi(m[5])
- if fn == nil && !strings.Contains(fnName, "<>") {
+ noframe = strings.Contains(flag, "NOFRAME")
+ if fn == nil && !strings.Contains(fnName, "<>") && !noframe {
badf("function %s missing Go declaration", fnName)
}
wroteSP = false
@@ -304,13 +312,18 @@ Files:
continue
}
- if strings.Contains(line, ", "+archDef.stack) || strings.Contains(line, ",\t"+archDef.stack) {
+ if strings.Contains(line, ", "+archDef.stack) || strings.Contains(line, ",\t"+archDef.stack) || strings.Contains(line, "NOP "+archDef.stack) || strings.Contains(line, "NOP\t"+archDef.stack) {
wroteSP = true
continue
}
+ if arch == "wasm" && strings.Contains(line, "CallImport") {
+ // CallImport is a call out to magic that can write the result.
+ haveRetArg = true
+ }
+
for _, m := range asmSP.FindAllStringSubmatch(line, -1) {
- if m[3] != archDef.stack || wroteSP {
+ if m[3] != archDef.stack || wroteSP || noframe {
continue
}
off := 0
@@ -370,7 +383,7 @@ Files:
}
continue
}
- asmCheckVar(badf, fn, line, m[0], off, v)
+ asmCheckVar(badf, fn, line, m[0], off, v, archDef)
}
}
flushRet()
@@ -588,7 +601,7 @@ func asmParseDecl(pass *analysis.Pass, decl *ast.FuncDecl) map[string]*asmFunc {
}
// asmCheckVar checks a single variable reference.
-func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr string, off int, v *asmVar) {
+func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr string, off int, v *asmVar, archDef *asmArch) {
m := asmOpcode.FindStringSubmatch(line)
if m == nil {
if !strings.HasPrefix(strings.TrimSpace(line), "//") {
@@ -597,6 +610,8 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
return
}
+ addr := strings.HasPrefix(expr, "$")
+
// Determine operand sizes from instruction.
// Typically the suffix suffices, but there are exceptions.
var src, dst, kind asmKind
@@ -616,10 +631,13 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
// They just take the address of it.
case "386.LEAL":
dst = 4
+ addr = true
case "amd64.LEAQ":
dst = 8
+ addr = true
case "amd64p32.LEAL":
dst = 4
+ addr = true
default:
switch fn.arch.name {
case "386", "amd64":
@@ -724,6 +742,11 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
vs = v.inner[0].size
vt = v.inner[0].typ
}
+ if addr {
+ vk = asmKind(archDef.ptrSize)
+ vs = archDef.ptrSize
+ vt = "address"
+ }
if off != v.off {
var inner bytes.Buffer
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/bools/bools.go b/libgo/go/golang.org/x/tools/go/analysis/passes/bools/bools.go
index 833c9d7aae1..c82d3675b95 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/bools/bools.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/bools/bools.go
@@ -30,8 +30,13 @@ func run(pass *analysis.Pass) (interface{}, error) {
nodeFilter := []ast.Node{
(*ast.BinaryExpr)(nil),
}
+ seen := make(map[*ast.BinaryExpr]bool)
inspect.Preorder(nodeFilter, func(n ast.Node) {
e := n.(*ast.BinaryExpr)
+ if seen[e] {
+ // Already processed as a subexpression of an earlier node.
+ return
+ }
var op boolOp
switch e.Op {
@@ -43,10 +48,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
return
}
- // TODO(adonovan): this reports n(n-1)/2 errors for an
- // expression e||...||e of depth n. Fix.
- // See https://golang.org/issue/28086.
- comm := op.commutativeSets(pass.TypesInfo, e)
+ comm := op.commutativeSets(pass.TypesInfo, e, seen)
for _, exprs := range comm {
op.checkRedundant(pass, exprs)
op.checkSuspect(pass, exprs)
@@ -70,8 +72,9 @@ var (
// expressions in e that are connected by op.
// For example, given 'a || b || f() || c || d' with the or op,
// commutativeSets returns {{b, a}, {d, c}}.
-func (op boolOp) commutativeSets(info *types.Info, e *ast.BinaryExpr) [][]ast.Expr {
- exprs := op.split(e)
+// commutativeSets adds any expanded BinaryExprs to seen.
+func (op boolOp) commutativeSets(info *types.Info, e *ast.BinaryExpr, seen map[*ast.BinaryExpr]bool) [][]ast.Expr {
+ exprs := op.split(e, seen)
// Partition the slice of expressions into commutative sets.
i := 0
@@ -188,11 +191,13 @@ func hasSideEffects(info *types.Info, e ast.Expr) bool {
// split returns a slice of all subexpressions in e that are connected by op.
// For example, given 'a || (b || c) || d' with the or op,
// split returns []{d, c, b, a}.
-func (op boolOp) split(e ast.Expr) (exprs []ast.Expr) {
+// seen[e] is already true; any newly processed exprs are added to seen.
+func (op boolOp) split(e ast.Expr, seen map[*ast.BinaryExpr]bool) (exprs []ast.Expr) {
for {
e = unparen(e)
if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok {
- exprs = append(exprs, op.split(b.Y)...)
+ seen[b] = true
+ exprs = append(exprs, op.split(b.Y, seen)...)
e = b.X
} else {
exprs = append(exprs, e)
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go b/libgo/go/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
index a6e76a192de..42a690dbab6 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/cgocall/cgocall.go
@@ -9,7 +9,6 @@ package cgocall
import (
"fmt"
"go/ast"
- "go/build"
"go/format"
"go/parser"
"go/token"
@@ -46,7 +45,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
return nil, nil // doesn't use cgo
}
- cgofiles, info, err := typeCheckCgoSourceFiles(pass.Fset, pass.Pkg, pass.Files, pass.TypesInfo)
+ cgofiles, info, err := typeCheckCgoSourceFiles(pass.Fset, pass.Pkg, pass.Files, pass.TypesInfo, pass.TypesSizes)
if err != nil {
return nil, err
}
@@ -172,7 +171,7 @@ func checkCgo(fset *token.FileSet, f *ast.File, info *types.Info, reportf func(t
// limited ourselves here to preserving function bodies and initializer
// expressions since that is all that the cgocall analyzer needs.
//
-func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*ast.File, info *types.Info) ([]*ast.File, *types.Info, error) {
+func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*ast.File, info *types.Info, sizes types.Sizes) ([]*ast.File, *types.Info, error) {
const thispkg = "·this·"
// Which files are cgo files?
@@ -270,8 +269,7 @@ func typeCheckCgoSourceFiles(fset *token.FileSet, pkg *types.Package, files []*a
Importer: importerFunc(func(path string) (*types.Package, error) {
return importMap[path], nil
}),
- // TODO(adonovan): Sizes should probably be provided by analysis.Pass.
- Sizes: types.SizesFor("gccgo", build.Default.GOARCH),
+ Sizes: sizes,
Error: func(error) {}, // ignore errors (e.g. unused import)
}
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/composite/composite.go b/libgo/go/golang.org/x/tools/go/analysis/passes/composite/composite.go
index 9cca7781d00..2abe7c6d51e 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/composite/composite.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/composite/composite.go
@@ -21,7 +21,16 @@ const Doc = `check for unkeyed composite literals
This analyzer reports a diagnostic for composite literals of struct
types imported from another package that do not use the field-keyed
syntax. Such literals are fragile because the addition of a new field
-(even if unexported) to the struct will cause compilation to fail.`
+(even if unexported) to the struct will cause compilation to fail.
+
+As an example,
+
+ err = &net.DNSConfigError{err}
+
+should be replaced by:
+
+ err = &net.DNSConfigError{Err: err}
+`
var Analyzer = &analysis.Analyzer{
Name: "composites",
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go b/libgo/go/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
new file mode 100644
index 00000000000..c411466c28e
--- /dev/null
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
@@ -0,0 +1,75 @@
+// Copyright 2018 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.
+
+// The errorsas package defines an Analyzer that checks that the second arugment to
+// errors.As is a pointer to a type implementing error.
+package errorsas
+
+import (
+ "go/ast"
+ "go/types"
+
+ "golang.org/x/tools/go/analysis"
+ "golang.org/x/tools/go/analysis/passes/inspect"
+ "golang.org/x/tools/go/ast/inspector"
+ "golang.org/x/tools/go/types/typeutil"
+)
+
+const doc = `report passing non-pointer or non-error values to errors.As
+
+The errorsas analysis reports calls to errors.As where the type
+of the second argument is not a pointer to a type implementing error.`
+
+var Analyzer = &analysis.Analyzer{
+ Name: "errorsas",
+ Doc: doc,
+ Requires: []*analysis.Analyzer{inspect.Analyzer},
+ Run: run,
+}
+
+func run(pass *analysis.Pass) (interface{}, error) {
+ switch pass.Pkg.Path() {
+ case "errors", "errors_test":
+ // These packages know how to use their own APIs.
+ // Sometimes they are testing what happens to incorrect programs.
+ return nil, nil
+ }
+
+ inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
+
+ nodeFilter := []ast.Node{
+ (*ast.CallExpr)(nil),
+ }
+ inspect.Preorder(nodeFilter, func(n ast.Node) {
+ call := n.(*ast.CallExpr)
+ fn := typeutil.StaticCallee(pass.TypesInfo, call)
+ if fn == nil {
+ return // not a static call
+ }
+ if len(call.Args) < 2 {
+ return // not enough arguments, e.g. called with return values of another function
+ }
+ if fn.FullName() == "errors.As" && !pointerToInterfaceOrError(pass, call.Args[1]) {
+ pass.Reportf(call.Pos(), "second argument to errors.As must be a pointer to an interface or a type implementing error")
+ }
+ })
+ return nil, nil
+}
+
+var errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
+
+// pointerToInterfaceOrError reports whether the type of e is a pointer to an interface or a type implementing error,
+// or is the empty interface.
+func pointerToInterfaceOrError(pass *analysis.Pass, e ast.Expr) bool {
+ t := pass.TypesInfo.Types[e].Type
+ if it, ok := t.Underlying().(*types.Interface); ok && it.NumMethods() == 0 {
+ return true
+ }
+ pt, ok := t.Underlying().(*types.Pointer)
+ if !ok {
+ return false
+ }
+ _, ok = pt.Elem().Underlying().(*types.Interface)
+ return ok || types.Implements(pt.Elem(), errorType)
+}
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/inspect/inspect.go b/libgo/go/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
index bd06549984a..8213f633135 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
@@ -8,7 +8,11 @@
//
// Example of use in another analysis:
//
-// import "golang.org/x/tools/go/analysis/passes/inspect"
+// import (
+// "golang.org/x/tools/go/analysis"
+// "golang.org/x/tools/go/analysis/passes/inspect"
+// "golang.org/x/tools/go/ast/inspector"
+// )
//
// var Analyzer = &analysis.Analyzer{
// ...
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go b/libgo/go/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
index b5161836a57..e88cf57d8f7 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
@@ -45,6 +45,8 @@ var contextPackage = "context"
// control-flow path from the call to a return statement and that path
// does not "use" the cancel function. Any reference to the variable
// counts as a use, even within a nested function literal.
+// If the variable's scope is larger than the function
+// containing the assignment, we assume that other uses exist.
//
// checkLostCancel analyzes a single named or literal function.
func run(pass *analysis.Pass) (interface{}, error) {
@@ -66,6 +68,15 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
func runFunc(pass *analysis.Pass, node ast.Node) {
+ // Find scope of function node
+ var funcScope *types.Scope
+ switch v := node.(type) {
+ case *ast.FuncLit:
+ funcScope = pass.TypesInfo.Scopes[v.Type]
+ case *ast.FuncDecl:
+ funcScope = pass.TypesInfo.Scopes[v.Type]
+ }
+
// Maps each cancel variable to its defining ValueSpec/AssignStmt.
cancelvars := make(map[*types.Var]ast.Node)
@@ -114,7 +125,11 @@ func runFunc(pass *analysis.Pass, node ast.Node) {
"the cancel function returned by context.%s should be called, not discarded, to avoid a context leak",
n.(*ast.SelectorExpr).Sel.Name)
} else if v, ok := pass.TypesInfo.Uses[id].(*types.Var); ok {
- cancelvars[v] = stmt
+ // If the cancel variable is defined outside function scope,
+ // do not analyze it.
+ if funcScope.Contains(v.Pos()) {
+ cancelvars[v] = stmt
+ }
} else if v, ok := pass.TypesInfo.Defs[id].(*types.Var); ok {
cancelvars[v] = stmt
}
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go b/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go
index c0265aafeee..f59e95dc219 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/printf/printf.go
@@ -453,15 +453,23 @@ func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func,
}
// isFormatter reports whether t satisfies fmt.Formatter.
-// Unlike fmt.Stringer, it's impossible to satisfy fmt.Formatter without importing fmt.
-func isFormatter(pass *analysis.Pass, t types.Type) bool {
- for _, imp := range pass.Pkg.Imports() {
- if imp.Path() == "fmt" {
- formatter := imp.Scope().Lookup("Formatter").Type().Underlying().(*types.Interface)
- return types.Implements(t, formatter)
- }
+// The only interface method to look for is "Format(State, rune)".
+func isFormatter(typ types.Type) bool {
+ obj, _, _ := types.LookupFieldOrMethod(typ, false, nil, "Format")
+ fn, ok := obj.(*types.Func)
+ if !ok {
+ return false
}
- return false
+ sig := fn.Type().(*types.Signature)
+ return sig.Params().Len() == 2 &&
+ sig.Results().Len() == 0 &&
+ isNamed(sig.Params().At(0).Type(), "fmt", "State") &&
+ types.Identical(sig.Params().At(1).Type(), types.Typ[types.Rune])
+}
+
+func isNamed(T types.Type, pkgpath, name string) bool {
+ named, ok := T.(*types.Named)
+ return ok && named.Obj().Pkg().Path() == pkgpath && named.Obj().Name() == name
}
// formatState holds the parsed representation of a printf directive such as "%3.*[4]d".
@@ -731,6 +739,7 @@ var printVerbs = []printVerb{
{'T', "-", anyType},
{'U', "-#", argRune | argInt},
{'v', allFlags, anyType},
+ {'w', noFlag, anyType},
{'x', sharpNumFlag, argRune | argInt | argString | argPointer},
{'X', sharpNumFlag, argRune | argInt | argString | argPointer},
}
@@ -753,7 +762,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
formatter := false
if state.argNum < len(call.Args) {
if tv, ok := pass.TypesInfo.Types[call.Args[state.argNum]]; ok {
- formatter = isFormatter(pass, tv.Type)
+ formatter = isFormatter(tv.Type)
}
}
@@ -831,7 +840,7 @@ func recursiveStringer(pass *analysis.Pass, e ast.Expr) bool {
typ := pass.TypesInfo.Types[e].Type
// It's unlikely to be a recursive stringer if it has a Format method.
- if isFormatter(pass, typ) {
+ if isFormatter(typ) {
return false
}
@@ -847,20 +856,28 @@ func recursiveStringer(pass *analysis.Pass, e ast.Expr) bool {
return false
}
- // Is it the receiver r, or &r?
- recv := stringMethod.Type().(*types.Signature).Recv()
- if recv == nil {
+ sig := stringMethod.Type().(*types.Signature)
+ if !isStringer(sig) {
return false
}
+
+ // Is it the receiver r, or &r?
if u, ok := e.(*ast.UnaryExpr); ok && u.Op == token.AND {
e = u.X // strip off & from &r
}
if id, ok := e.(*ast.Ident); ok {
- return pass.TypesInfo.Uses[id] == recv
+ return pass.TypesInfo.Uses[id] == sig.Recv()
}
return false
}
+// isStringer reports whether the method signature matches the String() definition in fmt.Stringer.
+func isStringer(sig *types.Signature) bool {
+ return sig.Params().Len() == 0 &&
+ sig.Results().Len() == 1 &&
+ sig.Results().At(0).Type() == types.Typ[types.String]
+}
+
// isFunctionValue reports whether the expression is a function as opposed to a function call.
// It is almost always a mistake to print a function value.
func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool {
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/printf/types.go b/libgo/go/golang.org/x/tools/go/analysis/passes/printf/types.go
index 87523a19c67..12286fd5df5 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/printf/types.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/printf/types.go
@@ -2,7 +2,6 @@ package printf
import (
"go/ast"
- "go/build"
"go/types"
"golang.org/x/tools/go/analysis"
@@ -39,7 +38,7 @@ func matchArgTypeInternal(pass *analysis.Pass, t printfArgType, typ types.Type,
}
}
// If the type implements fmt.Formatter, we have nothing to check.
- if isFormatter(pass, typ) {
+ if isFormatter(typ) {
return true
}
// If we can use a string, might arg (dynamically) implement the Stringer or Error interface?
@@ -235,5 +234,3 @@ func matchStructArgType(pass *analysis.Pass, t printfArgType, typ *types.Struct,
}
return true
}
-
-var archSizes = types.SizesFor("gccgo", build.Default.GOARCH)
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/shift/shift.go b/libgo/go/golang.org/x/tools/go/analysis/passes/shift/shift.go
index 4142ac342ad..39f54573c9f 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/shift/shift.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/shift/shift.go
@@ -12,10 +12,8 @@ package shift
import (
"go/ast"
- "go/build"
"go/constant"
"go/token"
- "go/types"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
@@ -93,36 +91,9 @@ func checkLongShift(pass *analysis.Pass, node ast.Node, x, y ast.Expr) {
if t == nil {
return
}
- b, ok := t.Underlying().(*types.Basic)
- if !ok {
- return
- }
- var size int64
- switch b.Kind() {
- case types.Uint8, types.Int8:
- size = 8
- case types.Uint16, types.Int16:
- size = 16
- case types.Uint32, types.Int32:
- size = 32
- case types.Uint64, types.Int64:
- size = 64
- case types.Int, types.Uint:
- size = uintBitSize
- case types.Uintptr:
- size = uintptrBitSize
- default:
- return
- }
+ size := 8 * pass.TypesSizes.Sizeof(t)
if amt >= size {
ident := analysisutil.Format(pass.Fset, x)
pass.Reportf(node.Pos(), "%s (%d bits) too small for shift of %d", ident, size, amt)
}
}
-
-var (
- uintBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uint])
- uintptrBitSize = 8 * archSizes.Sizeof(types.Typ[types.Uintptr])
-)
-
-var archSizes = types.SizesFor("gccgo", build.Default.GOARCH)
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go b/libgo/go/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go
index 83495112243..bc1db7e4c2e 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go
@@ -8,7 +8,6 @@ package stdmethods
import (
"go/ast"
- "go/token"
"go/types"
"strings"
@@ -117,6 +116,13 @@ func canonicalMethod(pass *analysis.Pass, id *ast.Ident) {
args := sign.Params()
results := sign.Results()
+ // Special case: WriteTo with more than one argument,
+ // not trying at all to implement io.WriterTo,
+ // comes up often enough to skip.
+ if id.Name == "WriteTo" && args.Len() > 1 {
+ return
+ }
+
// Do the =s (if any) all match?
if !matchParams(pass, expect.args, args, "=") || !matchParams(pass, expect.results, results, "=") {
return
@@ -163,7 +169,7 @@ func matchParams(pass *analysis.Pass, expect []string, actual *types.Tuple, pref
if i >= actual.Len() {
return false
}
- if !matchParamType(pass.Fset, pass.Pkg, x, actual.At(i).Type()) {
+ if !matchParamType(x, actual.At(i).Type()) {
return false
}
}
@@ -174,13 +180,8 @@ func matchParams(pass *analysis.Pass, expect []string, actual *types.Tuple, pref
}
// Does this one type match?
-func matchParamType(fset *token.FileSet, pkg *types.Package, expect string, actual types.Type) bool {
+func matchParamType(expect string, actual types.Type) bool {
expect = strings.TrimPrefix(expect, "=")
- // Strip package name if we're in that package.
- if n := len(pkg.Name()); len(expect) > n && expect[:n] == pkg.Name() && expect[n] == '.' {
- expect = expect[n+1:]
- }
-
// Overkill but easy.
return typeString(actual) == expect
}
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/structtag/structtag.go b/libgo/go/golang.org/x/tools/go/analysis/passes/structtag/structtag.go
index 2b67c376bab..acc6e6c770d 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/structtag/structtag.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/structtag/structtag.go
@@ -41,7 +41,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
inspect.Preorder(nodeFilter, func(n ast.Node) {
styp := pass.TypesInfo.Types[n.(*ast.StructType)].Type.(*types.Struct)
- var seen map[[2]string]token.Pos
+ var seen namesSeen
for i := 0; i < styp.NumFields(); i++ {
field := styp.Field(i)
tag := styp.Tag(i)
@@ -51,13 +51,47 @@ func run(pass *analysis.Pass) (interface{}, error) {
return nil, nil
}
+// namesSeen keeps track of encoding tags by their key, name, and nested level
+// from the initial struct. The level is taken into account because equal
+// encoding key names only conflict when at the same level; otherwise, the lower
+// level shadows the higher level.
+type namesSeen map[uniqueName]token.Pos
+
+type uniqueName struct {
+ key string // "xml" or "json"
+ name string // the encoding name
+ level int // anonymous struct nesting level
+}
+
+func (s *namesSeen) Get(key, name string, level int) (token.Pos, bool) {
+ if *s == nil {
+ *s = make(map[uniqueName]token.Pos)
+ }
+ pos, ok := (*s)[uniqueName{key, name, level}]
+ return pos, ok
+}
+
+func (s *namesSeen) Set(key, name string, level int, pos token.Pos) {
+ if *s == nil {
+ *s = make(map[uniqueName]token.Pos)
+ }
+ (*s)[uniqueName{key, name, level}] = pos
+}
+
var checkTagDups = []string{"json", "xml"}
var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true}
// checkCanonicalFieldTag checks a single struct field tag.
-func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, seen *map[[2]string]token.Pos) {
+func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, seen *namesSeen) {
+ switch pass.Pkg.Path() {
+ case "encoding/json", "encoding/xml":
+ // These packages know how to use their own APIs.
+ // Sometimes they are testing what happens to incorrect programs.
+ return
+ }
+
for _, key := range checkTagDups {
- checkTagDuplicates(pass, tag, key, field, field, seen)
+ checkTagDuplicates(pass, tag, key, field, field, seen, 1)
}
if err := validateStructTag(tag); err != nil {
@@ -88,28 +122,29 @@ func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, s
// checkTagDuplicates checks a single struct field tag to see if any tags are
// duplicated. nearest is the field that's closest to the field being checked,
// while still being part of the top-level struct type.
-func checkTagDuplicates(pass *analysis.Pass, tag, key string, nearest, field *types.Var, seen *map[[2]string]token.Pos) {
+func checkTagDuplicates(pass *analysis.Pass, tag, key string, nearest, field *types.Var, seen *namesSeen, level int) {
val := reflect.StructTag(tag).Get(key)
if val == "-" {
// Ignored, even if the field is anonymous.
return
}
if val == "" || val[0] == ',' {
- if field.Anonymous() {
- typ, ok := field.Type().Underlying().(*types.Struct)
- if !ok {
- return
- }
- for i := 0; i < typ.NumFields(); i++ {
- field := typ.Field(i)
- if !field.Exported() {
- continue
- }
- tag := typ.Tag(i)
- checkTagDuplicates(pass, tag, key, nearest, field, seen)
+ if !field.Anonymous() {
+ // Ignored if the field isn't anonymous.
+ return
+ }
+ typ, ok := field.Type().Underlying().(*types.Struct)
+ if !ok {
+ return
+ }
+ for i := 0; i < typ.NumFields(); i++ {
+ field := typ.Field(i)
+ if !field.Exported() {
+ continue
}
+ tag := typ.Tag(i)
+ checkTagDuplicates(pass, tag, key, nearest, field, seen, level+1)
}
- // Ignored if the field isn't anonymous.
return
}
if key == "xml" && field.Name() == "XMLName" {
@@ -132,10 +167,7 @@ func checkTagDuplicates(pass *analysis.Pass, tag, key string, nearest, field *ty
}
val = val[:i]
}
- if *seen == nil {
- *seen = map[[2]string]token.Pos{}
- }
- if pos, ok := (*seen)[[2]string{key, val}]; ok {
+ if pos, ok := seen.Get(key, val, level); ok {
alsoPos := pass.Fset.Position(pos)
alsoPos.Column = 0
@@ -154,7 +186,7 @@ func checkTagDuplicates(pass *analysis.Pass, tag, key string, nearest, field *ty
pass.Reportf(nearest.Pos(), "struct field %s repeats %s tag %q also at %s", field.Name(), key, val, alsoPos)
} else {
- (*seen)[[2]string{key, val}] = field.Pos()
+ seen.Set(key, val, level, field.Pos())
}
}
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/tests/tests.go b/libgo/go/golang.org/x/tools/go/analysis/passes/tests/tests.go
index 35b0a3e7cc2..8232276186a 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/tests/tests.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/tests/tests.go
@@ -20,7 +20,10 @@ const Doc = `check for common mistaken usages of tests and examples
The tests checker walks Test, Benchmark and Example functions checking
malformed names, wrong signatures and examples documenting non-existent
-identifiers.`
+identifiers.
+
+Please see the documentation for package testing in golang.org/pkg/testing
+for the conventions that are enforced for Tests, Benchmarks, and Examples.`
var Analyzer = &analysis.Analyzer{
Name: "tests",
@@ -84,23 +87,25 @@ func isTestParam(typ ast.Expr, wantType string) bool {
return false
}
-func lookup(pkg *types.Package, name string) types.Object {
+func lookup(pkg *types.Package, name string) []types.Object {
if o := pkg.Scope().Lookup(name); o != nil {
- return o
- }
-
- // If this package is ".../foo_test" and it imports a package
- // ".../foo", try looking in the latter package.
- // This heuristic should work even on build systems that do not
- // record any special link between the packages.
- if basePath := strings.TrimSuffix(pkg.Path(), "_test"); basePath != pkg.Path() {
- for _, imp := range pkg.Imports() {
- if imp.Path() == basePath {
- return imp.Scope().Lookup(name)
- }
+ return []types.Object{o}
+ }
+
+ var ret []types.Object
+ // Search through the imports to see if any of them define name.
+ // It's hard to tell in general which package is being tested, so
+ // for the purposes of the analysis, allow the object to appear
+ // in any of the imports. This guarantees there are no false positives
+ // because the example needs to use the object so it must be defined
+ // in the package or one if its imports. On the other hand, false
+ // negatives are possible, but should be rare.
+ for _, imp := range pkg.Imports() {
+ if obj := imp.Scope().Lookup(name); obj != nil {
+ ret = append(ret, obj)
}
}
- return nil
+ return ret
}
func checkExample(pass *analysis.Pass, fn *ast.FuncDecl) {
@@ -121,9 +126,9 @@ func checkExample(pass *analysis.Pass, fn *ast.FuncDecl) {
exName = strings.TrimPrefix(fnName, "Example")
elems = strings.SplitN(exName, "_", 3)
ident = elems[0]
- obj = lookup(pass.Pkg, ident)
+ objs = lookup(pass.Pkg, ident)
)
- if ident != "" && obj == nil {
+ if ident != "" && len(objs) == 0 {
// Check ExampleFoo and ExampleBadFoo.
pass.Reportf(fn.Pos(), "%s refers to unknown identifier: %s", fnName, ident)
// Abort since obj is absent and no subsequent checks can be performed.
@@ -145,7 +150,15 @@ func checkExample(pass *analysis.Pass, fn *ast.FuncDecl) {
mmbr := elems[1]
if !isExampleSuffix(mmbr) {
// Check ExampleFoo_Method and ExampleFoo_BadMethod.
- if obj, _, _ := types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), mmbr); obj == nil {
+ found := false
+ // Check if Foo.Method exists in this package or its imports.
+ for _, obj := range objs {
+ if obj, _, _ := types.LookupFieldOrMethod(obj.Type(), true, obj.Pkg(), mmbr); obj != nil {
+ found = true
+ break
+ }
+ }
+ if !found {
pass.Reportf(fn.Pos(), "%s refers to unknown field or method: %s.%s", fnName, ident, mmbr)
}
}
diff --git a/libgo/go/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go b/libgo/go/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
index 6cf4358ab9a..d019ecef15a 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
@@ -29,6 +29,13 @@ var Analyzer = &analysis.Analyzer{
}
func run(pass *analysis.Pass) (interface{}, error) {
+ switch pass.Pkg.Path() {
+ case "encoding/gob", "encoding/json", "encoding/xml":
+ // These packages know how to use their own APIs.
+ // Sometimes they are testing what happens to incorrect programs.
+ return nil, nil
+ }
+
inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
nodeFilter := []ast.Node{
diff --git a/libgo/go/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go b/libgo/go/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
index 5943c99e13b..b4fda19ecaa 100644
--- a/libgo/go/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
+++ b/libgo/go/golang.org/x/tools/go/analysis/unitchecker/unitchecker.go
@@ -329,6 +329,7 @@ func run(fset *token.FileSet, cfg *Config, analyzers []*analysis.Analyzer) ([]re
OtherFiles: cfg.NonGoFiles,
Pkg: pkg,
TypesInfo: info,
+ TypesSizes: tc.Sizes,
ResultOf: inputs,
Report: func(d analysis.Diagnostic) { act.diagnostics = append(act.diagnostics, d) },
ImportObjectFact: facts.ImportObjectFact,
diff --git a/libgo/go/golang.org/x/tools/go/ast/inspector/inspector.go b/libgo/go/golang.org/x/tools/go/ast/inspector/inspector.go
index db88a951090..ddbdd3f08fc 100644
--- a/libgo/go/golang.org/x/tools/go/ast/inspector/inspector.go
+++ b/libgo/go/golang.org/x/tools/go/ast/inspector/inspector.go
@@ -14,7 +14,7 @@
// Experiments suggest the inspector's traversals are about 2.5x faster
// than ast.Inspect, but it may take around 5 traversals for this
// benefit to amortize the inspector's construction cost.
-// If efficiency is the primary concern, do not use use Inspector for
+// If efficiency is the primary concern, do not use Inspector for
// one-off traversals.
package inspector