]> Cypherpunks repositories - gostls13.git/commitdiff
cmd: vendor in new version of x/tools
authorKeith Randall <khr@google.com>
Mon, 4 Nov 2019 22:50:35 +0000 (14:50 -0800)
committerKeith Randall <khr@golang.org>
Tue, 5 Nov 2019 00:16:41 +0000 (00:16 +0000)
Fixes #35264

Change-Id: Id540a48f593d8ac1b414551255c5eff24666aa0b
Reviewed-on: https://go-review.googlesource.com/c/go/+/205240
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

22 files changed:
src/cmd/go.mod
src/cmd/go.sum
src/cmd/vendor/golang.org/x/tools/go/analysis/analysis.go
src/cmd/vendor/golang.org/x/tools/go/analysis/diagnostic.go
src/cmd/vendor/golang.org/x/tools/go/analysis/internal/facts/facts.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/asmdecl/asmdecl.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/atomic/atomic.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/bools/bools.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/composite/composite.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/copylock/copylock.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/errorsas/errorsas.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/httpresponse/httpresponse.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/inspect/inspect.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/loopclosure/loopclosure.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/lostcancel/lostcancel.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/nilfunc/nilfunc.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/shift/shift.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stdmethods/stdmethods.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unreachable/unreachable.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unsafeptr/unsafeptr.go
src/cmd/vendor/modules.txt

index 6b2c45a9bbf7431ccc64b1e5c654983dab4412a8..4de382e0bedc75a2b9c2f89ae78c813934f4efb1 100644 (file)
@@ -9,5 +9,5 @@ require (
        golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
        golang.org/x/mod v0.1.1-0.20191029194233-18c3998b6452
        golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82 // indirect
-       golang.org/x/tools v0.0.0-20191018203202-04252eccb9d5
+       golang.org/x/tools v0.0.0-20191104222624-6b7b8b79ae80
 )
index 7fd4eaddad113f978b936e13f016ca22093c6d39..85b5317b7fd0f2804ee80314562cd615d2084ac6 100644 (file)
@@ -18,8 +18,8 @@ golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82 h1:vsphBvatvfbhlb4PO1BYSr9dz
 golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20191018203202-04252eccb9d5 h1:TFUhCYbgGMOGnRxJv+j0iAcxCjk8oGjXXWNejQBhUUs=
