]> Cypherpunks repositories - gostls13.git/commitdiff
cmd: update golang.org/x/tools to v0.0.0-20200901153117-6e59e24738da
authorTzu-Chiao Yeh <su3g4284zo6y7@gmail.com>
Sun, 6 Sep 2020 01:43:34 +0000 (09:43 +0800)
committerEmmanuel Odeke <emm.odeke@gmail.com>
Wed, 9 Sep 2020 22:03:39 +0000 (22:03 +0000)
Includes the latest fix on vet to warn unused context.WithValue result.

Fixes #41149

Change-Id: I06c204f40ef12b0f62f59b1bbdf1fe06ccd6565d
Reviewed-on: https://go-review.googlesource.com/c/go/+/252941
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
src/cmd/go.mod
src/cmd/go.sum
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/structtag/structtag.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unmarshal/unmarshal.go
src/cmd/vendor/golang.org/x/tools/go/analysis/passes/unusedresult/unusedresult.go
src/cmd/vendor/golang.org/x/tools/internal/analysisinternal/analysis.go
src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/input.go [new file with mode: 0644]
src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/matcher.go [new file with mode: 0644]
src/cmd/vendor/modules.txt

index 68ce1705e4131474791fc0cf8843117a46aa13fd..0952dbb84cb56de180d3c02b91f2fff5eebe8e12 100644 (file)
@@ -9,6 +9,6 @@ require (
        golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
        golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449
        golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
-       golang.org/x/tools v0.0.0-20200616133436-c1934b75d054
+       golang.org/x/tools v0.0.0-20200901153117-6e59e24738da
        golang.org/x/xerrors v0.0.0-20200806184451-1a77d5e9f316 // indirect
 )
index cb64a5d47573fb1d14df1f7754b3addd1e2dab83..adbc5a96ac363cf2165ed5d3c83be2d77a97dd9f 100644 (file)
@@ -6,33 +6,34 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 h1:S1+yTUaFPXuDZnPDbO+TrDFIjPzQraYH8/CwSlu9Fac=
 github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
-github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 golang.org/x/arch v0.0.0-20200511175325-f7c78586839d h1:YvwchuJby5xEAPdBGmdAVSiVME50C+RJfJJwJJsGEV8=
 golang.org/x/arch v0.0.0-20200511175325-f7c78586839d/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449 h1:xUIPaMhvROX9dhPvRCenIJtU78+lbEenGbgqB5hfHCQ=
 golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 h1:5B6i6EAiSYyejWfvc5Rc9BbI3rzIsrrXfAQBWnYfn+w=
 golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200616133436-c1934b75d054 h1:HHeAlu5H9b71C+Fx0K+1dGgVFN1DM1/wz4aoGOA5qS8=
-golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200901153117-6e59e24738da h1:8nFbt74voFOsM+Hb5XtF+1SNbbf3dzikH5osZO1hyyo=
+golang.org/x/tools v0.0.0-20200901153117-6e59e24738da/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200806184451-1a77d5e9f316 h1:Jhw4VC65LaKnpq9FvcK+a8ZzrFm3D+UygvMMrhkOw70=
 golang.org/x/xerrors v0.0.0-20200806184451-1a77d5e9f316/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
