From 0a51a03f35a3fa9edbfa790698aa615f4dd49783 Mon Sep 17 00:00:00 2001 From: Liang Ding Date: Tue, 13 Mar 2018 13:05:45 +0800 Subject: [PATCH] :heavy_plus_sign: Update gocode in vendor --- vendor/github.com/b3log/wide/Dockerfile | 13 +- vendor/github.com/b3log/wide/coverage.sh | 2 +- vendor/github.com/nsf/gocode/README.md | 18 +- .../nsf/gocode/autocompletecontext.go | 207 ++++++++++++++---- .../github.com/nsf/gocode/autocompletefile.go | 6 +- vendor/github.com/nsf/gocode/client.go | 6 + vendor/github.com/nsf/gocode/config.go | 65 +++++- vendor/github.com/nsf/gocode/cursorcontext.go | 67 ++++-- vendor/github.com/nsf/gocode/decl.go | 150 +++++++++---- vendor/github.com/nsf/gocode/declcache.go | 30 ++- vendor/github.com/nsf/gocode/formatters.go | 18 +- vendor/github.com/nsf/gocode/gocode.go | 8 +- vendor/github.com/nsf/gocode/package.go | 40 ++-- vendor/github.com/nsf/gocode/package_bin.go | 153 +++++++++---- vendor/github.com/nsf/gocode/package_text.go | 2 +- vendor/github.com/nsf/gocode/pre_go17.go | 2 +- vendor/github.com/nsf/gocode/rpc.go | 24 ++ vendor/github.com/nsf/gocode/scope.go | 11 + vendor/github.com/nsf/gocode/server.go | 24 +- .../nsf/gocode/type_alias_build_hack_18.go | 18 ++ .../nsf/gocode/type_alias_build_hack_19.go | 19 ++ vendor/github.com/nsf/gocode/utils.go | 17 +- vendor/vendor.json | 12 +- 23 files changed, 691 insertions(+), 221 deletions(-) create mode 100644 vendor/github.com/nsf/gocode/type_alias_build_hack_18.go create mode 100644 vendor/github.com/nsf/gocode/type_alias_build_hack_19.go diff --git a/vendor/github.com/b3log/wide/Dockerfile b/vendor/github.com/b3log/wide/Dockerfile index d11ce97..217bb46 100644 --- a/vendor/github.com/b3log/wide/Dockerfile +++ b/vendor/github.com/b3log/wide/Dockerfile @@ -1,20 +1,13 @@ FROM golang:latest MAINTAINER Liang Ding -ENV GOROOT /usr/local/go - -RUN apt-get update && apt-get install bzip2 zip unzip && cp -r /usr/local/go /usr/local/gobt -ENV GOROOT_BOOTSTRAP=/usr/local/gobt - -ADD . /wide/gogogo/src/github.com/b3log/wide -ADD vendor/* /go/src/ +ADD . /go/src/github.com/b3log/wide +ADD vendor/ /go/src/ RUN go install github.com/visualfc/gotools github.com/nsf/gocode github.com/bradfitz/goimports RUN useradd wide && useradd runner -ENV GOPATH /wide/gogogo - -WORKDIR /wide/gogogo/src/github.com/b3log/wide +WORKDIR /go/src/github.com/b3log/wide RUN go build -v EXPOSE 7070 diff --git a/vendor/github.com/b3log/wide/coverage.sh b/vendor/github.com/b3log/wide/coverage.sh index 378fe42..ec12a36 100644 --- a/vendor/github.com/b3log/wide/coverage.sh +++ b/vendor/github.com/b3log/wide/coverage.sh @@ -8,7 +8,7 @@ set -e echo "mode: count" > profile.cov # Standard go tooling behavior is to ignore dirs with leading underscors -for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -type d); +for dir in $(find . -maxdepth 10 -not -path './.git*' -not -path '*/_*' -not -path './vendor*' -type d); do if ls $dir/*.go &> /dev/null; then go test -covermode=count -coverprofile=$dir/profile.tmp $dir diff --git a/vendor/github.com/nsf/gocode/README.md b/vendor/github.com/nsf/gocode/README.md index 11148c8..0e676e6 100644 --- a/vendor/github.com/nsf/gocode/README.md +++ b/vendor/github.com/nsf/gocode/README.md @@ -151,7 +151,7 @@ You can change all available options using `gocode set` command. The config file - *propose-builtins* - A boolean option. If **true**, gocode will add built-in types, functions and constants to an autocompletion proposals. Default: **false**. + A boolean option. If **true**, gocode will add built-in types, functions and constants to autocompletion proposals. Default: **false**. - *lib-path* @@ -173,6 +173,22 @@ You can change all available options using `gocode set` command. The config file An integer option. If there have been no completion requests after this number of seconds, the gocode process will terminate. Defaults to 1800 (30 minutes). + - *unimported-packages* + + A boolean option. If set to true, gocode will try to import certain known packages automatically for identifiers which cannot be resolved otherwise. Currently only a limited set of standard library packages are supported. Default: **false**. + + - *partials* + + A boolean option. If set to false, gocode will not filter autocompletion results based on entered prefix before the cursor. Instead it will return all available autocompletion results viable for a given context. Whether this option is set to true or false, gocode will return a valid prefix length for output formats which support it. Setting this option to a non-default value may result in editor misbehaviour. Default: **true**. + + - *ignore-case* + + A boolean option. If set to true, gocode will perform case-insensitive matching when doing prefix-based filtering. Default: **false**. + + - *class-filtering* + + A boolean option. Enables or disables gocode's feature where it performs class-based filtering if partial input matches corresponding class keyword: const, var, type, func, package. Default: **true**. + ### Debugging If something went wrong, the first thing you may want to do is manually start the gocode daemon with a debug mode enabled and in a separate terminal window. It will show you all the stack traces, panics if any and additional info about autocompletion requests. Shutdown the daemon if it was already started and run a new one explicitly with a debug mode enabled: diff --git a/vendor/github.com/nsf/gocode/autocompletecontext.go b/vendor/github.com/nsf/gocode/autocompletecontext.go index 473cbd3..d5d4bc4 100644 --- a/vendor/github.com/nsf/gocode/autocompletecontext.go +++ b/vendor/github.com/nsf/gocode/autocompletecontext.go @@ -6,6 +6,7 @@ import ( "go/ast" "go/parser" "go/token" + "log" "os" "path/filepath" "runtime" @@ -22,17 +23,19 @@ import ( // fields must be exported for RPC type candidate struct { - Name string - Type string - Class decl_class + Name string + Type string + Class decl_class + Package string } type out_buffers struct { - tmpbuf *bytes.Buffer - candidates []candidate - ctx *auto_complete_context - tmpns map[string]bool - ignorecase bool + tmpbuf *bytes.Buffer + candidates []candidate + canonical_aliases map[string]string + ctx *auto_complete_context + tmpns map[string]bool + ignorecase bool } func new_out_buffers(ctx *auto_complete_context) *out_buffers { @@ -40,6 +43,10 @@ func new_out_buffers(ctx *auto_complete_context) *out_buffers { b.tmpbuf = bytes.NewBuffer(make([]byte, 0, 1024)) b.candidates = make([]candidate, 0, 64) b.ctx = ctx + b.canonical_aliases = make(map[string]string) + for _, imp := range b.ctx.current.packages { + b.canonical_aliases[imp.abspath] = imp.alias + } return b } @@ -60,7 +67,7 @@ func (b *out_buffers) Swap(i, j int) { b.candidates[i], b.candidates[j] = b.candidates[j], b.candidates[i] } -func (b *out_buffers) append_decl(p, name string, decl *decl, class decl_class) { +func (b *out_buffers) append_decl(p, name, pkg string, decl *decl, class decl_class) { c1 := !g_config.ProposeBuiltins && decl.scope == g_universe_scope && decl.name != "Error" c2 := class != decl_invalid && decl.class != class c3 := class == decl_invalid && !has_prefix(name, p, b.ignorecase) @@ -71,16 +78,17 @@ func (b *out_buffers) append_decl(p, name string, decl *decl, class decl_class) return } - decl.pretty_print_type(b.tmpbuf) + decl.pretty_print_type(b.tmpbuf, b.canonical_aliases) b.candidates = append(b.candidates, candidate{ - Name: name, - Type: b.tmpbuf.String(), - Class: decl.class, + Name: name, + Type: b.tmpbuf.String(), + Class: decl.class, + Package: pkg, }) b.tmpbuf.Reset() } -func (b *out_buffers) append_embedded(p string, decl *decl, class decl_class) { +func (b *out_buffers) append_embedded(p string, decl *decl, pkg string, class decl_class) { if decl.embedded == nil { return } @@ -103,21 +111,26 @@ func (b *out_buffers) append_embedded(p string, decl *decl, class decl_class) { continue } + // could be type alias + if typedecl.is_alias() { + typedecl = typedecl.type_dealias() + } + // prevent infinite recursion here - if typedecl.flags&decl_visited != 0 { + if typedecl.is_visited() { continue } - typedecl.flags |= decl_visited + typedecl.set_visited() defer typedecl.clear_visited() for _, c := range typedecl.children { if _, has := b.tmpns[c.name]; has { continue } - b.append_decl(p, c.name, c, class) + b.append_decl(p, c.name, pkg, c, class) b.tmpns[c.name] = true } - b.append_embedded(p, typedecl, class) + b.append_embedded(p, typedecl, pkg, class) } if first_level { @@ -183,6 +196,12 @@ func (c *auto_complete_context) merge_decls() { merge_decls(f.filescope, c.pkg, f.decls) merge_decls_from_packages(c.pkg, f.packages, c.pcache) } + + // special pass for type aliases which also have methods, while this is + // valid code, it shouldn't happen a lot in practice, so, whatever + // let's move all type alias methods to their first non-alias type down in + // the chain + propagate_type_alias_methods(c.pkg) } func (c *auto_complete_context) make_decl_set(scope *scope) map[string]*decl { @@ -197,11 +216,47 @@ func (c *auto_complete_context) get_candidates_from_set(set map[string]*decl, pa continue } value.infer_type() - b.append_decl(partial, key, value, class) + pkgname := "" + if pkg, ok := c.pcache[value.name]; ok { + pkgname = pkg.import_name + } + b.append_decl(partial, key, pkgname, value, class) } } +func (c *auto_complete_context) get_candidates_from_decl_alias(cc cursor_context, class decl_class, b *out_buffers) { + if cc.decl.is_visited() { + return + } + + cc.decl = cc.decl.type_dealias() + if cc.decl == nil { + return + } + + cc.decl.set_visited() + defer cc.decl.clear_visited() + + c.get_candidates_from_decl(cc, class, b) + return +} + +func (c *auto_complete_context) decl_package_import_path(decl *decl) string { + if decl == nil || decl.scope == nil { + return "" + } + if pkg, ok := c.pcache[decl.scope.pkgname]; ok { + return pkg.import_name + } + return "" +} + func (c *auto_complete_context) get_candidates_from_decl(cc cursor_context, class decl_class, b *out_buffers) { + if cc.decl.is_alias() { + c.get_candidates_from_decl_alias(cc, class, b) + return + } + // propose all children of a subject declaration and for _, decl := range cc.decl.children { if cc.decl.class == decl_package && !ast.IsExported(decl.name) { @@ -213,34 +268,34 @@ func (c *auto_complete_context) get_candidates_from_decl(cc cursor_context, clas continue } } - b.append_decl(cc.partial, decl.name, decl, class) + b.append_decl(cc.partial, decl.name, c.decl_package_import_path(decl), decl, class) } // propose all children of an underlying struct/interface type adecl := advance_to_struct_or_interface(cc.decl) if adecl != nil && adecl != cc.decl { for _, decl := range adecl.children { if decl.class == decl_var { - b.append_decl(cc.partial, decl.name, decl, class) + b.append_decl(cc.partial, decl.name, c.decl_package_import_path(decl), decl, class) } } } // propose all children of its embedded types - b.append_embedded(cc.partial, cc.decl, class) + b.append_embedded(cc.partial, cc.decl, c.decl_package_import_path(cc.decl), class) } func (c *auto_complete_context) get_import_candidates(partial string, b *out_buffers) { - pkgdirs := g_daemon.context.pkg_dirs() + currentPackagePath, pkgdirs := g_daemon.context.pkg_dirs() resultSet := map[string]struct{}{} for _, pkgdir := range pkgdirs { // convert srcpath to pkgpath and get candidates - get_import_candidates_dir(pkgdir, filepath.FromSlash(partial), b.ignorecase, resultSet) + get_import_candidates_dir(pkgdir, filepath.FromSlash(partial), b.ignorecase, currentPackagePath, resultSet) } for k := range resultSet { b.candidates = append(b.candidates, candidate{Name: k, Class: decl_import}) } } -func get_import_candidates_dir(root, partial string, ignorecase bool, r map[string]struct{}) { +func get_import_candidates_dir(root, partial string, ignorecase bool, currentPackagePath string, r map[string]struct{}) { var fpath string var match bool if strings.HasSuffix(partial, "/") { @@ -259,7 +314,7 @@ func get_import_candidates_dir(root, partial string, ignorecase bool, r map[stri if match && !has_prefix(rel, partial, ignorecase) { continue } else if fi[i].IsDir() { - get_import_candidates_dir(root, rel+string(filepath.Separator), ignorecase, r) + get_import_candidates_dir(root, rel+string(filepath.Separator), ignorecase, currentPackagePath, r) } else { ext := filepath.Ext(name) if ext != ".a" { @@ -267,7 +322,9 @@ func get_import_candidates_dir(root, partial string, ignorecase bool, r map[stri } else { rel = rel[0 : len(rel)-2] } - r[vendorlessImportPath(filepath.ToSlash(rel))] = struct{}{} + if ipath, ok := vendorlessImportPath(filepath.ToSlash(rel), currentPackagePath); ok { + r[ipath] = struct{}{} + } } } } @@ -305,13 +362,29 @@ func (c *auto_complete_context) apropos(file []byte, filename string, cursor int // And we're ready to Go. ;) b := new_out_buffers(c) + if g_config.IgnoreCase { + if *g_debug { + log.Printf("ignoring case sensitivity") + } + b.ignorecase = true + } - partial := 0 cc, ok := c.deduce_cursor_context(file, cursor) + partial := len(cc.partial) + if !g_config.Partials { + if *g_debug { + log.Printf("not performing partial prefix matching") + } + cc.partial = "" + } if !ok { var d *decl if ident, ok := cc.expr.(*ast.Ident); ok && g_config.UnimportedPackages { - d = resolveKnownPackageIdent(ident.Name, c.current.name, c.current.context) + p := resolveKnownPackageIdent(ident.Name, c.current.name, c.current.context) + if p != nil { + c.pcache[p.name] = p + d = p.main + } } if d == nil { return nil, 0 @@ -320,17 +393,19 @@ func (c *auto_complete_context) apropos(file []byte, filename string, cursor int } class := decl_invalid - switch cc.partial { - case "const": - class = decl_const - case "var": - class = decl_var - case "type": - class = decl_type - case "func": - class = decl_func - case "package": - class = decl_package + if g_config.ClassFiltering { + switch cc.partial { + case "const": + class = decl_const + case "var": + class = decl_var + case "type": + class = decl_type + case "func": + class = decl_func + case "package": + class = decl_package + } } if cc.decl_import { @@ -357,7 +432,6 @@ func (c *auto_complete_context) apropos(file []byte, filename string, cursor int c.get_candidates_from_decl(cc, class, b) } } - partial = len(cc.partial) if len(b.candidates) == 0 { return nil, 0 @@ -391,6 +465,52 @@ func update_packages(ps map[string]*package_file_cache) { } } +func collect_type_alias_methods(d *decl) map[string]*decl { + if d == nil || d.is_visited() || !d.is_alias() { + return nil + } + d.set_visited() + defer d.clear_visited() + + // add own methods + m := map[string]*decl{} + for k, v := range d.children { + m[k] = v + } + + // recurse into more aliases + dd := type_to_decl(d.typ, d.scope) + for k, v := range collect_type_alias_methods(dd) { + m[k] = v + } + + return m +} + +func propagate_type_alias_methods(s *scope) { + for _, e := range s.entities { + if !e.is_alias() { + continue + } + + methods := collect_type_alias_methods(e) + if len(methods) == 0 { + continue + } + + dd := e.type_dealias() + if dd == nil { + continue + } + + decl := dd.deep_copy() + for _, v := range methods { + decl.add_child(v) + } + s.entities[decl.name] = decl + } +} + func merge_decls(filescope *scope, pkg *scope, decls map[string]*decl) { for _, d := range decls { pkg.merge_decl(d) @@ -400,7 +520,7 @@ func merge_decls(filescope *scope, pkg *scope, decls map[string]*decl) { func merge_decls_from_packages(pkgscope *scope, pkgs []package_import, pcache package_cache) { for _, p := range pkgs { - path, alias := p.path, p.alias + path, alias := p.abspath, p.alias if alias != "." { continue } @@ -418,7 +538,7 @@ func merge_decls_from_packages(pkgscope *scope, pkgs []package_import, pcache pa func fixup_packages(filescope *scope, pkgs []package_import, pcache package_cache) { for _, p := range pkgs { - path, alias := p.path, p.alias + path, alias := p.abspath, p.alias if alias == "" { alias = pcache[path].defalias } @@ -555,7 +675,6 @@ func check_type_expr(e ast.Expr) bool { default: return true } - return true } //------------------------------------------------------------------------- diff --git a/vendor/github.com/nsf/gocode/autocompletefile.go b/vendor/github.com/nsf/gocode/autocompletefile.go index ca6d2ca..c68f7ca 100644 --- a/vendor/github.com/nsf/gocode/autocompletefile.go +++ b/vendor/github.com/nsf/gocode/autocompletefile.go @@ -141,7 +141,7 @@ func (f *auto_complete_file) process_decl(decl ast.Decl) { for i, name := range data.names { typ, v, vi := data.type_value_index(i) - d := new_decl_full(name.Name, class, 0, typ, v, vi, prevscope) + d := new_decl_full(name.Name, class, ast_decl_flags(data.decl), typ, v, vi, prevscope) if d == nil { return } @@ -243,7 +243,9 @@ func (f *auto_complete_file) process_select_stmt(a *ast.SelectStmt) { if astmt, ok := last_cursor_after.Comm.(*ast.AssignStmt); ok && astmt.Tok == token.DEFINE { vname := astmt.Lhs[0].(*ast.Ident).Name v := new_decl_var(vname, nil, astmt.Rhs[0], -1, prevscope) - f.scope.add_named_decl(v) + if v != nil { + f.scope.add_named_decl(v) + } } } for _, s := range last_cursor_after.Body { diff --git a/vendor/github.com/nsf/gocode/client.go b/vendor/github.com/nsf/gocode/client.go index b16f82c..3174a2d 100644 --- a/vendor/github.com/nsf/gocode/client.go +++ b/vendor/github.com/nsf/gocode/client.go @@ -50,6 +50,8 @@ func do_client() int { cmd_drop_cache(client) case "set": cmd_set(client) + case "options": + cmd_options(client) default: fmt.Printf("unknown argument: %q, try running \"gocode -h\"\n", flag.Arg(0)) return 1 @@ -180,3 +182,7 @@ func cmd_set(c *rpc.Client) { fmt.Print(client_set(c, flag.Arg(1), flag.Arg(2))) } } + +func cmd_options(c *rpc.Client) { + fmt.Print(client_options(c, 0)) +} diff --git a/vendor/github.com/nsf/gocode/config.go b/vendor/github.com/nsf/gocode/config.go index 01b198f..075c5c0 100644 --- a/vendor/github.com/nsf/gocode/config.go +++ b/vendor/github.com/nsf/gocode/config.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "os" "reflect" + "regexp" "strconv" ) @@ -28,9 +29,27 @@ type config struct { PackageLookupMode string `json:"package-lookup-mode"` CloseTimeout int `json:"close-timeout"` UnimportedPackages bool `json:"unimported-packages"` + Partials bool `json:"partials"` + IgnoreCase bool `json:"ignore-case"` + ClassFiltering bool `json:"class-filtering"` } -var g_config = config{ +var g_config_desc = map[string]string{ + "propose-builtins": "If set to {true}, gocode will add built-in types, functions and constants to autocompletion proposals.", + "lib-path": "A string option. Allows you to add search paths for packages. By default, gocode only searches {$GOPATH/pkg/$GOOS_$GOARCH} and {$GOROOT/pkg/$GOOS_$GOARCH} in terms of previously existed environment variables. Also you can specify multiple paths using ':' (colon) as a separator (on Windows use semicolon ';'). The paths specified by {lib-path} are prepended to the default ones.", + "custom-pkg-prefix": "", + "custom-vendor-dir": "", + "autobuild": "If set to {true}, gocode will try to automatically build out-of-date packages when their source files are modified, in order to obtain the freshest autocomplete results for them. This feature is experimental.", + "force-debug-output": "If is not empty, gocode will forcefully redirect the logging into that file. Also forces enabling of the debug mode on the server side.", + "package-lookup-mode": "If set to {go}, use standard Go package lookup rules. If set to {gb}, use gb-specific lookup rules. See {https://github.com/constabulary/gb} for details.", + "close-timeout": "If there have been no completion requests after this number of seconds, the gocode process will terminate. Default is 30 minutes.", + "unimported-packages": "If set to {true}, gocode will try to import certain known packages automatically for identifiers which cannot be resolved otherwise. Currently only a limited set of standard library packages is supported.", + "partials": "If set to {false}, gocode will not filter autocompletion results based on entered prefix before the cursor. Instead it will return all available autocompletion results viable for a given context. Whether this option is set to {true} or {false}, gocode will return a valid prefix length for output formats which support it. Setting this option to a non-default value may result in editor misbehaviour.", + "ignore-case": "If set to {true}, gocode will perform case-insensitive matching when doing prefix-based filtering.", + "class-filtering": "Enables or disables gocode's feature where it performs class-based filtering if partial input matches corresponding class keyword: const, var, type, func, package.", +} + +var g_default_config = config{ ProposeBuiltins: false, LibPath: "", CustomPkgPrefix: "", @@ -39,7 +58,11 @@ var g_config = config{ PackageLookupMode: "go", CloseTimeout: 1800, UnimportedPackages: false, + Partials: true, + IgnoreCase: false, + ClassFiltering: true, } +var g_config = g_default_config var g_string_to_bool = map[string]bool{ "t": true, @@ -175,3 +198,43 @@ func (this *config) read() error { return nil } + +func quoted(v interface{}) string { + switch v.(type) { + case string: + return fmt.Sprintf("%q", v) + case int: + return fmt.Sprint(v) + case bool: + return fmt.Sprint(v) + default: + panic("unreachable") + } +} + +var descRE = regexp.MustCompile(`{[^}]+}`) + +func preprocess_desc(v string) string { + return descRE.ReplaceAllStringFunc(v, func(v string) string { + return color_cyan + v[1:len(v)-1] + color_none + }) +} + +func (this *config) options() string { + var buf bytes.Buffer + fmt.Fprintf(&buf, "%sConfig file location%s: %s\n", color_white_bold, color_none, config_file()) + dv := reflect.ValueOf(g_default_config) + v, t := this.value_and_type() + for i, n := 0, t.NumField(); i < n; i++ { + f := t.Field(i) + index := f.Index + tag := f.Tag.Get("json") + fmt.Fprintf(&buf, "\n%s%s%s\n", color_yellow_bold, tag, color_none) + fmt.Fprintf(&buf, "%stype%s: %s\n", color_yellow, color_none, f.Type) + fmt.Fprintf(&buf, "%svalue%s: %s\n", color_yellow, color_none, quoted(v.FieldByIndex(index).Interface())) + fmt.Fprintf(&buf, "%sdefault%s: %s\n", color_yellow, color_none, quoted(dv.FieldByIndex(index).Interface())) + fmt.Fprintf(&buf, "%sdescription%s: %s\n", color_yellow, color_none, preprocess_desc(g_config_desc[tag])) + } + + return buf.String() +} diff --git a/vendor/github.com/nsf/gocode/cursorcontext.go b/vendor/github.com/nsf/gocode/cursorcontext.go index ae8fb38..92c036b 100644 --- a/vendor/github.com/nsf/gocode/cursorcontext.go +++ b/vendor/github.com/nsf/gocode/cursorcontext.go @@ -35,10 +35,8 @@ type token_item struct { func (i token_item) literal() string { if i.tok.IsLiteral() { return i.lit - } else { - return i.tok.String() } - return "" + return i.tok.String() } func new_token_iterator(src []byte, cursor int) token_iterator { @@ -116,6 +114,28 @@ func (this *token_iterator) skip_to_left_curly() bool { return this.skip_to_left(token.LBRACE, token.RBRACE) } +func (ti *token_iterator) extract_type_alike() string { + if ti.token().tok != token.IDENT { // not Foo, return nothing + return "" + } + b := ti.token().literal() + if !ti.go_back() { // just Foo + return b + } + if ti.token().tok != token.PERIOD { // not .Foo, return Foo + return b + } + if !ti.go_back() { // just .Foo, return Foo (best choice recovery) + return b + } + if ti.token().tok != token.IDENT { // not lib.Foo, return Foo + return b + } + out := ti.token().literal() + "." + b // lib.Foo + ti.go_back() + return out +} + // Extract the type expression right before the enclosing curly bracket block. // Examples (# - the cursor): // &lib.Struct{Whatever: 1, Hel#} // returns "lib.Struct" @@ -130,23 +150,21 @@ func (ti *token_iterator) extract_struct_type() string { if !ti.go_back() { return "" } - if ti.token().tok != token.IDENT { + if ti.token().tok == token.LBRACE { // Foo{#{}} + if !ti.go_back() { + return "" + } + } else if ti.token().tok == token.COMMA { // Foo{abc,#{}} + return ti.extract_struct_type() + } + typ := ti.extract_type_alike() + if typ == "" { return "" } - b := ti.token().literal() - if !ti.go_back() { - return b + if ti.token().tok == token.RPAREN || ti.token().tok == token.MUL { + return "" } - if ti.token().tok != token.PERIOD { - return b - } - if !ti.go_back() { - return b - } - if ti.token().tok != token.IDENT { - return b - } - return ti.token().literal() + "." + b + return typ } // Starting from the token under the cursor move back and extract something @@ -266,7 +284,14 @@ func (c *auto_complete_context) deduce_struct_type_decl(iter *token_iterator) *d if decl == nil { return nil } - if _, ok := decl.typ.(*ast.StructType); !ok { + + // we allow only struct types here, but also support type aliases + if decl.is_alias() { + dd := decl.type_dealias() + if _, ok := dd.typ.(*ast.StructType); !ok { + return nil + } + } else if _, ok := decl.typ.(*ast.StructType); !ok { return nil } return decl @@ -395,7 +420,7 @@ func (c *auto_complete_context) deduce_cursor_context(file []byte, cursor int) ( // package name has nothing to do with package file name, that's why we need to // scan the packages. And many of them will have conflicts. Can we make a smart // prediction algorithm which will prefer certain packages over another ones? -func resolveKnownPackageIdent(ident string, filename string, context *package_lookup_context) *decl { +func resolveKnownPackageIdent(ident string, filename string, context *package_lookup_context) *package_file_cache { importPath, ok := knownPackageIdents[ident] if !ok { return nil @@ -406,9 +431,9 @@ func resolveKnownPackageIdent(ident string, filename string, context *package_lo return nil } - p := new_package_file_cache(path) + p := new_package_file_cache(path, importPath) p.update_cache() - return p.main + return p } var knownPackageIdents = map[string]string{ diff --git a/vendor/github.com/nsf/gocode/decl.go b/vendor/github.com/nsf/gocode/decl.go index a19a601..7709c5f 100644 --- a/vendor/github.com/nsf/gocode/decl.go +++ b/vendor/github.com/nsf/gocode/decl.go @@ -56,12 +56,15 @@ func (this decl_class) String() string { type decl_flags int16 const ( - decl_foreign = decl_flags(1 << iota) // imported from another package + decl_foreign decl_flags = 1 << iota // imported from another package // means that the decl is a part of the range statement // its type is inferred in a special way decl_rangevar + // decl of decl_type class is a type alias + decl_alias + // for preventing infinite recursions and loops in type inference code decl_visited ) @@ -115,7 +118,19 @@ func ast_decl_type(d ast.Decl) ast.Expr { return t.Type } panic("unreachable") - return nil +} + +func ast_decl_flags(d ast.Decl) decl_flags { + switch t := d.(type) { + case *ast.GenDecl: + switch t.Tok { + case token.TYPE: + if isAliasTypeSpec(t.Specs[0].(*ast.TypeSpec)) { + return decl_alias + } + } + } + return 0 } func ast_decl_class(d ast.Decl) decl_class { @@ -324,7 +339,7 @@ func new_decl_var(name string, typ ast.Expr, value ast.Expr, vindex int, scope * func method_of(d ast.Decl) string { if t, ok := d.(*ast.FuncDecl); ok { - if t.Recv != nil { + if t.Recv != nil && len(t.Recv.List) != 0 { switch t := t.Recv.List[0].Type.(type) { case *ast.StarExpr: if se, ok := t.X.(*ast.SelectorExpr); ok { @@ -348,6 +363,7 @@ func (other *decl) deep_copy() *decl { d := new(decl) d.name = other.name d.class = other.class + d.flags = other.flags d.typ = other.typ d.value = other.value d.value_index = other.value_index @@ -363,20 +379,36 @@ func (other *decl) deep_copy() *decl { return d } +func (d *decl) is_rangevar() bool { + return d.flags&decl_rangevar != 0 +} + +func (d *decl) is_alias() bool { + return d.flags&decl_alias != 0 +} + +func (d *decl) is_visited() bool { + return d.flags&decl_visited != 0 +} + +func (d *decl) set_visited() { + d.flags |= decl_visited +} + func (d *decl) clear_visited() { d.flags &^= decl_visited } func (d *decl) expand_or_replace(other *decl) { - // expand only if it's a methods stub, otherwise simply copy + // expand only if it's a methods stub, otherwise simply keep it as is if d.class != decl_methods_stub && other.class != decl_methods_stub { - d = other return } if d.class == decl_methods_stub { d.typ = other.typ d.class = other.class + d.flags = other.flags } if other.children != nil { @@ -398,7 +430,7 @@ func (d *decl) matches() bool { return true } -func (d *decl) pretty_print_type(out io.Writer) { +func (d *decl) pretty_print_type(out io.Writer, canonical_aliases map[string]string) { switch d.class { case decl_type: switch d.typ.(type) { @@ -410,15 +442,15 @@ func (d *decl) pretty_print_type(out io.Writer) { fmt.Fprintf(out, "interface") default: if d.typ != nil { - pretty_print_type_expr(out, d.typ) + pretty_print_type_expr(out, d.typ, canonical_aliases) } } case decl_var: if d.typ != nil { - pretty_print_type_expr(out, d.typ) + pretty_print_type_expr(out, d.typ, canonical_aliases) } case decl_func: - pretty_print_type_expr(out, d.typ) + pretty_print_type_expr(out, d.typ, canonical_aliases) } } @@ -481,17 +513,14 @@ func func_return_type(f *ast.FuncType, index int) ast.Expr { i := 0 var field *ast.Field for _, field = range f.Results.List { - if i >= index { + n := 1 + if field.Names != nil { + n = len(field.Names) + } + if i <= index && index < i+n { return field.Type } - if field.Names != nil { - i += len(field.Names) - } else { - i++ - } - } - if i >= index { - return field.Type + i += n } return nil } @@ -599,20 +628,20 @@ func advance_to_type(pred type_predicate, v ast.Expr, scope *scope) (ast.Expr, * return nil, nil } - if decl.flags&decl_visited != 0 { + if decl.is_visited() { return nil, nil } - decl.flags |= decl_visited + decl.set_visited() defer decl.clear_visited() return advance_to_type(pred, decl.typ, decl.scope) } func advance_to_struct_or_interface(decl *decl) *decl { - if decl.flags&decl_visited != 0 { + if decl.is_visited() { return nil } - decl.flags |= decl_visited + decl.set_visited() defer decl.clear_visited() if struct_interface_predicate(decl.typ) { @@ -917,7 +946,7 @@ func infer_type(v ast.Expr, scope *scope, index int) (ast.Expr, *scope, bool) { // makes sense. func (d *decl) infer_type() (ast.Expr, *scope) { // special case for range vars - if d.flags&decl_rangevar != 0 { + if d.is_rangevar() { var scope *scope d.typ, scope = infer_range_type(d.value, d.scope, d.value_index) return d.typ, scope @@ -937,10 +966,10 @@ func (d *decl) infer_type() (ast.Expr, *scope) { } // prevent loops - if d.flags&decl_visited != 0 { + if d.is_visited() { return nil, nil } - d.flags |= decl_visited + d.set_visited() defer d.clear_visited() var scope *scope @@ -948,13 +977,34 @@ func (d *decl) infer_type() (ast.Expr, *scope) { return d.typ, scope } -func (d *decl) find_child(name string) *decl { - if d.flags&decl_visited != 0 { +func (d *decl) type_dealias() *decl { + if d.is_visited() { return nil } - d.flags |= decl_visited + d.set_visited() defer d.clear_visited() + dd := type_to_decl(d.typ, d.scope) + if dd != nil && dd.is_alias() { + return dd.type_dealias() + } + return dd +} + +func (d *decl) find_child(name string) *decl { + // type aliases don't really have any children on their own, but they + // point to a different type, let's try to find one + if d.is_alias() { + dd := d.type_dealias() + if dd != nil { + return dd.find_child(name) + } + + // note that type alias can also point to a type literal, something like + // type A = struct { A int } + // in this case we rely on "advance_to_struct_or_interface" below + } + if d.children != nil { if c, ok := d.children[name]; ok { return c @@ -963,6 +1013,12 @@ func (d *decl) find_child(name string) *decl { decl := advance_to_struct_or_interface(d) if decl != nil && decl != d { + if d.is_visited() { + return nil + } + d.set_visited() + defer d.clear_visited() + return decl.find_child(name) } return nil @@ -1053,11 +1109,11 @@ func get_array_len(e ast.Expr) string { return "" } -func pretty_print_type_expr(out io.Writer, e ast.Expr) { +func pretty_print_type_expr(out io.Writer, e ast.Expr, canonical_aliases map[string]string) { switch t := e.(type) { case *ast.StarExpr: fmt.Fprintf(out, "*") - pretty_print_type_expr(out, t.X) + pretty_print_type_expr(out, t.X, canonical_aliases) case *ast.Ident: if strings.HasPrefix(t.Name, "$") { // beautify anonymous types @@ -1070,15 +1126,19 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) { // it's always true fmt.Fprintf(out, "interface{}") } - } else if !*g_debug && strings.HasPrefix(t.Name, "#") { - fmt.Fprintf(out, t.Name[1:]) } else if !*g_debug && strings.HasPrefix(t.Name, "!") { // these are full package names for disambiguating and pretty - // printing packages withing packages, e.g. + // printing packages within packages, e.g. // !go/ast!ast vs. !github.com/nsf/my/ast!ast // another ugly hack, if people are punished in hell for ugly hacks // I'm screwed... - fmt.Fprintf(out, t.Name[strings.LastIndex(t.Name, "!")+1:]) + emarkIdx := strings.LastIndex(t.Name, "!") + path := t.Name[1:emarkIdx] + alias := canonical_aliases[path] + if alias == "" { + alias = t.Name[emarkIdx+1:] + } + fmt.Fprintf(out, alias) } else { fmt.Fprintf(out, t.Name) } @@ -1092,17 +1152,17 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) { } else { fmt.Fprintf(out, "[]") } - pretty_print_type_expr(out, t.Elt) + pretty_print_type_expr(out, t.Elt, canonical_aliases) case *ast.SelectorExpr: - pretty_print_type_expr(out, t.X) + pretty_print_type_expr(out, t.X, canonical_aliases) fmt.Fprintf(out, ".%s", t.Sel.Name) case *ast.FuncType: fmt.Fprintf(out, "func(") - pretty_print_func_field_list(out, t.Params) + pretty_print_func_field_list(out, t.Params, canonical_aliases) fmt.Fprintf(out, ")") buf := bytes.NewBuffer(make([]byte, 0, 256)) - nresults := pretty_print_func_field_list(buf, t.Results) + nresults := pretty_print_func_field_list(buf, t.Results, canonical_aliases) if nresults > 0 { results := buf.String() if strings.IndexAny(results, ", ") != -1 { @@ -1112,14 +1172,14 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) { } case *ast.MapType: fmt.Fprintf(out, "map[") - pretty_print_type_expr(out, t.Key) + pretty_print_type_expr(out, t.Key, canonical_aliases) fmt.Fprintf(out, "]") - pretty_print_type_expr(out, t.Value) + pretty_print_type_expr(out, t.Value, canonical_aliases) case *ast.InterfaceType: fmt.Fprintf(out, "interface{}") case *ast.Ellipsis: fmt.Fprintf(out, "...") - pretty_print_type_expr(out, t.Elt) + pretty_print_type_expr(out, t.Elt, canonical_aliases) case *ast.StructType: fmt.Fprintf(out, "struct") case *ast.ChanType: @@ -1131,10 +1191,10 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) { case ast.SEND | ast.RECV: fmt.Fprintf(out, "chan ") } - pretty_print_type_expr(out, t.Value) + pretty_print_type_expr(out, t.Value, canonical_aliases) case *ast.ParenExpr: fmt.Fprintf(out, "(") - pretty_print_type_expr(out, t.X) + pretty_print_type_expr(out, t.X, canonical_aliases) fmt.Fprintf(out, ")") case *ast.BadExpr: // TODO: probably I should check that in a separate function @@ -1145,7 +1205,7 @@ func pretty_print_type_expr(out io.Writer, e ast.Expr) { } } -func pretty_print_func_field_list(out io.Writer, f *ast.FieldList) int { +func pretty_print_func_field_list(out io.Writer, f *ast.FieldList, canonical_aliases map[string]string) int { count := 0 if f == nil { return count @@ -1172,7 +1232,7 @@ func pretty_print_func_field_list(out io.Writer, f *ast.FieldList) int { } // type - pretty_print_type_expr(out, field.Type) + pretty_print_type_expr(out, field.Type, canonical_aliases) // , if i != len(f.List)-1 { diff --git a/vendor/github.com/nsf/gocode/declcache.go b/vendor/github.com/nsf/gocode/declcache.go index 6eb9313..215a5a8 100644 --- a/vendor/github.com/nsf/gocode/declcache.go +++ b/vendor/github.com/nsf/gocode/declcache.go @@ -19,8 +19,9 @@ import ( //------------------------------------------------------------------------- type package_import struct { - alias string - path string + alias string + abspath string + path string } // Parses import declarations until the first non-import declaration and fills @@ -32,9 +33,9 @@ func collect_package_imports(filename string, decls []ast.Decl, context *package for _, spec := range gd.Specs { imp := spec.(*ast.ImportSpec) path, alias := path_and_alias(imp) - path, ok := abs_path_for_package(filename, path, context) + abspath, ok := abs_path_for_package(filename, path, context) if ok && alias != "_" { - pi = append(pi, package_import{alias, path}) + pi = append(pi, package_import{alias, abspath, path}) } } } else { @@ -121,7 +122,7 @@ func append_to_top_decls(decls map[string]*decl, decl ast.Decl, scope *scope) { for i, name := range data.names { typ, v, vi := data.type_value_index(i) - d := new_decl_full(name.Name, class, 0, typ, v, vi, scope) + d := new_decl_full(name.Name, class, ast_decl_flags(data.decl), typ, v, vi, scope) if d == nil { return } @@ -314,7 +315,11 @@ func find_global_file(imp string, context *package_lookup_context) (string, bool // gb-specific lookup mode, only if the root dir was found if g_config.PackageLookupMode == "gb" && context.GBProjectRoot != "" { root := context.GBProjectRoot - pkg_path := filepath.Join(root, "pkg", context.GOOS+"-"+context.GOARCH, pkgfile) + pkgdir := filepath.Join(root, "pkg", context.GOOS+"-"+context.GOARCH) + if !is_dir(pkgdir) { + pkgdir = filepath.Join(root, "pkg", context.GOOS+"-"+context.GOARCH+"-race") + } + pkg_path := filepath.Join(pkgdir, pkgfile) if file_exists(pkg_path) { log_found_package_maybe(imp, pkg_path) return pkg_path, true @@ -453,9 +458,10 @@ func (ctxt *package_lookup_context) gopath() []string { return all } -func (ctxt *package_lookup_context) pkg_dirs() []string { +func (ctxt *package_lookup_context) pkg_dirs() (string, []string) { pkgdir := fmt.Sprintf("%s_%s", ctxt.GOOS, ctxt.GOARCH) + var currentPackagePath string var all []string if ctxt.GOROOT != "" { dir := filepath.Join(ctxt.GOROOT, "pkg", pkgdir) @@ -466,15 +472,23 @@ func (ctxt *package_lookup_context) pkg_dirs() []string { switch g_config.PackageLookupMode { case "go": + currentPackagePath = ctxt.CurrentPackagePath for _, p := range ctxt.gopath() { dir := filepath.Join(p, "pkg", pkgdir) if is_dir(dir) { all = append(all, dir) } + dir = filepath.Join(dir, currentPackagePath, "vendor") + if is_dir(dir) { + all = append(all, dir) + } } case "gb": if ctxt.GBProjectRoot != "" { pkgdir := fmt.Sprintf("%s-%s", ctxt.GOOS, ctxt.GOARCH) + if !is_dir(pkgdir) { + pkgdir = fmt.Sprintf("%s-%s-race", ctxt.GOOS, ctxt.GOARCH) + } dir := filepath.Join(ctxt.GBProjectRoot, "pkg", pkgdir) if is_dir(dir) { all = append(all, dir) @@ -483,7 +497,7 @@ func (ctxt *package_lookup_context) pkg_dirs() []string { case "bzl": // TODO: Support bazel mode } - return all + return currentPackagePath, all } type decl_cache struct { diff --git a/vendor/github.com/nsf/gocode/formatters.go b/vendor/github.com/nsf/gocode/formatters.go index b0ec264..4a9738c 100644 --- a/vendor/github.com/nsf/gocode/formatters.go +++ b/vendor/github.com/nsf/gocode/formatters.go @@ -128,6 +128,18 @@ func (*csv_formatter) write_candidates(candidates []candidate, num int) { } } +//------------------------------------------------------------------------- +// csv_with_package_formatter +//------------------------------------------------------------------------- + +type csv_with_package_formatter struct{} + +func (*csv_with_package_formatter) write_candidates(candidates []candidate, num int) { + for _, c := range candidates { + fmt.Printf("%s,,%s,,%s,,%s\n", c.Class, c.Name, c.Type, c.Package) + } +} + //------------------------------------------------------------------------- // json_formatter //------------------------------------------------------------------------- @@ -145,8 +157,8 @@ func (*json_formatter) write_candidates(candidates []candidate, num int) { if i != 0 { fmt.Printf(", ") } - fmt.Printf(`{"class": "%s", "name": "%s", "type": "%s"}`, - c.Class, c.Name, c.Type) + fmt.Printf(`{"class": "%s", "name": "%s", "type": "%s", "package": "%s"}`, + c.Class, c.Name, c.Type, c.Package) } fmt.Print("]]") } @@ -163,6 +175,8 @@ func get_formatter(name string) formatter { return new(nice_formatter) case "csv": return new(csv_formatter) + case "csv-with-package": + return new(csv_with_package_formatter) case "json": return new(json_formatter) case "godit": diff --git a/vendor/github.com/nsf/gocode/gocode.go b/vendor/github.com/nsf/gocode/gocode.go index 650e346..b0dd5a2 100644 --- a/vendor/github.com/nsf/gocode/gocode.go +++ b/vendor/github.com/nsf/gocode/gocode.go @@ -12,7 +12,7 @@ import ( var ( g_is_server = flag.Bool("s", false, "run a server instead of a client") - g_format = flag.String("f", "nice", "output format (vim | emacs | nice | csv | json)") + g_format = flag.String("f", "nice", "output format (vim | emacs | nice | csv | csv-with-package | json)") g_input = flag.String("in", "", "use this file instead of stdin input") g_sock = create_sock_flag("sock", "socket type (unix | tcp)") g_addr = flag.String("addr", "127.0.0.1:37373", "address for tcp socket") @@ -40,9 +40,11 @@ func show_usage() { "\nCommands:\n"+ " autocomplete [] main autocompletion command\n"+ " close close the gocode daemon\n"+ - " status gocode daemon status report\n"+ " drop-cache drop gocode daemon's cache\n"+ - " set [ []] list or set config options\n") + " options list config options (extended)\n"+ + " set [ []] list or set config options\n"+ + " status gocode daemon status report\n"+ + "") } func main() { diff --git a/vendor/github.com/nsf/gocode/package.go b/vendor/github.com/nsf/gocode/package.go index ab57aad..687cb80 100644 --- a/vendor/github.com/nsf/gocode/package.go +++ b/vendor/github.com/nsf/gocode/package.go @@ -20,18 +20,20 @@ type package_parser interface { //------------------------------------------------------------------------- type package_file_cache struct { - name string // file name - mtime int64 - defalias string + name string // file name + import_name string + mtime int64 + defalias string scope *scope main *decl // package declaration others map[string]*decl } -func new_package_file_cache(name string) *package_file_cache { +func new_package_file_cache(absname, name string) *package_file_cache { m := new(package_file_cache) - m.name = name + m.name = absname + m.import_name = name m.mtime = 0 m.defalias = "" return m @@ -92,7 +94,7 @@ func (m *package_file_cache) update_cache() { } func (m *package_file_cache) process_package_data(data []byte) { - m.scope = new_scope(g_universe_scope) + m.scope = new_named_scope(g_universe_scope, m.name) // find import section i := bytes.Index(data, []byte{'\n', '$', '$'}) @@ -126,9 +128,10 @@ func (m *package_file_cache) process_package_data(data []byte) { pp = &p } + prefix := "!" + m.name + "!" pp.parse_export(func(pkg string, decl ast.Decl) { anonymify_ast(decl, decl_foreign, m.scope) - if pkg == "" || strings.HasPrefix(pkg, "#") { + if pkg == "" || strings.HasPrefix(pkg, prefix) { // main package add_ast_decl_to_package(m.main, decl, m.scope) } else { @@ -141,12 +144,12 @@ func (m *package_file_cache) process_package_data(data []byte) { }) // hack, add ourselves to the package scope - mainName := "#" + m.defalias + mainName := "!" + m.name + "!" + m.defalias m.add_package_to_scope(mainName, m.name) // replace dummy package decls in package scope to actual packages for key := range m.scope.entities { - if !strings.HasPrefix(key, "#") && !strings.HasPrefix(key, "!") { + if !strings.HasPrefix(key, "!") { continue } pkg, ok := m.others[key] @@ -168,7 +171,7 @@ func add_ast_decl_to_package(pkg *decl, decl ast.Decl, scope *scope) { for i, name := range data.names { typ, v, vi := data.type_value_index(i) - d := new_decl_full(name.Name, class, decl_foreign, typ, v, vi, scope) + d := new_decl_full(name.Name, class, decl_foreign|ast_decl_flags(data.decl), typ, v, vi, scope) if d == nil { return } @@ -218,16 +221,16 @@ func new_package_cache() package_cache { // In case if package is not in the cache, it creates one and adds one to the cache. func (c package_cache) append_packages(ps map[string]*package_file_cache, pkgs []package_import) { for _, m := range pkgs { - if _, ok := ps[m.path]; ok { + if _, ok := ps[m.abspath]; ok { continue } - if mod, ok := c[m.path]; ok { - ps[m.path] = mod + if mod, ok := c[m.abspath]; ok { + ps[m.abspath] = mod } else { - mod = new_package_file_cache(m.path) - ps[m.path] = mod - c[m.path] = mod + mod = new_package_file_cache(m.abspath, m.path) + ps[m.abspath] = mod + c[m.abspath] = mod } } } @@ -240,11 +243,6 @@ package unsafe func @"".Offsetof (? any) uintptr func @"".Sizeof (? any) uintptr func @"".Alignof (? any) uintptr - func @"".Typeof (i interface { }) interface { } - func @"".Reflect (i interface { }) (typ interface { }, addr @"".Pointer) - func @"".Unreflect (typ interface { }, addr @"".Pointer) interface { } - func @"".New (typ interface { }) @"".Pointer - func @"".NewArray (typ interface { }, n int) @"".Pointer $$ `) diff --git a/vendor/github.com/nsf/gocode/package_bin.go b/vendor/github.com/nsf/gocode/package_bin.go index e93d5d2..4a51c74 100644 --- a/vendor/github.com/nsf/gocode/package_bin.go +++ b/vendor/github.com/nsf/gocode/package_bin.go @@ -49,10 +49,11 @@ import ( type gc_bin_parser struct { data []byte buf []byte // for reading strings - version int + version int // export format version // object lists strList []string // in order of appearance + pathList []string // in order of appearance pkgList []string // in order of appearance typList []ast.Expr // in order of appearance callback func(pkg string, decl ast.Decl) @@ -72,8 +73,9 @@ type gc_bin_parser struct { func (p *gc_bin_parser) init(data []byte, pfc *package_file_cache) { p.data = data - p.version = -1 // unknown version - p.strList = []string{""} // empty string is mapped to 0 + p.version = -1 // unknown version + p.strList = []string{""} // empty string is mapped to 0 + p.pathList = []string{""} // empty string is mapped to 0 p.pfc = pfc } @@ -111,17 +113,10 @@ func (p *gc_bin_parser) parse_export(callback func(string, ast.Decl)) { // read version specific flags - extend as necessary switch p.version { - // case 4: + // case 6: // ... // fallthrough - case 3, 2, 1: - // Support for Go 1.8 type aliases will be added very - // soon (Oct 2016). In the meantime, we make a - // best-effort attempt to read v3 export data, failing - // if we encounter a type alias. This allows the - // automated builders to make progress since - // type aliases are not yet used in practice. - // TODO(gri): add support for type aliases. + case 5, 4, 3, 2, 1: p.debugFormat = p.rawStringln(p.rawByte()) == "debug" p.trackAllTypes = p.int() != 0 p.posInfoFormat = p.int() != 0 @@ -137,7 +132,8 @@ func (p *gc_bin_parser) parse_export(callback func(string, ast.Decl)) { p.typList = append(p.typList, predeclared...) // read package data - p.pfc.defalias = p.pkg()[1:] + pkgName := p.pkg() + p.pfc.defalias = pkgName[strings.LastIndex(pkgName, "!")+1:] // read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go) objcount := 0 @@ -165,12 +161,17 @@ func (p *gc_bin_parser) pkg() string { // otherwise, i is the package tag (< 0) if i != packageTag { - panic(fmt.Sprintf("unexpected package tag %d", i)) + panic(fmt.Sprintf("unexpected package tag %d version %d", i, p.version)) } // read package data name := p.string() - path := p.string() + var path string + if p.version >= 5 { + path = p.path() + } else { + path = p.string() + } // we should never see an empty package name if name == "" { @@ -188,7 +189,7 @@ func (p *gc_bin_parser) pkg() string { fullName = "!" + path + "!" + name p.pfc.add_package_to_scope(fullName, path) } else { - fullName = "#" + name + fullName = "!" + p.pfc.name + "!" + name } // if the package was imported before, use that one; otherwise create a new one @@ -213,6 +214,17 @@ func (p *gc_bin_parser) obj(tag int) { }, }, }) + + case aliasTag: + // TODO(gri) verify type alias hookup is correct + p.pos() + pkg, name := p.qualifiedName() + typ := p.typ("") + p.callback(pkg, &ast.GenDecl{ + Tok: token.TYPE, + Specs: []ast.Spec{typeAliasSpec(name, typ)}, + }) + case typeTag: _ = p.typ("") @@ -229,6 +241,7 @@ func (p *gc_bin_parser) obj(tag int) { }, }, }) + case funcTag: p.pos() pkg, name := p.qualifiedName() @@ -244,6 +257,8 @@ func (p *gc_bin_parser) obj(tag int) { } } +const deltaNewFile = -64 // see cmd/compile/internal/gc/bexport.go + func (p *gc_bin_parser) pos() { if !p.posInfoFormat { return @@ -251,15 +266,26 @@ func (p *gc_bin_parser) pos() { file := p.prevFile line := p.prevLine - if delta := p.int(); delta != 0 { - // line changed - line += delta - } else if n := p.int(); n >= 0 { - // file changed - file = p.prevFile[:n] + p.string() - p.prevFile = file - line = p.int() + delta := p.int() + line += delta + if p.version >= 5 { + if delta == deltaNewFile { + if n := p.int(); n >= 0 { + // file changed + file = p.path() + line = n + } + } + } else { + if delta == 0 { + if n := p.int(); n >= 0 { + // file changed + file = p.prevFile[:n] + p.string() + line = p.int() + } + } } + p.prevFile = file p.prevLine = line // TODO(gri) register new position @@ -391,10 +417,17 @@ func (p *gc_bin_parser) typ(parent string) ast.Expr { case interfaceTag: i := p.reserveMaybe() - if p.int() != 0 { - panic("unexpected embedded interface") + var embeddeds []*ast.SelectorExpr + for n := p.int(); n > 0; n-- { + p.pos() + if named, ok := p.typ(parent).(*ast.SelectorExpr); ok { + embeddeds = append(embeddeds, named) + } } methods := p.methodList(parent) + for _, field := range embeddeds { + methods = append(methods, &ast.Field{Type: field}) + } return p.recordMaybe(i, &ast.InterfaceType{Methods: &ast.FieldList{List: methods}}) case mapTag: @@ -429,17 +462,17 @@ func (p *gc_bin_parser) structType(parent string) *ast.StructType { if n := p.int(); n > 0 { fields = make([]*ast.Field, n) for i := range fields { - fields[i] = p.field(parent) - p.string() // tag, not interested in tags + fields[i], _ = p.field(parent) // (*ast.Field, tag), not interested in tags } } return &ast.StructType{Fields: &ast.FieldList{List: fields}} } -func (p *gc_bin_parser) field(parent string) *ast.Field { +func (p *gc_bin_parser) field(parent string) (*ast.Field, string) { p.pos() - _, name := p.fieldName(parent) + _, name, _ := p.fieldName(parent) typ := p.typ(parent) + tag := p.string() var names []*ast.Ident if name != "" { @@ -448,7 +481,7 @@ func (p *gc_bin_parser) field(parent string) *ast.Field { return &ast.Field{ Names: names, Type: typ, - } + }, tag } func (p *gc_bin_parser) methodList(parent string) (methods []*ast.Field) { @@ -463,7 +496,7 @@ func (p *gc_bin_parser) methodList(parent string) (methods []*ast.Field) { func (p *gc_bin_parser) method(parent string) *ast.Field { p.pos() - _, name := p.fieldName(parent) + _, name, _ := p.fieldName(parent) params := p.paramList() results := p.paramList() return &ast.Field{ @@ -472,22 +505,32 @@ func (p *gc_bin_parser) method(parent string) *ast.Field { } } -func (p *gc_bin_parser) fieldName(parent string) (string, string) { +func (p *gc_bin_parser) fieldName(parent string) (string, string, bool) { name := p.string() pkg := parent if p.version == 0 && name == "_" { - // versions < 1 don't export a package for _ fields - // TODO: remove once versions are not supported anymore - return pkg, name + // version 0 didn't export a package for _ fields + return pkg, name, false } - if name != "" && !exported(name) { - // explicitly qualified field - if name == "?" { - name = "" - } + var alias bool + switch name { + case "": + // 1) field name matches base type name and is exported: nothing to do + case "?": + // 2) field name matches base type name and is not exported: need package + name = "" pkg = p.pkg() + case "@": + // 3) field name doesn't match type name (alias) + name = p.string() + alias = true + fallthrough + default: + if !exported(name) { + pkg = p.pkg() + } } - return pkg, name + return pkg, name, alias } func (p *gc_bin_parser) paramList() *ast.FieldList { @@ -594,6 +637,26 @@ func (p *gc_bin_parser) int64() int64 { return p.rawInt64() } +func (p *gc_bin_parser) path() string { + if p.debugFormat { + p.marker('p') + } + // if the path was seen before, i is its index (>= 0) + // (the empty string is at index 0) + i := p.rawInt64() + if i >= 0 { + return p.pathList[i] + } + // otherwise, i is the negative path length (< 0) + a := make([]string, -i) + for n := range a { + a[n] = p.string() + } + s := strings.Join(a, "/") + p.pathList = append(p.pathList, s) + return s +} + func (p *gc_bin_parser) string() string { if p.debugFormat { p.marker('s') @@ -710,7 +773,11 @@ const ( fractionTag // not used by gc complexTag stringTag + nilTag // only used by gc (appears in exported inlined function bodies) unknownTag // not used by gc (only appears in packages with errors) + + // Type aliases + aliasTag ) var predeclared = []ast.Expr{ @@ -733,7 +800,7 @@ var predeclared = []ast.Expr{ ast.NewIdent("complex128"), ast.NewIdent("string"), - // aliases + // basic type aliases ast.NewIdent("byte"), ast.NewIdent("rune"), diff --git a/vendor/github.com/nsf/gocode/package_text.go b/vendor/github.com/nsf/gocode/package_text.go index 9ed7451..c714bb1 100644 --- a/vendor/github.com/nsf/gocode/package_text.go +++ b/vendor/github.com/nsf/gocode/package_text.go @@ -172,7 +172,7 @@ func (p *gc_parser) parse_exported_name() *ast.SelectorExpr { p.expect('@') pkg := p.parse_package() if pkg.Name == "" { - pkg.Name = "#" + p.pfc.defalias + pkg.Name = "!" + p.pfc.name + "!" + p.pfc.defalias } else { pkg.Name = p.path_to_name[pkg.Name] } diff --git a/vendor/github.com/nsf/gocode/pre_go17.go b/vendor/github.com/nsf/gocode/pre_go17.go index 202ef5a..6fca344 100644 --- a/vendor/github.com/nsf/gocode/pre_go17.go +++ b/vendor/github.com/nsf/gocode/pre_go17.go @@ -1,4 +1,4 @@ -// +build !go1.7 +// +build !go1.7,!go1.8 package main diff --git a/vendor/github.com/nsf/gocode/rpc.go b/vendor/github.com/nsf/gocode/rpc.go index 9955f4d..b1e0ea7 100644 --- a/vendor/github.com/nsf/gocode/rpc.go +++ b/vendor/github.com/nsf/gocode/rpc.go @@ -136,3 +136,27 @@ func client_set(cli *rpc.Client, Arg0, Arg1 string) string { } return reply.Arg0 } + +// wrapper for: server_options + +type Args_options struct { + Arg0 int +} +type Reply_options struct { + Arg0 string +} + +func (r *RPC) RPC_options(args *Args_options, reply *Reply_options) error { + reply.Arg0 = server_options(args.Arg0) + return nil +} +func client_options(cli *rpc.Client, Arg0 int) string { + var args Args_options + var reply Reply_options + args.Arg0 = Arg0 + err := cli.Call("RPC.RPC_options", &args, &reply) + if err != nil { + panic(err) + } + return reply.Arg0 +} diff --git a/vendor/github.com/nsf/gocode/scope.go b/vendor/github.com/nsf/gocode/scope.go index 34afb89..802e296 100644 --- a/vendor/github.com/nsf/gocode/scope.go +++ b/vendor/github.com/nsf/gocode/scope.go @@ -5,12 +5,23 @@ package main //------------------------------------------------------------------------- type scope struct { + // the package name that this scope resides in + pkgname string parent *scope // nil for universe scope entities map[string]*decl } +func new_named_scope(outer *scope, name string) *scope { + s := new_scope(outer) + s.pkgname = name + return s +} + func new_scope(outer *scope) *scope { s := new(scope) + if outer != nil { + s.pkgname = outer.pkgname + } s.parent = outer s.entities = make(map[string]*decl) return s diff --git a/vendor/github.com/nsf/gocode/server.go b/vendor/github.com/nsf/gocode/server.go index 15e7d01..82813df 100644 --- a/vendor/github.com/nsf/gocode/server.go +++ b/vendor/github.com/nsf/gocode/server.go @@ -137,7 +137,7 @@ func server_auto_complete(file []byte, filename string, cursor int, context_pack if err := recover(); err != nil { print_backtrace(err) c = []candidate{ - {"PANIC", "PANIC", decl_invalid}, + {"PANIC", "PANIC", decl_invalid, "panic"}, } // drop cache @@ -186,12 +186,18 @@ func server_auto_complete(file []byte, filename string, cursor int, context_pack var buf bytes.Buffer log.Printf("Got autocompletion request for '%s'\n", filename) log.Printf("Cursor at: %d\n", cursor) - buf.WriteString("-------------------------------------------------------\n") - buf.Write(file[:cursor]) - buf.WriteString("#") - buf.Write(file[cursor:]) - log.Print(buf.String()) - log.Println("-------------------------------------------------------") + if cursor > len(file) || cursor < 0 { + log.Println("ERROR! Cursor is outside of the boundaries of the buffer, " + + "this is most likely a text editor plugin bug. Text editor is responsible " + + "for passing the correct cursor position to gocode.") + } else { + buf.WriteString("-------------------------------------------------------\n") + buf.Write(file[:cursor]) + buf.WriteString("#") + buf.Write(file[cursor:]) + log.Print(buf.String()) + log.Println("-------------------------------------------------------") + } } candidates, d := g_daemon.autocomplete.apropos(file, filename, cursor) if *g_debug { @@ -235,3 +241,7 @@ func server_set(key, value string) string { g_daemon.drop_cache() return g_config.set_option(key, value) } + +func server_options(notused int) string { + return g_config.options() +} diff --git a/vendor/github.com/nsf/gocode/type_alias_build_hack_18.go b/vendor/github.com/nsf/gocode/type_alias_build_hack_18.go new file mode 100644 index 0000000..cb7d1f1 --- /dev/null +++ b/vendor/github.com/nsf/gocode/type_alias_build_hack_18.go @@ -0,0 +1,18 @@ +// +build !go1.9,!go1.8.typealias + +package main + +import ( + "go/ast" +) + +func typeAliasSpec(name string, typ ast.Expr) *ast.TypeSpec { + return &ast.TypeSpec{ + Name: ast.NewIdent(name), + Type: typ, + } +} + +func isAliasTypeSpec(t *ast.TypeSpec) bool { + return false +} diff --git a/vendor/github.com/nsf/gocode/type_alias_build_hack_19.go b/vendor/github.com/nsf/gocode/type_alias_build_hack_19.go new file mode 100644 index 0000000..b2b074f --- /dev/null +++ b/vendor/github.com/nsf/gocode/type_alias_build_hack_19.go @@ -0,0 +1,19 @@ +// +build go1.9 go1.8.typealias + +package main + +import ( + "go/ast" +) + +func typeAliasSpec(name string, typ ast.Expr) *ast.TypeSpec { + return &ast.TypeSpec{ + Name: ast.NewIdent(name), + Assign: 1, + Type: typ, + } +} + +func isAliasTypeSpec(t *ast.TypeSpec) bool { + return t.Assign != 0 +} diff --git a/vendor/github.com/nsf/gocode/utils.go b/vendor/github.com/nsf/gocode/utils.go index ece34dd..8b153c5 100644 --- a/vendor/github.com/nsf/gocode/utils.go +++ b/vendor/github.com/nsf/gocode/utils.go @@ -153,15 +153,24 @@ func find_gb_project_root(path string) (string, error) { // vendorlessImportPath returns the devendorized version of the provided import path. // e.g. "foo/bar/vendor/a/b" => "a/b" -func vendorlessImportPath(ipath string) string { +func vendorlessImportPath(ipath string, currentPackagePath string) (string, bool) { + split := strings.Split(ipath, "vendor/") + // no vendor in path + if len(split) == 1 { + return ipath, true + } + // this import path does not belong to the current package + if currentPackagePath != "" && !strings.Contains(currentPackagePath, split[0]) { + return "", false + } // Devendorize for use in import statement. if i := strings.LastIndex(ipath, "/vendor/"); i >= 0 { - return ipath[i+len("/vendor/"):] + return ipath[i+len("/vendor/"):], true } if strings.HasPrefix(ipath, "vendor/") { - return ipath[len("vendor/"):] + return ipath[len("vendor/"):], true } - return ipath + return ipath, true } //------------------------------------------------------------------------- diff --git a/vendor/vendor.json b/vendor/vendor.json index e4e069b..07d1218 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -3,10 +3,10 @@ "ignore": "test", "package": [ { - "checksumSHA1": "7NpGLW+EOhRLs5cDvi1S+LqUNQ8=", + "checksumSHA1": "ZesPb1w0u5/uv/fdVc+G6wOee30=", "path": "github.com/b3log/wide", - "revision": "f96c8befdf3484ad4d3abdf7a11c7a3d6182d018", - "revisionTime": "2018-03-13T04:09:30Z" + "revision": "bfd836c6fc8fbc007ce437db1406455493cd532f", + "revisionTime": "2018-03-13T04:57:02Z" }, { "checksumSHA1": "83iEp3SqOoIkZUYyR7BOVP4vaGE=", @@ -45,10 +45,10 @@ "revisionTime": "2015-05-30T03:03:52Z" }, { - "checksumSHA1": "5i+5zScV0FNuG3cmRzRPn6PFsfo=", + "checksumSHA1": "gKm38IQHqLfYHwS7B6JDTJzXYYI=", "path": "github.com/nsf/gocode", - "revision": "5070dacabf2a80deeaf4ddb0be3761d06fce7be5", - "revisionTime": "2016-11-22T21:38:51Z" + "revision": "416643789f088aa5077f667cecde7f966131f6be", + "revisionTime": "2018-01-07T08:36:41Z" }, { "checksumSHA1": "4fp/TH5nX7seO5p4qJfIj/BokbI=",