-golang.org/x/tools v0.0.0-20191018203202-04252eccb9d5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191104222624-6b7b8b79ae80 h1:6CcDC1SXj4DrJP955osT9RJmKsH3LQBZJ59D5v4Rw0s=
+golang.org/x/tools v0.0.0-20191104222624-6b7b8b79ae80/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
index bc58c31c9f0dce38c9878873b2386efde3cdd08f..ea605f4fd463d701c857422112ff6d3da6913875 100644 (file)
@@ -163,13 +163,19 @@ 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{}) {
+// The Range interface provides a range. It's equivalent to and satisfied by
+// ast.Node.
+type Range interface {
+       Pos() token.Pos // position of first character belonging to the node
+       End() token.Pos // position of first character immediately after the node
+}
+
+// ReportRangef is a helper function that reports a Diagnostic using the
+// range provided. ast.Node values can be passed in as the range because
+// they satisfy the Range interface.
+func (pass *Pass) ReportRangef(rng Range, format string, args ...interface{}) {
        msg := fmt.Sprintf(format, args...)
-       pass.Report(Diagnostic{Pos: node.Pos(), End: node.End(), Message: msg})
+       pass.Report(Diagnostic{Pos: rng.Pos(), End: rng.End(), Message: msg})
 }
 
 func (pass *Pass) String() string {
index 744072cd798e0bcdce3c918bbeb67e4a0070f13a..57eaf6faa2ac73c24ef6ef71cc9dabeee37e18b0 100644 (file)
@@ -22,6 +22,19 @@ type Diagnostic struct {
        // Diagnostics should not contain SuggestedFixes that overlap.
        // Experimental: This API is experimental and may change in the future.
        SuggestedFixes []SuggestedFix // optional
+
+       // Experimental: This API is experimental and may change in the future.
+       Related []RelatedInformation // optional
+}
+
+// RelatedInformation contains information related to a diagnostic.
+// For example, a diagnostic that flags duplicated declarations of a
+// variable may include one RelatedInformation per existing
+// declaration.
+type RelatedInformation struct {
+       Pos     token.Pos
+       End     token.Pos
+       Message string
 }
 
 // A SuggestedFix is a code change associated with a Diagnostic that a user can choose
index 07984521c3728acad5dff263d7c8611f31f72a0d..fe8e8f3884403f258af5e8a7fec252a79dce4a34 100644 (file)
@@ -101,11 +101,13 @@ func (s *Set) ExportObjectFact(obj types.Object, fact analysis.Fact) {
 
 func (s *Set) AllObjectFacts(filter map[reflect.Type]bool) []analysis.ObjectFact {
        var facts []analysis.ObjectFact
+       s.mu.Lock()
        for k, v := range s.m {
                if k.obj != nil && filter[k.t] {
                        facts = append(facts, analysis.ObjectFact{Object: k.obj, Fact: v})
                }
        }
+       s.mu.Unlock()
        return facts
 }
 
@@ -134,11 +136,13 @@ func (s *Set) ExportPackageFact(fact analysis.Fact) {
 
 func (s *Set) AllPackageFacts(filter map[reflect.Type]bool) []analysis.PackageFact {
        var facts []analysis.PackageFact
+       s.mu.Lock()
        for k, v := range s.m {
                if k.obj == nil && filter[k.t] {
                        facts = append(facts, analysis.PackageFact{Package: k.pkg, Fact: v})
                }
        }
+       s.mu.Unlock()
        return facts
 }
 
@@ -227,7 +231,6 @@ func Decode(pkg *types.Package, read func(packagePath string) ([]byte, error)) (
 // It may fail if one of the Facts could not be gob-encoded, but this is
 // a sign of a bug in an Analyzer.
 func (s *Set) Encode() []byte {
-
        // TODO(adonovan): opt: use a more efficient encoding
        // that avoids repeating PkgPath for each fact.
 
index 6e7a76e8c8be46064306d90f2efdd0172beb760d..c2e89ee2dc67b72af45df4ad07d1f3e2f3276171 100644 (file)
@@ -661,6 +661,10 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
                                src = 4
                                break
                        }
+                       if op == "MOVO" || op == "MOVOU" {
+                               src = 16
+                               break
+                       }
                        if strings.HasPrefix(op, "SET") {
                                // SETEQ, etc
                                src = 1
@@ -736,6 +740,11 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
                vk = v.inner[0].kind
                vs = v.inner[0].size
                vt = v.inner[0].typ
+       case asmComplex:
+               // Allow a single instruction to load both parts of a complex.
+               if int(kind) == vs {
+                       kind = asmComplex
+               }
        }
        if addr {
                vk = asmKind(archDef.ptrSize)
index 45243d6f8c0d94aab3c3927c82a6b4ef92dafda4..9261db7e4e52a51d95a89dfd2f8d9cbc8811c541 100644 (file)
@@ -91,6 +91,6 @@ func checkAtomicAddAssignment(pass *analysis.Pass, left ast.Expr, call *ast.Call
        }
 
        if broken {
-               pass.Reportf(left.Pos(), "direct assignment to atomic value")
+               pass.ReportRangef(left, "direct assignment to atomic value")
        }
 }
index c82d3675b95f49ef7081cb0448504e48ca5a44de..fbc1f7ea91480659497487730af0268c49d5cca7 100644 (file)
@@ -100,7 +100,7 @@ func (op boolOp) checkRedundant(pass *analysis.Pass, exprs []ast.Expr) {
        for _, e := range exprs {
                efmt := analysisutil.Format(pass.Fset, e)
                if seen[efmt] {
-                       pass.Reportf(e.Pos(), "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt)
+                       pass.ReportRangef(e, "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt)
                } else {
                        seen[efmt] = true
                }
@@ -147,7 +147,7 @@ func (op boolOp) checkSuspect(pass *analysis.Pass, exprs []ast.Expr) {
                if prev, found := seen[xfmt]; found {
                        // checkRedundant handles the case in which efmt == prev.
                        if efmt != prev {
-                               pass.Reportf(e.Pos(), "suspect %s: %s %s %s", op.name, efmt, op.tok, prev)
+                               pass.ReportRangef(e, "suspect %s: %s %s %s", op.name, efmt, op.tok, prev)
                        }
                } else {
                        seen[xfmt] = efmt
index 2abe7c6d51e803a5bc927d0581d3340d37254f16..4c3ac6647f6acb26810af1d690d2c5712d37d544 100644 (file)
@@ -97,7 +97,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
                        return
                }
 
-               pass.Reportf(cl.Pos(), "%s composite literal uses unkeyed fields", typeName)
+               pass.ReportRangef(cl, "%s composite literal uses unkeyed fields", typeName)
        })
        return nil, nil
 }
index 067aed57df30c992542bcd77733bc6738a966033..c4ebf785710f9431502a85e0f06ab1af2f7a6562 100644 (file)
@@ -74,7 +74,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
 func checkCopyLocksAssign(pass *analysis.Pass, as *ast.AssignStmt) {
        for i, x := range as.Rhs {
                if path := lockPathRhs(pass, x); path != nil {
-                       pass.Reportf(x.Pos(), "assignment copies lock value to %v: %v", analysisutil.Format(pass.Fset, as.Lhs[i]), path)
+                       pass.ReportRangef(x, "assignment copies lock value to %v: %v", analysisutil.Format(pass.Fset, as.Lhs[i]), path)
                }
        }
 }
@@ -89,7 +89,7 @@ func checkCopyLocksGenDecl(pass *analysis.Pass, gd *ast.GenDecl) {
                valueSpec := spec.(*ast.ValueSpec)
                for i, x := range valueSpec.Values {
                        if path := lockPathRhs(pass, x); path != nil {
-                               pass.Reportf(x.Pos(), "variable declaration copies lock value to %v: %v", valueSpec.Names[i].Name, path)
+                               pass.ReportRangef(x, "variable declaration copies lock value to %v: %v", valueSpec.Names[i].Name, path)
                        }
                }
        }
@@ -102,7 +102,7 @@ func checkCopyLocksCompositeLit(pass *analysis.Pass, cl *ast.CompositeLit) {
                        x = node.Value
                }
                if path := lockPathRhs(pass, x); path != nil {
-                       pass.Reportf(x.Pos(), "literal copies lock value from %v: %v", analysisutil.Format(pass.Fset, x), path)
+                       pass.ReportRangef(x, "literal copies lock value from %v: %v", analysisutil.Format(pass.Fset, x), path)
                }
        }
 }
@@ -111,7 +111,7 @@ func checkCopyLocksCompositeLit(pass *analysis.Pass, cl *ast.CompositeLit) {
 func checkCopyLocksReturnStmt(pass *analysis.Pass, rs *ast.ReturnStmt) {
        for _, x := range rs.Results {
                if path := lockPathRhs(pass, x); path != nil {
-                       pass.Reportf(x.Pos(), "return copies lock value: %v", path)
+                       pass.ReportRangef(x, "return copies lock value: %v", path)
                }
        }
 }
@@ -133,7 +133,7 @@ func checkCopyLocksCallExpr(pass *analysis.Pass, ce *ast.CallExpr) {
        }
        for _, x := range ce.Args {
                if path := lockPathRhs(pass, x); path != nil {
-                       pass.Reportf(x.Pos(), "call of %s copies lock value: %v", analysisutil.Format(pass.Fset, ce.Fun), path)
+                       pass.ReportRangef(x, "call of %s copies lock value: %v", analysisutil.Format(pass.Fset, ce.Fun), path)
                }
        }
 }
@@ -146,7 +146,7 @@ func checkCopyLocksFunc(pass *analysis.Pass, name string, recv *ast.FieldList, t
        if recv != nil && len(recv.List) > 0 {
                expr := recv.List[0].Type
                if path := lockPath(pass.Pkg, pass.TypesInfo.Types[expr].Type); path != nil {
-                       pass.Reportf(expr.Pos(), "%s passes lock by value: %v", name, path)
+                       pass.ReportRangef(expr, "%s passes lock by value: %v", name, path)
                }
        }
 
@@ -154,7 +154,7 @@ func checkCopyLocksFunc(pass *analysis.Pass, name string, recv *ast.FieldList, t
                for _, field := range typ.Params.List {
                        expr := field.Type
                        if path := lockPath(pass.Pkg, pass.TypesInfo.Types[expr].Type); path != nil {
-                               pass.Reportf(expr.Pos(), "%s passes lock by value: %v", name, path)
+                               pass.ReportRangef(expr, "%s passes lock by value: %v", name, path)
                        }
                }
        }
index 01abc70017b8ef528154143394884138004e823f..cd3740714488c3ef54ff1e60bec0051b8751faa5 100644 (file)
@@ -51,7 +51,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
                        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")
+                       pass.ReportRangef(call, "second argument to errors.As must be a pointer to an interface or a type implementing error")
                }
        })
        return nil, nil
index 0cf21b8cd1e8b99ee9447b59a8c88b988d046f24..ec335d35061dd67946161a941850438717d95195 100644 (file)
@@ -85,7 +85,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
                }
 
                if resp.Obj == root.Obj {
-                       pass.Reportf(root.Pos(), "using %s before checking for errors", resp.Name)
+                       pass.ReportRangef(root, "using %s before checking for errors", resp.Name)
                }
                return true
        })
