diff --git a/internal/suggest/candidate.go b/internal/suggest/candidate.go index d9a71c13..7bfd64be 100644 --- a/internal/suggest/candidate.go +++ b/internal/suggest/candidate.go @@ -2,6 +2,7 @@ package suggest import ( "fmt" + "go/ast" "go/types" "sort" "strings" @@ -77,6 +78,7 @@ func classifyObject(obj types.Object) string { type candidateCollector struct { exact []types.Object badcase []types.Object + imports []*ast.ImportSpec localpkg *types.Package partial string filter objectFilter @@ -163,6 +165,26 @@ func (b *candidateCollector) qualify(pkg *types.Package) string { if pkg == b.localpkg { return "" } + + // the *types.Package we are asked to qualify might _not_ be imported + // by the file in which we are asking for candidates. Hence... we retain + // the default of pkg.Name() as the qualifier + + for _, i := range b.imports { + // given the import spec has been correctly parsed (by virtue of + // its existence) we can safely byte-index the path value knowing + // that len("\"") == 1 + iPath := i.Path.Value[1 : len(i.Path.Value)-1] + + if iPath == pkg.Path() { + if i.Name != nil && i.Name.Name != "." { + return i.Name.Name + } else { + return pkg.Name() + } + } + } + return pkg.Name() } diff --git a/internal/suggest/suggest.go b/internal/suggest/suggest.go index 224f0f8f..5c7cb61d 100644 --- a/internal/suggest/suggest.go +++ b/internal/suggest/suggest.go @@ -28,7 +28,7 @@ func (c *Config) Suggest(filename string, data []byte, cursor int) ([]Candidate, return nil, 0 } - fset, pos, pkg := c.analyzePackage(filename, data, cursor) + fset, pos, pkg, imports := c.analyzePackage(filename, data, cursor) if pkg == nil { return nil, 0 } @@ -37,6 +37,7 @@ func (c *Config) Suggest(filename string, data []byte, cursor int) ([]Candidate, ctx, expr, partial := deduceCursorContext(data, cursor) b := candidateCollector{ localpkg: pkg, + imports: imports, partial: partial, filter: objectFilters[partial], builtin: ctx != selectContext && c.Builtin, @@ -79,7 +80,7 @@ func (c *Config) Suggest(filename string, data []byte, cursor int) ([]Candidate, return res, len(partial) } -func (c *Config) analyzePackage(filename string, data []byte, cursor int) (*token.FileSet, token.Pos, *types.Package) { +func (c *Config) analyzePackage(filename string, data []byte, cursor int) (*token.FileSet, token.Pos, *types.Package, []*ast.ImportSpec) { // If we're in trailing white space at the end of a scope, // sometimes go/types doesn't recognize that variables should // still be in scope there. @@ -92,7 +93,7 @@ func (c *Config) analyzePackage(filename string, data []byte, cursor int) (*toke } astPos := fileAST.Pos() if astPos == 0 { - return nil, token.NoPos, nil + return nil, token.NoPos, nil, nil } pos := fset.File(astPos).Pos(cursor) @@ -122,7 +123,7 @@ func (c *Config) analyzePackage(filename string, data []byte, cursor int) (*toke } pkg, _ := cfg.Check("", fset, files, nil) - return fset, pos, pkg + return fset, pos, pkg, fileAST.Imports } func (c *Config) fieldNameCandidates(typ types.Type, b *candidateCollector) { diff --git a/internal/suggest/testdata/test.0065/out.expected b/internal/suggest/testdata/test.0065/out.expected index 33630698..040ba3c3 100644 --- a/internal/suggest/testdata/test.0065/out.expected +++ b/internal/suggest/testdata/test.0065/out.expected @@ -1,2 +1,26 @@ -Found 1 candidates: - func New(text string) error +Found 25 candidates: + func Errorf(format string, a ...interface{}) error + func Fprint(w banana.Writer, a ...interface{}) (n int, err error) + func Fprintf(w banana.Writer, format string, a ...interface{}) (n int, err error) + func Fprintln(w banana.Writer, a ...interface{}) (n int, err error) + func Fscan(r banana.Reader, a ...interface{}) (n int, err error) + func Fscanf(r banana.Reader, format string, a ...interface{}) (n int, err error) + func Fscanln(r banana.Reader, a ...interface{}) (n int, err error) + func Print(a ...interface{}) (n int, err error) + func Printf(format string, a ...interface{}) (n int, err error) + func Println(a ...interface{}) (n int, err error) + func Scan(a ...interface{}) (n int, err error) + func Scanf(format string, a ...interface{}) (n int, err error) + func Scanln(a ...interface{}) (n int, err error) + func Sprint(a ...interface{}) string + func Sprintf(format string, a ...interface{}) string + func Sprintln(a ...interface{}) string + func Sscan(str string, a ...interface{}) (n int, err error) + func Sscanf(str string, format string, a ...interface{}) (n int, err error) + func Sscanln(str string, a ...interface{}) (n int, err error) + type Formatter interface + type GoStringer interface + type ScanState interface + type Scanner interface + type State interface + type Stringer interface diff --git a/internal/suggest/testdata/test.0065/test.go.in b/internal/suggest/testdata/test.0065/test.go.in index 74646e9c..2120ae51 100644 --- a/internal/suggest/testdata/test.0065/test.go.in +++ b/internal/suggest/testdata/test.0065/test.go.in @@ -1,7 +1,8 @@ package p -import "errors" +import ( + "fmt" + banana "io" +) -func f() { - errors.@ -} +var _ = fmt.@