Update gocode in vendor

This commit is contained in:
Liang Ding 2018-03-13 13:05:45 +08:00
parent bfd836c6fc
commit 0a51a03f35
23 changed files with 691 additions and 221 deletions

View File

@ -1,20 +1,13 @@
FROM golang:latest
MAINTAINER Liang Ding <d@b3log.org>
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

View File

@ -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

View File

@ -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:

View File

@ -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
}
//-------------------------------------------------------------------------

View File

@ -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 {

View File

@ -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))
}

View File

@ -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()
}

View File

@ -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{

150
vendor/github.com/nsf/gocode/decl.go generated vendored
View File

@ -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 {

View File

@ -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 {

View File

@ -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":

View File

@ -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 [<path>] <offset> 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 [<name> [<value>]] list or set config options\n")
" options list config options (extended)\n"+
" set [<name> [<value>]] list or set config options\n"+
" status gocode daemon status report\n"+
"")
}
func main() {

View File

@ -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
$$
`)

View File

@ -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"),

View File

@ -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]
}

View File

@ -1,4 +1,4 @@
// +build !go1.7
// +build !go1.7,!go1.8
package main

24
vendor/github.com/nsf/gocode/rpc.go generated vendored
View File

@ -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
}

View File

@ -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

View File

@ -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()
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
//-------------------------------------------------------------------------

12
vendor/vendor.json vendored
View File

@ -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=",