index 8213f633135934088b7ec2711ecf7edb600b24b8..2856df137c562f01a225ca7553ae7a1a88c264e5 100644 (file)
@@ -16,7 +16,7 @@
 //
 //     var Analyzer = &analysis.Analyzer{
 //             ...
-//             Requires:       reflect.TypeOf(new(inspect.Analyzer)),
+//             Requires:       []*analysis.Analyzer{inspect.Analyzer},
 //     }
 //
 //     func run(pass *analysis.Pass) (interface{}, error) {
index da0714069f7b14f1ba147776c890d7c5a20c3bb6..a14e7eb55d0abf0a2caf2aa3255a05a307a4cbb1 100644 (file)
@@ -119,7 +119,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
                        }
                        for _, v := range vars {
                                if v.Obj == id.Obj {
-                                       pass.Reportf(id.Pos(), "loop variable %s captured by func literal",
+                                       pass.ReportRangef(id, "loop variable %s captured by func literal",
                                                id.Name)
                                }
                        }
index e88cf57d8f7a048600a17b57964caf94466d8067..85e7ba7a8efee0d32f494424a403e7dc605f78e0 100644 (file)
@@ -121,7 +121,7 @@ func runFunc(pass *analysis.Pass, node ast.Node) {
                }
                if id != nil {
                        if id.Name == "_" {
-                               pass.Reportf(id.Pos(),
+                               pass.ReportRangef(id,
                                        "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 {
@@ -174,8 +174,8 @@ func runFunc(pass *analysis.Pass, node ast.Node) {
        for v, stmt := range cancelvars {
                if ret := lostCancelPath(pass, g, v, stmt, sig); ret != nil {
                        lineno := pass.Fset.Position(stmt.Pos()).Line
-                       pass.Reportf(stmt.Pos(), "the %s function is not used on all paths (possible context leak)", v.Name())
-                       pass.Reportf(ret.Pos(), "this return statement may be reached without using the %s var defined on line %d", v.Name(), lineno)
+                       pass.ReportRangef(stmt, "the %s function is not used on all paths (possible context leak)", v.Name())
+                       pass.ReportRangef(ret, "this return statement may be reached without using the %s var defined on line %d", v.Name(), lineno)
                }
        }
 }
index 9c2d4df20a087ff2b1008e03c5baeec161970e0d..cd42c9897f2d4bfe30999296e22ae0b0936b4f40 100644 (file)
@@ -68,7 +68,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
                        return
                }
 
-               pass.Reportf(e.Pos(), "comparison of function %v %v nil is always %v", obj.Name(), e.Op, e.Op == token.NEQ)
+               pass.ReportRangef(e, "comparison of function %v %v nil is always %v", obj.Name(), e.Op, e.Op == token.NEQ)
        })
        return nil, nil
 }
index b50153805519a4002ff13fc47be3c2a84f67bfd9..38a752c957318fef9a8502fa4f1b48edb24cd08b 100644 (file)
@@ -13,6 +13,7 @@ import (
        "go/constant"
        "go/token"
        "go/types"
+       "reflect"
        "regexp"
        "sort"
        "strconv"
@@ -31,11 +32,12 @@ func init() {
 }
 
 var Analyzer = &analysis.Analyzer{
-       Name:      "printf",
-       Doc:       doc,
-       Requires:  []*analysis.Analyzer{inspect.Analyzer},
-       Run:       run,
-       FactTypes: []analysis.Fact{new(isWrapper)},
+       Name:       "printf",
+       Doc:        doc,
+       Requires:   []*analysis.Analyzer{inspect.Analyzer},
+       Run:        run,
+       ResultType: reflect.TypeOf((*Result)(nil)),
+       FactTypes:  []analysis.Fact{new(isWrapper)},
 }
 
 const doc = `check consistency of Printf format strings and arguments
@@ -66,18 +68,64 @@ argument list. Otherwise it is assumed to be Print-like, taking a list
 of arguments with no format string.
 `
 
+// Kind is a kind of fmt function behavior.
+type Kind int
+
+const (
+       KindNone   Kind = iota // not a fmt wrapper function
+       KindPrint              // function behaves like fmt.Print
+       KindPrintf             // function behaves like fmt.Printf
+       KindErrorf             // function behaves like fmt.Errorf
+)
+
+func (kind Kind) String() string {
+       switch kind {
+       case KindPrint:
+               return "print"
+       case KindPrintf:
+               return "printf"
+       case KindErrorf:
+               return "errorf"
+       }
+       return ""
+}
+
+// Result is the printf analyzer's result type. Clients may query the result
+// to learn whether a function behaves like fmt.Print or fmt.Printf.
+type Result struct {
+       funcs map[*types.Func]Kind
+}
+
+// Kind reports whether fn behaves like fmt.Print or fmt.Printf.
+func (r *Result) Kind(fn *types.Func) Kind {
+       _, ok := isPrint[fn.FullName()]
+       if !ok {
+               // Next look up just "printf", for use with -printf.funcs.
+               _, ok = isPrint[strings.ToLower(fn.Name())]
+       }
+       if ok {
+               if strings.HasSuffix(fn.Name(), "f") {
+                       return KindPrintf
+               } else {
+                       return KindPrint
+               }
+       }
+
+       return r.funcs[fn]
+}
+
 // isWrapper is a fact indicating that a function is a print or printf wrapper.
-type isWrapper struct{ Kind funcKind }
+type isWrapper struct{ Kind Kind }
 
 func (f *isWrapper) AFact() {}
 
 func (f *isWrapper) String() string {
        switch f.Kind {
-       case kindPrintf:
+       case KindPrintf:
                return "printfWrapper"
-       case kindPrint:
+       case KindPrint:
                return "printWrapper"
-       case kindErrorf:
+       case KindErrorf:
                return "errorfWrapper"
        default:
                return "unknownWrapper"
@@ -85,9 +133,12 @@ func (f *isWrapper) String() string {
 }
 
 func run(pass *analysis.Pass) (interface{}, error) {
-       findPrintfLike(pass)
+       res := &Result{
+               funcs: make(map[*types.Func]Kind),
+       }
+       findPrintfLike(pass, res)
        checkCall(pass)
-       return nil, nil
+       return res, nil
 }
 
 type printfWrapper struct {
@@ -154,7 +205,7 @@ func maybePrintfWrapper(info *types.Info, decl ast.Decl) *printfWrapper {
 }
 
 // findPrintfLike scans the entire package to find printf-like functions.
-func findPrintfLike(pass *analysis.Pass) (interface{}, error) {
+func findPrintfLike(pass *analysis.Pass, res *Result) (interface{}, error) {
        // Gather potential wrappers and call graph between them.
        byObj := make(map[*types.Func]*printfWrapper)
        var wrappers []*printfWrapper
@@ -209,7 +260,7 @@ func findPrintfLike(pass *analysis.Pass) (interface{}, error) {
 
                        fn, kind := printfNameAndKind(pass, call)
                        if kind != 0 {
-                               checkPrintfFwd(pass, w, call, kind)
+                               checkPrintfFwd(pass, w, call, kind, res)
                                return true
                        }
 
@@ -232,20 +283,11 @@ func match(info *types.Info, arg ast.Expr, param *types.Var) bool {
        return ok && info.ObjectOf(id) == param
 }
 
-type funcKind int
-
-const (
-       kindUnknown funcKind = iota
-       kindPrintf           = iota
-       kindPrint
-       kindErrorf
-)
-
 // checkPrintfFwd checks that a printf-forwarding wrapper is forwarding correctly.
 // It diagnoses writing fmt.Printf(format, args) instead of fmt.Printf(format, args...).
-func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, kind funcKind) {
-       matched := kind == kindPrint ||
-               kind != kindUnknown && len(call.Args) >= 2 && match(pass.TypesInfo, call.Args[len(call.Args)-2], w.format)
+func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, kind Kind, res *Result) {
+       matched := kind == KindPrint ||
+               kind != KindNone && len(call.Args) >= 2 && match(pass.TypesInfo, call.Args[len(call.Args)-2], w.format)
        if !matched {
                return
        }
@@ -266,10 +308,10 @@ func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, k
                        return
                }
                desc := "printf"
-               if kind == kindPrint {
+               if kind == KindPrint {
                        desc = "print"
                }
-               pass.Reportf(call.Pos(), "missing ... in args forwarded to %s-like function", desc)
+               pass.ReportRangef(call, "missing ... in args forwarded to %s-like function", desc)
                return
        }
        fn := w.obj
@@ -277,8 +319,9 @@ func checkPrintfFwd(pass *analysis.Pass, w *printfWrapper, call *ast.CallExpr, k
        if !pass.ImportObjectFact(fn, &fact) {
                fact.Kind = kind
                pass.ExportObjectFact(fn, &fact)
+               res.funcs[fn] = kind
                for _, caller := range w.callers {
-                       checkPrintfFwd(pass, caller.w, caller.call, kind)
+                       checkPrintfFwd(pass, caller.w, caller.call, kind, res)
                }
        }
 }
@@ -427,15 +470,15 @@ func checkCall(pass *analysis.Pass) {
                call := n.(*ast.CallExpr)
                fn, kind := printfNameAndKind(pass, call)
                switch kind {
-               case kindPrintf, kindErrorf:
+               case KindPrintf, KindErrorf:
                        checkPrintf(pass, kind, call, fn)
-               case kindPrint:
+               case KindPrint:
                        checkPrint(pass, call, fn)
                }
        })
 }
 
-func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, kind funcKind) {
+func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func, kind Kind) {
        fn, _ = typeutil.Callee(pass.TypesInfo, call).(*types.Func)
        if fn == nil {
                return nil, 0
@@ -448,11 +491,11 @@ func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func,
        }
        if ok {
                if fn.Name() == "Errorf" {
-                       kind = kindErrorf
+                       kind = KindErrorf
                } else if strings.HasSuffix(fn.Name(), "f") {
-                       kind = kindPrintf
+                       kind = KindPrintf
                } else {
-                       kind = kindPrint
+                       kind = KindPrint
                }
                return fn, kind
        }
@@ -462,7 +505,7 @@ func printfNameAndKind(pass *analysis.Pass, call *ast.CallExpr) (fn *types.Func,
                return fn, fact.Kind
        }
 
-       return fn, kindUnknown
+       return fn, KindNone
 }
 
 // isFormatter reports whether t satisfies fmt.Formatter.
@@ -504,7 +547,7 @@ type formatState struct {
 }
 
 // checkPrintf checks a call to a formatted print routine such as Printf.
-func checkPrintf(pass *analysis.Pass, kind funcKind, call *ast.CallExpr, fn *types.Func) {
+func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, fn *types.Func) {
        format, idx := formatString(pass, call)
        if idx < 0 {
                if false {
@@ -542,7 +585,7 @@ func checkPrintf(pass *analysis.Pass, kind funcKind, call *ast.CallExpr, fn *typ
                        anyIndex = true
                }
                if state.verb == 'w' {
-                       if kind != kindErrorf {
+                       if kind != KindErrorf {
                                pass.Reportf(call.Pos(), "%s call has error-wrapping directive %%w", state.name)
                                return
                        }
@@ -574,7 +617,7 @@ func checkPrintf(pass *analysis.Pass, kind funcKind, call *ast.CallExpr, fn *typ
        if maxArgNum != len(call.Args) {
                expect := maxArgNum - firstArg
                numArgs := len(call.Args) - firstArg
-               pass.Reportf(call.Pos(), "%s call needs %v but has %v", fn.Name(), count(expect, "arg"), count(numArgs, "arg"))
+               pass.ReportRangef(call, "%s call needs %v but has %v", fn.Name(), count(expect, "arg"), count(numArgs, "arg"))
        }
 }
 
@@ -615,13 +658,13 @@ func (s *formatState) parseIndex() bool {
                ok = false
                s.nbytes = strings.Index(s.format, "]")
                if s.nbytes < 0 {
-                       s.pass.Reportf(s.call.Pos(), "%s format %s is missing closing ]", s.name, s.format)
+                       s.pass.ReportRangef(s.call, "%s format %s is missing closing ]", s.name, s.format)
                        return false
                }
        }
        arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32)
        if err != nil || !ok || arg32 <= 0 || arg32 > int64(len(s.call.Args)-s.firstArg) {
-               s.pass.Reportf(s.call.Pos(), "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes])
+               s.pass.ReportRangef(s.call, "%s format has invalid argument index [%s]", s.name, s.format[start:s.nbytes])
                return false
        }
        s.nbytes++ // skip ']'
@@ -698,7 +741,7 @@ func parsePrintfVerb(pass *analysis.Pass, call *ast.CallExpr, name, format strin
                return nil
        }
        if state.nbytes == len(state.format) {
-               pass.Reportf(call.Pos(), "%s format %s is missing verb at end of string", name, state.format)
+               pass.ReportRangef(call.Fun, "%s format %s is missing verb at end of string", name, state.format)
                return nil
        }
        verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:])
@@ -748,7 +791,7 @@ var printVerbs = []printVerb{
        // '#' is alternate format for several verbs.
        // ' ' is spacer for numbers
        {'%', noFlag, 0},
-       {'b', numFlag, argInt | argFloat | argComplex | argPointer},
+       {'b', sharpNumFlag, argInt | argFloat | argComplex | argPointer},
        {'c', "-", argRune | argInt},
        {'d', numFlag, argInt | argPointer},
        {'e', sharpNumFlag, argFloat | argComplex},
@@ -794,7 +837,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
 
        if !formatter {
                if !found {
-                       pass.Reportf(call.Pos(), "%s format %s has unknown verb %c", state.name, state.format, state.verb)
+                       pass.ReportRangef(call, "%s format %s has unknown verb %c", state.name, state.format, state.verb)
                        return false
                }
                for _, flag := range state.flags {
@@ -804,7 +847,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
                                continue
                        }
                        if !strings.ContainsRune(v.flags, rune(flag)) {
-                               pass.Reportf(call.Pos(), "%s format %s has unrecognized flag %c", state.name, state.format, flag)
+                               pass.ReportRangef(call, "%s format %s has unrecognized flag %c", state.name, state.format, flag)
                                return false
                        }
                }
@@ -823,7 +866,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
                }
                arg := call.Args[argNum]
                if !matchArgType(pass, argInt, nil, arg) {
-                       pass.Reportf(call.Pos(), "%s format %s uses non-int %s as argument of *", state.name, state.format, analysisutil.Format(pass.Fset, arg))
+                       pass.ReportRangef(call, "%s format %s uses non-int %s as argument of *", state.name, state.format, analysisutil.Format(pass.Fset, arg))
                        return false
                }
        }
@@ -837,7 +880,7 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
        }
        arg := call.Args[argNum]
        if isFunctionValue(pass, arg) && state.verb != 'p' && state.verb != 'T' {
-               pass.Reportf(call.Pos(), "%s format %s arg %s is a func value, not called", state.name, state.format, analysisutil.Format(pass.Fset, arg))
+               pass.ReportRangef(call, "%s format %s arg %s is a func value, not called", state.name, state.format, analysisutil.Format(pass.Fset, arg))
                return false
        }
        if !matchArgType(pass, v.typ, nil, arg) {
@@ -845,11 +888,11 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, state *formatState) (o
                if typ := pass.TypesInfo.Types[arg].Type; typ != nil {
                        typeString = typ.String()
                }
-               pass.Reportf(call.Pos(), "%s format %s has arg %s of wrong type %s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString)
+               pass.ReportRangef(call, "%s format %s has arg %s of wrong type %s", state.name, state.format, analysisutil.Format(pass.Fset, arg), typeString)
                return false
        }
        if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) && recursiveStringer(pass, arg) {
-               pass.Reportf(call.Pos(), "%s format %s with arg %s causes recursive String method call", state.name, state.format, analysisutil.Format(pass.Fset, arg))
+               pass.ReportRangef(call, "%s format %s with arg %s causes recursive String method call", state.name, state.format, analysisutil.Format(pass.Fset, arg))
                return false
        }
        return true
@@ -935,7 +978,7 @@ func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, formatArg int, sta
        // There are bad indexes in the format or there are fewer arguments than the format needs.
        // This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi".
        arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed.
-       pass.Reportf(call.Pos(), "%s format %s reads arg #%d, but call has %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg"))
+       pass.ReportRangef(call, "%s format %s reads arg #%d, but call has %v", state.name, state.format, arg, count(len(call.Args)-state.firstArg, "arg"))
        return false
 }
 
@@ -986,7 +1029,7 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
                if sel, ok := call.Args[0].(*ast.SelectorExpr); ok {
                        if x, ok := sel.X.(*ast.Ident); ok {
                                if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
-                                       pass.Reportf(call.Pos(), "%s does not take io.Writer but has first arg %s", fn.Name(), analysisutil.Format(pass.Fset, call.Args[0]))
+                                       pass.ReportRangef(call, "%s does not take io.Writer but has first arg %s", fn.Name(), analysisutil.Format(pass.Fset, call.Args[0]))
                                }
                        }
                }
@@ -1000,7 +1043,7 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
                if strings.Contains(s, "%") {
                        m := printFormatRE.FindStringSubmatch(s)
                        if m != nil {
-                               pass.Reportf(call.Pos(), "%s call has possible formatting directive %s", fn.Name(), m[0])
+                               pass.ReportRangef(call, "%s call has possible formatting directive %s", fn.Name(), m[0])
                        }
                }
        }
@@ -1010,16 +1053,16 @@ func checkPrint(pass *analysis.Pass, call *ast.CallExpr, fn *types.Func) {
                if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
                        str, _ := strconv.Unquote(lit.Value)
                        if strings.HasSuffix(str, "\n") {
-                               pass.Reportf(call.Pos(), "%s arg list ends with redundant newline", fn.Name())
+                               pass.ReportRangef(call, "%s arg list ends with redundant newline", fn.Name())
                        }
                }
        }
        for _, arg := range args {
                if isFunctionValue(pass, arg) {
-                       pass.Reportf(call.Pos(), "%s arg %s is a func value, not called", fn.Name(), analysisutil.Format(pass.Fset, arg))
+                       pass.ReportRangef(call, "%s arg %s is a func value, not called", fn.Name(), analysisutil.Format(pass.Fset, arg))
                }
                if recursiveStringer(pass, arg) {
-                       pass.Reportf(call.Pos(), "%s arg %s causes recursive call to String method", fn.Name(), analysisutil.Format(pass.Fset, arg))
+                       pass.ReportRangef(call, "%s arg %s causes recursive call to String method", fn.Name(), analysisutil.Format(pass.Fset, arg))
                }
        }
 }