index e09160379f6b118ac4068c05915042768d50ed72..f0b15051c52eacc1cc5fd6912bfa03dcb3ea7558 100644 (file)
@@ -116,7 +116,11 @@ func checkCanonicalFieldTag(pass *analysis.Pass, field *types.Var, tag string, s
        }
 
        for _, enc := range [...]string{"json", "xml"} {
-               if reflect.StructTag(tag).Get(enc) != "" {
+               switch reflect.StructTag(tag).Get(enc) {
+               // Ignore warning if the field not exported and the tag is marked as
+               // ignored.
+               case "", "-":
+               default:
                        pass.Reportf(field.Pos(), "struct field %s has %s tag but is not exported", field.Name(), enc)
                        return
                }
index f9cc993cbb42639c2482398d5504c2b22fca3088..92b37caff9f113c7f2122dd004f9e324ec065de7 100644 (file)
@@ -30,7 +30,7 @@ var Analyzer = &analysis.Analyzer{
 
 func run(pass *analysis.Pass) (interface{}, error) {
        switch pass.Pkg.Path() {
-       case "encoding/gob", "encoding/json", "encoding/xml":
+       case "encoding/gob", "encoding/json", "encoding/xml", "encoding/asn1":
                // These packages know how to use their own APIs.
                // Sometimes they are testing what happens to incorrect programs.
                return nil, nil
@@ -53,9 +53,10 @@ func run(pass *analysis.Pass) (interface{}, error) {
                recv := fn.Type().(*types.Signature).Recv()
                if fn.Name() == "Unmarshal" && recv == nil {
                        // "encoding/json".Unmarshal
-                       //  "encoding/xml".Unmarshal
+                       // "encoding/xml".Unmarshal
+                       // "encoding/asn1".Unmarshal
                        switch fn.Pkg().Path() {
-                       case "encoding/json", "encoding/xml":
+                       case "encoding/json", "encoding/xml", "encoding/asn1":
                                argidx = 1 // func([]byte, interface{})
                        }
                } else if fn.Name() == "Decode" && recv != nil {
index 76d4ab23827677e169e2d68e376a187889de0068..bececee7e9399173937c73d1ed77a6ee20290bda 100644 (file)
@@ -44,7 +44,7 @@ var funcs, stringMethods stringSetFlag
 func init() {
        // TODO(adonovan): provide a comment syntax to allow users to
        // add their functions to this set using facts.
-       funcs.Set("errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse")
+       funcs.Set("errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse,context.WithValue,context.WithCancel,context.WithDeadline,context.WithTimeout")
        Analyzer.Flags.Var(&funcs, "funcs",
                "comma-separated list of functions whose results must be used")
 
index 26586810c7f5ad662c9f580601af5350248b4118..01f6e829f75300d80a4a52f2a485b37d05faa206 100644 (file)
@@ -14,6 +14,12 @@ import (
        "strings"
 
        "golang.org/x/tools/go/ast/astutil"
+       "golang.org/x/tools/internal/lsp/fuzzy"
+)
+
+var (
+       GetTypeErrors func(p interface{}) []types.Error
+       SetTypeErrors func(p interface{}, errors []types.Error)
 )
 
 func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos {
@@ -45,32 +51,34 @@ func ZeroValue(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.T
                default:
                        panic("unknown basic type")
                }
-       case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice:
+       case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice, *types.Array:
                return ast.NewIdent("nil")
        case *types.Struct:
-               texpr := typeExpr(fset, f, pkg, typ) // typ because we want the name here.
+               texpr := TypeExpr(fset, f, pkg, typ) // typ because we want the name here.
                if texpr == nil {
                        return nil
                }
                return &ast.CompositeLit{
                        Type: texpr,
                }
-       case *types.Array:
-               texpr := typeExpr(fset, f, pkg, u.Elem())
-               if texpr == nil {
-                       return nil
-               }
-               return &ast.CompositeLit{
-                       Type: &ast.ArrayType{
-                               Elt: texpr,
-                               Len: &ast.BasicLit{Kind: token.INT, Value: fmt.Sprintf("%v", u.Len())},
-                       },
-               }
        }
        return nil
 }
 
-func typeExpr(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
+// IsZeroValue checks whether the given expression is a 'zero value' (as determined by output of
+// analysisinternal.ZeroValue)
+func IsZeroValue(expr ast.Expr) bool {
+       switch e := expr.(type) {
+       case *ast.BasicLit:
+               return e.Value == "0" || e.Value == `""`
+       case *ast.Ident:
+               return e.Name == "nil" || e.Name == "false"
+       default:
+               return false
+       }
+}
+
+func TypeExpr(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
        switch t := typ.(type) {
        case *types.Basic:
                switch t.Kind() {
@@ -79,7 +87,96 @@ func typeExpr(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Ty
                default:
                        return ast.NewIdent(t.Name())
                }
+       case *types.Pointer:
+               x := TypeExpr(fset, f, pkg, t.Elem())
+               if x == nil {
+                       return nil
+               }
+               return &ast.UnaryExpr{
+                       Op: token.MUL,
+                       X:  x,
+               }
+       case *types.Array:
+               elt := TypeExpr(fset, f, pkg, t.Elem())
+               if elt == nil {
+                       return nil
+               }
+               return &ast.ArrayType{
+                       Len: &ast.BasicLit{
+                               Kind:  token.INT,
+                               Value: fmt.Sprintf("%d", t.Len()),
+                       },
+                       Elt: elt,
+               }
+       case *types.Slice:
+               elt := TypeExpr(fset, f, pkg, t.Elem())
+               if elt == nil {
+                       return nil
+               }
+               return &ast.ArrayType{
+                       Elt: elt,
+               }
+       case *types.Map:
+               key := TypeExpr(fset, f, pkg, t.Key())
+               value := TypeExpr(fset, f, pkg, t.Elem())
+               if key == nil || value == nil {
+                       return nil
+               }
+               return &ast.MapType{
+                       Key:   key,
+                       Value: value,
+               }
+       case *types.Chan:
+               dir := ast.ChanDir(t.Dir())
+               if t.Dir() == types.SendRecv {
+                       dir = ast.SEND | ast.RECV
+               }
+               value := TypeExpr(fset, f, pkg, t.Elem())
+               if value == nil {
+                       return nil
+               }
+               return &ast.ChanType{
+                       Dir:   dir,
+                       Value: value,
+               }
+       case *types.Signature:
+               var params []*ast.Field
+               for i := 0; i < t.Params().Len(); i++ {
+                       p := TypeExpr(fset, f, pkg, t.Params().At(i).Type())
+                       if p == nil {
+                               return nil
+                       }
+                       params = append(params, &ast.Field{
+                               Type: p,
+                               Names: []*ast.Ident{
+                                       {
+                                               Name: t.Params().At(i).Name(),
+                                       },
+                               },
+                       })
+               }
+               var returns []*ast.Field
+               for i := 0; i < t.Results().Len(); i++ {
+                       r := TypeExpr(fset, f, pkg, t.Results().At(i).Type())
+                       if r == nil {
+                               return nil
+                       }
+                       returns = append(returns, &ast.Field{
+                               Type: r,
+                       })
+               }
+               return &ast.FuncType{
+                       Params: &ast.FieldList{
+                               List: params,
+                       },
+                       Results: &ast.FieldList{
+                               List: returns,
+                       },
+               }
        case *types.Named:
+               if t.Obj().Pkg() == nil {
+                       return ast.NewIdent(t.Obj().Name())
+               }
                if t.Obj().Pkg() == pkg {
                        return ast.NewIdent(t.Obj().Name())
                }
@@ -101,14 +198,15 @@ func typeExpr(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Ty
                        X:   ast.NewIdent(pkgName),
                        Sel: ast.NewIdent(t.Obj().Name()),
                }
+       case *types.Struct:
+               return ast.NewIdent(t.String())
+       case *types.Interface:
+               return ast.NewIdent(t.String())
        default:
-               return nil // TODO: anonymous structs, but who does that
+               return nil
        }
 }
 
-var GetTypeErrors = func(p interface{}) []types.Error { return nil }
-var SetTypeErrors = func(p interface{}, errors []types.Error) {}
-
 type TypeErrorPass string
 
 const (
@@ -116,3 +214,212 @@ const (
        NoResultValues TypeErrorPass = "noresultvalues"
        UndeclaredName TypeErrorPass = "undeclaredname"
 )
+
+// StmtToInsertVarBefore returns the ast.Stmt before which we can safely insert a new variable.
+// Some examples:
+//
+// Basic Example:
+// z := 1
+// y := z + x
+// If x is undeclared, then this function would return `y := z + x`, so that we
+// can insert `x := ` on the line before `y := z + x`.
+//
+// If stmt example:
+// if z == 1 {
+// } else if z == y {}
+// If y is undeclared, then this function would return `if z == 1 {`, because we cannot
+// insert a statement between an if and an else if statement. As a result, we need to find
+// the top of the if chain to insert `y := ` before.
+func StmtToInsertVarBefore(path []ast.Node) ast.Stmt {
+       enclosingIndex := -1
+       for i, p := range path {
+               if _, ok := p.(ast.Stmt); ok {
+                       enclosingIndex = i
+                       break
+               }
+       }
+       if enclosingIndex == -1 {
+               return nil
+       }
+       enclosingStmt := path[enclosingIndex]
+       switch enclosingStmt.(type) {
+       case *ast.IfStmt:
+               // The enclosingStmt is inside of the if declaration,
+               // We need to check if we are in an else-if stmt and
+               // get the base if statement.
+               return baseIfStmt(path, enclosingIndex)
+       case *ast.CaseClause:
+               // Get the enclosing switch stmt if the enclosingStmt is
+               // inside of the case statement.
+               for i := enclosingIndex + 1; i < len(path); i++ {
+                       if node, ok := path[i].(*ast.SwitchStmt); ok {
+                               return node
+                       } else if node, ok := path[i].(*ast.TypeSwitchStmt); ok {
+                               return node
+                       }
+               }
+       }
+       if len(path) <= enclosingIndex+1 {
+               return enclosingStmt.(ast.Stmt)
+       }
+       // Check if the enclosing statement is inside another node.
+       switch expr := path[enclosingIndex+1].(type) {
+       case *ast.IfStmt:
+               // Get the base if statement.
+               return baseIfStmt(path, enclosingIndex+1)
+       case *ast.ForStmt:
+               if expr.Init == enclosingStmt || expr.Post == enclosingStmt {
+                       return expr
+               }
+       }
+       return enclosingStmt.(ast.Stmt)
+}
+
+// baseIfStmt walks up the if/else-if chain until we get to
+// the top of the current if chain.
+func baseIfStmt(path []ast.Node, index int) ast.Stmt {
+       stmt := path[index]
+       for i := index + 1; i < len(path); i++ {
+               if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt {
+                       stmt = node
+                       continue
+               }
+               break
+       }
+       return stmt.(ast.Stmt)
+}
+
+// WalkASTWithParent walks the AST rooted at n. The semantics are
+// similar to ast.Inspect except it does not call f(nil).
+func WalkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) {
+       var ancestors []ast.Node
+       ast.Inspect(n, func(n ast.Node) (recurse bool) {
+               if n == nil {
+                       ancestors = ancestors[:len(ancestors)-1]
+                       return false
+               }
+
+               var parent ast.Node
+               if len(ancestors) > 0 {
+                       parent = ancestors[len(ancestors)-1]
+               }
+               ancestors = append(ancestors, n)
+               return f(n, parent)
+       })
+}
+
+// FindMatchingIdents finds all identifiers in 'node' that match any of the given types.
+// 'pos' represents the position at which the identifiers may be inserted. 'pos' must be within
+// the scope of each of identifier we select. Otherwise, we will insert a variable at 'pos' that
+// is unrecognized.
+func FindMatchingIdents(typs []types.Type, node ast.Node, pos token.Pos, info *types.Info, pkg *types.Package) map[types.Type][]*ast.Ident {
+       matches := map[types.Type][]*ast.Ident{}
+       // Initialize matches to contain the variable types we are searching for.
+       for _, typ := range typs {
+               if typ == nil {
+                       continue
+               }
+               matches[typ] = []*ast.Ident{}
+       }
+       seen := map[types.Object]struct{}{}
+       ast.Inspect(node, func(n ast.Node) bool {
+               if n == nil {
+                       return false
+               }
+               // Prevent circular definitions. If 'pos' is within an assignment statement, do not
+               // allow any identifiers in that assignment statement to be selected. Otherwise,
+               // we could do the following, where 'x' satisfies the type of 'f0':
+               //
+               // x := fakeStruct{f0: x}
+               //
+               assignment, ok := n.(*ast.AssignStmt)
+               if ok && pos > assignment.Pos() && pos <= assignment.End() {
+                       return false
+               }
+               if n.End() > pos {
+                       return n.Pos() <= pos
+               }
+               ident, ok := n.(*ast.Ident)
+               if !ok || ident.Name == "_" {
+                       return true
+               }
+               obj := info.Defs[ident]
+               if obj == nil || obj.Type() == nil {
+                       return true
+               }
+               if _, ok := obj.(*types.TypeName); ok {
+                       return true
+               }
+               // Prevent duplicates in matches' values.
+               if _, ok = seen[obj]; ok {
+                       return true
+               }
+               seen[obj] = struct{}{}
+               // Find the scope for the given position. Then, check whether the object
+               // exists within the scope.
+               innerScope := pkg.Scope().Innermost(pos)
+               if innerScope == nil {
+                       return true
+               }
+               _, foundObj := innerScope.LookupParent(ident.Name, pos)
+               if foundObj != obj {
+                       return true
+               }
+               // The object must match one of the types that we are searching for.
+               if idents, ok := matches[obj.Type()]; ok {
+                       matches[obj.Type()] = append(idents, ast.NewIdent(ident.Name))
+               }
+               // If the object type does not exactly match any of the target types, greedily
+               // find the first target type that the object type can satisfy.
+               for typ := range matches {
+                       if obj.Type() == typ {
+                               continue
+                       }
+                       if equivalentTypes(obj.Type(), typ) {
+                               matches[typ] = append(matches[typ], ast.NewIdent(ident.Name))
+                       }
+               }
+               return true
+       })
+       return matches
+}
+
+func equivalentTypes(want, got types.Type) bool {
+       if want == got || types.Identical(want, got) {
+               return true
+       }
+       // Code segment to help check for untyped equality from (golang/go#32146).
+       if rhs, ok := want.(*types.Basic); ok && rhs.Info()&types.IsUntyped > 0 {
+               if lhs, ok := got.Underlying().(*types.Basic); ok {
+                       return rhs.Info()&types.IsConstType == lhs.Info()&types.IsConstType
+               }
+       }
+       return types.AssignableTo(want, got)
+}
+
+// FindBestMatch employs fuzzy matching to evaluate the similarity of each given identifier to the
+// given pattern. We return the identifier whose name is most similar to the pattern.
+func FindBestMatch(pattern string, idents []*ast.Ident) ast.Expr {
+       fuzz := fuzzy.NewMatcher(pattern)
+       var bestFuzz ast.Expr
+       highScore := float32(0) // minimum score is 0 (no match)
+       for _, ident := range idents {
+               // TODO: Improve scoring algorithm.
+               score := fuzz.Score(ident.Name)
+               if score > highScore {
+                       highScore = score
+                       bestFuzz = ident
+               } else if score == 0 {
+                       // Order matters in the fuzzy matching algorithm. If we find no match
+                       // when matching the target to the identifier, try matching the identifier
+                       // to the target.
+                       revFuzz := fuzzy.NewMatcher(ident.Name)
+                       revScore := revFuzz.Score(pattern)
+                       if revScore > highScore {
+                               highScore = revScore
+                               bestFuzz = ident
+                       }
+               }
+       }
+       return bestFuzz
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/input.go b/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/input.go
new file mode 100644 (file)
index 0000000..ac37703
--- /dev/null
@@ -0,0 +1,168 @@
+// Copyright 2019 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.
+
+package fuzzy
+
+import (
+       "unicode"
+)
+
+// RuneRole specifies the role of a rune in the context of an input.
+type RuneRole byte
+
+const (
+       // RNone specifies a rune without any role in the input (i.e., whitespace/non-ASCII).
+       RNone RuneRole = iota
+       // RSep specifies a rune with the role of segment separator.
+       RSep
+       // RTail specifies a rune which is a lower-case tail in a word in the input.
+       RTail
+       // RUCTail specifies a rune which is an upper-case tail in a word in the input.
+       RUCTail
+       // RHead specifies a rune which is the first character in a word in the input.
+       RHead
+)
+
+// RuneRoles detects the roles of each byte rune in an input string and stores it in the output
+// slice. The rune role depends on the input type. Stops when it parsed all the runes in the string
+// or when it filled the output. If output is nil, then it gets created.
+func RuneRoles(str string, reuse []RuneRole) []RuneRole {
+       var output []RuneRole
+       if cap(reuse) < len(str) {
+               output = make([]RuneRole, 0, len(str))
+       } else {
+               output = reuse[:0]
+       }
+
+       prev, prev2 := rtNone, rtNone
+       for i := 0; i < len(str); i++ {
+               r := rune(str[i])
+
+               role := RNone
+
+               curr := rtLower
+               if str[i] <= unicode.MaxASCII {
+                       curr = runeType(rt[str[i]] - '0')
+               }
+
+               if curr == rtLower {
+                       if prev == rtNone || prev == rtPunct {
+                               role = RHead
+                       } else {
+                               role = RTail
+                       }
+               } else if curr == rtUpper {
+                       role = RHead
+
+                       if prev == rtUpper {
+                               // This and previous characters are both upper case.
+
+                               if i+1 == len(str) {
+                                       // This is last character, previous was also uppercase -> this is UCTail
+                                       // i.e., (current char is C): aBC / BC / ABC
+                                       role = RUCTail
+                               }
+                       }
+               } else if curr == rtPunct {
+                       switch r {
+                       case '.', ':':
+                               role = RSep
+                       }
+               }
+               if curr != rtLower {
+                       if i > 1 && output[i-1] == RHead && prev2 == rtUpper && (output[i-2] == RHead || output[i-2] == RUCTail) {
+                               // The previous two characters were uppercase. The current one is not a lower case, so the
+                               // previous one can't be a HEAD. Make it a UCTail.
+                               // i.e., (last char is current char - B must be a UCTail): ABC / ZABC / AB.
+                               output[i-1] = RUCTail
+                       }
+               }
+
+               output = append(output, role)
+               prev2 = prev
+               prev = curr
+       }
+       return output
+}
+
+type runeType byte
+
+const (
+       rtNone runeType = iota
+       rtPunct
+       rtLower
+       rtUpper
+)
+
+const rt = "00000000000000000000000000000000000000000000001122222222221000000333333333333333333333333330000002222222222222222222222222200000"
+
+// LastSegment returns the substring representing the last segment from the input, where each
+// byte has an associated RuneRole in the roles slice. This makes sense only for inputs of Symbol
+// or Filename type.
+func LastSegment(input string, roles []RuneRole) string {
+       // Exclude ending separators.
+       end := len(input) - 1
+       for end >= 0 && roles[end] == RSep {
+               end--
+       }
+       if end < 0 {
+               return ""
+       }
+
+       start := end - 1
+       for start >= 0 && roles[start] != RSep {
+               start--
+       }
+
+       return input[start+1 : end+1]
+}
+
+// ToLower transforms the input string to lower case, which is stored in the output byte slice.
+// The lower casing considers only ASCII values - non ASCII values are left unmodified.
+// Stops when parsed all input or when it filled the output slice. If output is nil, then it gets
+// created.
+func ToLower(input string, reuse []byte) []byte {
+       output := reuse
+       if cap(reuse) < len(input) {
+               output = make([]byte, len(input))
+       }
+
+       for i := 0; i < len(input); i++ {
+               r := rune(input[i])
+               if r <= unicode.MaxASCII {
+                       if 'A' <= r && r <= 'Z' {
+                               r += 'a' - 'A'
+                       }
+               }
+               output[i] = byte(r)
+       }
+       return output[:len(input)]
+}
+
+// WordConsumer defines a consumer for a word delimited by the [start,end) byte offsets in an input
+// (start is inclusive, end is exclusive).
+type WordConsumer func(start, end int)
+
+// Words find word delimiters in an input based on its bytes' mappings to rune roles. The offset
+// delimiters for each word are fed to the provided consumer function.
+func Words(roles []RuneRole, consume WordConsumer) {
+       var wordStart int
+       for i, r := range roles {
+               switch r {
+               case RUCTail, RTail:
+               case RHead, RNone, RSep:
+                       if i != wordStart {
+                               consume(wordStart, i)
+                       }
+                       wordStart = i
+                       if r != RHead {
+                               // Skip this character.
+                               wordStart = i + 1
+                       }
+               }
+       }
+       if wordStart != len(roles) {
+               consume(wordStart, len(roles))
+       }
+}
diff --git a/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/matcher.go b/src/cmd/vendor/golang.org/x/tools/internal/lsp/fuzzy/matcher.go
new file mode 100644 (file)
index 0000000..16a6430
--- /dev/null
@@ -0,0 +1,398 @@
+// Copyright 2019 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.
+
+// Package fuzzy implements a fuzzy matching algorithm.
+package fuzzy
+
+import (
+       "bytes"
+       "fmt"
+)
+
+const (
+       // MaxInputSize is the maximum size of the input scored against the fuzzy matcher. Longer inputs
+       // will be truncated to this size.
+       MaxInputSize = 127
+       // MaxPatternSize is the maximum size of the pattern used to construct the fuzzy matcher. Longer
+       // inputs are truncated to this size.
+       MaxPatternSize = 63
+)
+
+type scoreVal int
+
+func (s scoreVal) val() int {
+       return int(s) >> 1
+}
+
+func (s scoreVal) prevK() int {
+       return int(s) & 1
+}
+
+func score(val int, prevK int /*0 or 1*/) scoreVal {
+       return scoreVal(val<<1 + prevK)
+}
+
+// Matcher implements a fuzzy matching algorithm for scoring candidates against a pattern.
+// The matcher does not support parallel usage.
+type Matcher struct {
+       pattern       string
+       patternLower  []byte // lower-case version of the pattern
+       patternShort  []byte // first characters of the pattern
+       caseSensitive bool   // set if the pattern is mix-cased
+
+       patternRoles []RuneRole // the role of each character in the pattern
+       roles        []RuneRole // the role of each character in the tested string
+
+       scores [MaxInputSize + 1][MaxPatternSize + 1][2]scoreVal
+
+       scoreScale float32
+
+       lastCandidateLen     int // in bytes
+       lastCandidateMatched bool
+
+       // Here we save the last candidate in lower-case. This is basically a byte slice we reuse for
+       // performance reasons, so the slice is not reallocated for every candidate.
+       lowerBuf [MaxInputSize]byte
+       rolesBuf [MaxInputSize]RuneRole
+}
+
+func (m *Matcher) bestK(i, j int) int {
+       if m.scores[i][j][0].val() < m.scores[i][j][1].val() {
+               return 1
+       }
+       return 0
+}
+
+// NewMatcher returns a new fuzzy matcher for scoring candidates against the provided pattern.
+func NewMatcher(pattern string) *Matcher {
+       if len(pattern) > MaxPatternSize {
+               pattern = pattern[:MaxPatternSize]
+       }
+
+       m := &Matcher{
+               pattern:      pattern,
+               patternLower: ToLower(pattern, nil),
+       }
+
+       for i, c := range m.patternLower {
+               if pattern[i] != c {
+                       m.caseSensitive = true
+                       break
+               }
+       }
+
+       if len(pattern) > 3 {
+               m.patternShort = m.patternLower[:3]
+       } else {
+               m.patternShort = m.patternLower
+       }
+
+       m.patternRoles = RuneRoles(pattern, nil)
+
+       if len(pattern) > 0 {
+               maxCharScore := 4
+               m.scoreScale = 1 / float32(maxCharScore*len(pattern))
+       }
+
+       return m
+}
+
+// Score returns the score returned by matching the candidate to the pattern.
+// This is not designed for parallel use. Multiple candidates must be scored sequentially.
+// Returns a score between 0 and 1 (0 - no match, 1 - perfect match).
+func (m *Matcher) Score(candidate string) float32 {
+       if len(candidate) > MaxInputSize {
+               candidate = candidate[:MaxInputSize]
+       }
+       lower := ToLower(candidate, m.lowerBuf[:])
+       m.lastCandidateLen = len(candidate)
+
+       if len(m.pattern) == 0 {
+               // Empty patterns perfectly match candidates.
+               return 1
+       }
+
+       if m.match(candidate, lower) {
+               sc := m.computeScore(candidate, lower)
+               if sc > minScore/2 && !m.poorMatch() {
+                       m.lastCandidateMatched = true
+                       if len(m.pattern) == len(candidate) {
+                               // Perfect match.
+                               return 1
+                       }
+
+                       if sc < 0 {
+                               sc = 0
+                       }
+                       normalizedScore := float32(sc) * m.scoreScale
+                       if normalizedScore > 1 {
+                               normalizedScore = 1
+                       }
+
+                       return normalizedScore
+               }
+       }
+
+       m.lastCandidateMatched = false
+       return 0
+}
+
+const minScore = -10000
+
+// MatchedRanges returns matches ranges for the last scored string as a flattened array of
+// [begin, end) byte offset pairs.
+func (m *Matcher) MatchedRanges() []int {
+       if len(m.pattern) == 0 || !m.lastCandidateMatched {
+               return nil
+       }
+       i, j := m.lastCandidateLen, len(m.pattern)
+       if m.scores[i][j][0].val() < minScore/2 && m.scores[i][j][1].val() < minScore/2 {
+               return nil
+       }
+
+       var ret []int
+       k := m.bestK(i, j)
+       for i > 0 {
+               take := (k == 1)
+               k = m.scores[i][j][k].prevK()
+               if take {
+                       if len(ret) == 0 || ret[len(ret)-1] != i {
+                               ret = append(ret, i)
+                               ret = append(ret, i-1)
+                       } else {
+                               ret[len(ret)-1] = i - 1
+                       }
+                       j--
+               }
+               i--
+       }
+       // Reverse slice.
+       for i := 0; i < len(ret)/2; i++ {
+               ret[i], ret[len(ret)-1-i] = ret[len(ret)-1-i], ret[i]
+       }
+       return ret
+}
+
+func (m *Matcher) match(candidate string, candidateLower []byte) bool {
+       i, j := 0, 0
+       for ; i < len(candidateLower) && j < len(m.patternLower); i++ {
+               if candidateLower[i] == m.patternLower[j] {
+                       j++
+               }
+       }
+       if j != len(m.patternLower) {
+               return false
+       }
+
+       // The input passes the simple test against pattern, so it is time to classify its characters.
+       // Character roles are used below to find the last segment.
+       m.roles = RuneRoles(candidate, m.rolesBuf[:])
+
+       return true
+}
+
+func (m *Matcher) computeScore(candidate string, candidateLower []byte) int {
+       pattLen, candLen := len(m.pattern), len(candidate)
+
+       for j := 0; j <= len(m.pattern); j++ {
+               m.scores[0][j][0] = minScore << 1
+               m.scores[0][j][1] = minScore << 1
+       }
+       m.scores[0][0][0] = score(0, 0) // Start with 0.
+
+       segmentsLeft, lastSegStart := 1, 0
+       for i := 0; i < candLen; i++ {
+               if m.roles[i] == RSep {
+                       segmentsLeft++
+                       lastSegStart = i + 1
+               }
+       }
+
+       // A per-character bonus for a consecutive match.
+       consecutiveBonus := 2
+       wordIdx := 0 // Word count within segment.
+       for i := 1; i <= candLen; i++ {
+
+               role := m.roles[i-1]
+               isHead := role == RHead
+
+               if isHead {
+                       wordIdx++
+               } else if role == RSep && segmentsLeft > 1 {
+                       wordIdx = 0
+                       segmentsLeft--
+               }
+
+               var skipPenalty int
+               if i == 1 || (i-1) == lastSegStart {
+                       // Skipping the start of first or last segment.
+                       skipPenalty++
+               }
+
+               for j := 0; j <= pattLen; j++ {
+                       // By default, we don't have a match. Fill in the skip data.
+                       m.scores[i][j][1] = minScore << 1
+
+                       // Compute the skip score.
+                       k := 0
+                       if m.scores[i-1][j][0].val() < m.scores[i-1][j][1].val() {
+                               k = 1
+                       }
+
+                       skipScore := m.scores[i-1][j][k].val()
+                       // Do not penalize missing characters after the last matched segment.
+                       if j != pattLen {
+                               skipScore -= skipPenalty
+                       }
+                       m.scores[i][j][0] = score(skipScore, k)
+
+                       if j == 0 || candidateLower[i-1] != m.patternLower[j-1] {
+                               // Not a match.
+                               continue
+                       }
+                       pRole := m.patternRoles[j-1]
+
+                       if role == RTail && pRole == RHead {
+                               if j > 1 {
+                                       // Not a match: a head in the pattern matches a tail character in the candidate.
+                                       continue
+                               }
+                               // Special treatment for the first character of the pattern. We allow
+                               // matches in the middle of a word if they are long enough, at least
+                               // min(3, pattern.length) characters.
+                               if !bytes.HasPrefix(candidateLower[i-1:], m.patternShort) {
+                                       continue
+                               }
+                       }
+
+                       // Compute the char score.
+                       var charScore int
+                       // Bonus 1: the char is in the candidate's last segment.
+                       if segmentsLeft <= 1 {
+                               charScore++
+                       }
+                       // Bonus 2: Case match or a Head in the pattern aligns with one in the word.
+                       // Single-case patterns lack segmentation signals and we assume any character
+                       // can be a head of a segment.
+                       if candidate[i-1] == m.pattern[j-1] || role == RHead && (!m.caseSensitive || pRole == RHead) {
+                               charScore++
+                       }
+
+                       // Penalty 1: pattern char is Head, candidate char is Tail.
+                       if role == RTail && pRole == RHead {
+                               charScore--
+                       }
+                       // Penalty 2: first pattern character matched in the middle of a word.
+                       if j == 1 && role == RTail {
+                               charScore -= 4
+                       }
+
+                       // Third dimension encodes whether there is a gap between the previous match and the current
+                       // one.
+                       for k := 0; k < 2; k++ {
+                               sc := m.scores[i-1][j-1][k].val() + charScore
+
+                               isConsecutive := k == 1 || i-1 == 0 || i-1 == lastSegStart
+                               if isConsecutive {
+                                       // Bonus 3: a consecutive match. First character match also gets a bonus to
+                                       // ensure prefix final match score normalizes to 1.0.
+                                       // Logically, this is a part of charScore, but we have to compute it here because it
+                                       // only applies for consecutive matches (k == 1).
+                                       sc += consecutiveBonus
+                               }
+                               if k == 0 {
+                                       // Penalty 3: Matching inside a segment (and previous char wasn't matched). Penalize for the lack
+                                       // of alignment.
+                                       if role == RTail || role == RUCTail {
+                                               sc -= 3
+                                       }
+                               }
+
+                               if sc > m.scores[i][j][1].val() {
+                                       m.scores[i][j][1] = score(sc, k)
+                               }
+                       }
+               }
+       }
+
+       result := m.scores[len(candidate)][len(m.pattern)][m.bestK(len(candidate), len(m.pattern))].val()
+
+       return result
+}
+
+// ScoreTable returns the score table computed for the provided candidate. Used only for debugging.
+func (m *Matcher) ScoreTable(candidate string) string {
+       var buf bytes.Buffer
+
+       var line1, line2, separator bytes.Buffer
+       line1.WriteString("\t")
+       line2.WriteString("\t")
+       for j := 0; j < len(m.pattern); j++ {
+               line1.WriteString(fmt.Sprintf("%c\t\t", m.pattern[j]))
+               separator.WriteString("----------------")
+       }
+
+       buf.WriteString(line1.String())
+       buf.WriteString("\n")
+       buf.WriteString(separator.String())
+       buf.WriteString("\n")
+
+       for i := 1; i <= len(candidate); i++ {
+               line1.Reset()
+               line2.Reset()
+
+               line1.WriteString(fmt.Sprintf("%c\t", candidate[i-1]))
+               line2.WriteString("\t")
+
+               for j := 1; j <= len(m.pattern); j++ {
+                       line1.WriteString(fmt.Sprintf("M%6d(%c)\t", m.scores[i][j][0].val(), dir(m.scores[i][j][0].prevK())))
+                       line2.WriteString(fmt.Sprintf("H%6d(%c)\t", m.scores[i][j][1].val(), dir(m.scores[i][j][1].prevK())))
+               }
+               buf.WriteString(line1.String())
+               buf.WriteString("\n")
+               buf.WriteString(line2.String())
+               buf.WriteString("\n")
+               buf.WriteString(separator.String())
+               buf.WriteString("\n")
+       }
+
+       return buf.String()
+}
+
+func dir(prevK int) rune {
+       if prevK == 0 {
+               return 'M'
+       }
+       return 'H'
+}
+
+func (m *Matcher) poorMatch() bool {
+       if len(m.pattern) < 2 {
+               return false
+       }
+
+       i, j := m.lastCandidateLen, len(m.pattern)
+       k := m.bestK(i, j)
+
+       var counter, len int
+       for i > 0 {
+               take := (k == 1)
+               k = m.scores[i][j][k].prevK()
+               if take {
+                       len++
+                       if k == 0 && len < 3 && m.roles[i-1] == RTail {
+                               // Short match in the middle of a word
+                               counter++
+                               if counter > 1 {
+                                       return true
+                               }
+                       }
+                       j--
+               } else {
+                       len = 0
+               }
+               i--
+       }
+       return false
+}
index c0c008e038d17a42d35dfc01bde64b1744419b39..c8273654003924c8037d073ff626f8d088153c75 100644 (file)
@@ -45,7 +45,7 @@ golang.org/x/mod/zip
 golang.org/x/sys/internal/unsafeheader
 golang.org/x/sys/unix
 golang.org/x/sys/windows
-# golang.org/x/tools v0.0.0-20200616133436-c1934b75d054
+# golang.org/x/tools v0.0.0-20200901153117-6e59e24738da
 ## explicit
 golang.org/x/tools/go/analysis
 golang.org/x/tools/go/analysis/internal/analysisflags
@@ -84,6 +84,7 @@ golang.org/x/tools/go/cfg
 golang.org/x/tools/go/types/objectpath
 golang.org/x/tools/go/types/typeutil
 golang.org/x/tools/internal/analysisinternal
+golang.org/x/tools/internal/lsp/fuzzy
 # golang.org/x/xerrors v0.0.0-20200806184451-1a77d5e9f316
 ## explicit
 golang.org/x/xerrors