index 39f54573c9fd644c8279e89aa67f77b9b8129efb..0db95dafb07bc6e4cf9270878ba3cc6911201e34 100644 (file)
@@ -94,6 +94,6 @@ func checkLongShift(pass *analysis.Pass, node ast.Node, x, y ast.Expr) {
        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)
+               pass.ReportRangef(node, "%s (%d bits) too small for shift of %d", ident, size, amt)
        }
 }
index bc1db7e4c2e5562e4bb5ad2f9880ba81839345d0..856c6ae0d811eef294a0016fe526c4ca783391ec 100644 (file)
@@ -141,7 +141,7 @@ func canonicalMethod(pass *analysis.Pass, id *ast.Ident) {
                actual = strings.TrimPrefix(actual, "func")
                actual = id.Name + actual
 
-               pass.Reportf(id.Pos(), "method %s should have signature %s", actual, expectFmt)
+               pass.ReportRangef(id, "method %s should have signature %s", actual, expectFmt)
        }
 }
 
index 19bc9c2db988b4ecd9e2b633c3889912e764c180..089c064838dda96fd86bdb0421ada5697ed5802e 100644 (file)
@@ -189,7 +189,7 @@ func (d *deadState) findDead(stmt ast.Stmt) {
                case *ast.EmptyStmt:
                        // do not warn about unreachable empty statements
                default:
-                       d.pass.Reportf(stmt.Pos(), "unreachable code")
+                       d.pass.ReportRangef(stmt, "unreachable code")
                        d.reachable = true // silence error about next statement
                }
        }
index 308bfc69cb44d538733a91d35efcdbb2f24d08ae..d5bafb859d2ce6bed700f9cb43562f4bbe28f94d 100644 (file)
@@ -45,7 +45,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
                if hasBasicType(pass.TypesInfo, x.Fun, types.UnsafePointer) &&
                        hasBasicType(pass.TypesInfo, x.Args[0], types.Uintptr) &&
                        !isSafeUintptr(pass.TypesInfo, x.Args[0]) {
-                       pass.Reportf(x.Pos(), "possible misuse of unsafe.Pointer")
+                       pass.ReportRangef(x, "possible misuse of unsafe.Pointer")
                }
        })
        return nil, nil
index 6cc6ed87fad9ea7deb4c42a52b3254bb16b0dade..7bca3d0d3df4206dfd4cc5be17c834b8c4f83a9c 100644 (file)
@@ -43,7 +43,7 @@ golang.org/x/mod/sumdb/tlog
 ## explicit
 golang.org/x/sys/unix
 golang.org/x/sys/windows
-# golang.org/x/tools v0.0.0-20191018203202-04252eccb9d5
+# golang.org/x/tools v0.0.0-20191104222624-6b7b8b79ae80
 ## explicit
 golang.org/x/tools/go/analysis
 golang.org/x/tools/go/analysis/internal/analysisflags