// Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package source import ( "context" "fmt" "go/ast" "go/token" "go/types" "golang.org/x/tools/go/ast/astutil" "golang.org/x/tools/internal/lsp/snippet" "golang.org/x/tools/internal/span" ) type CompletionItem struct { // Label is the primary text the user sees for this completion item. Label string // Detail is supplemental information to present to the user. // This often contains the type or return type of the completion item. Detail string // InsertText is the text to insert if this item is selected. // Any of the prefix that has already been typed is not trimmed. // The insert text does not contain snippets. InsertText string Kind CompletionItemKind // Score is the internal relevance score. // A higher score indicates that this completion item is more relevant. Score float64 // Snippet is the LSP snippet for the completion item, without placeholders. // The LSP specification contains details about LSP snippets. // For example, a snippet for a function with the following signature: // // func foo(a, b, c int) // // would be: // // foo(${1:}) // plainSnippet *snippet.Builder // PlaceholderSnippet is the LSP snippet for the completion ite, containing // placeholders. The LSP specification contains details about LSP snippets. // For example, a placeholder snippet for a function with the following signature: // // func foo(a, b, c int) // // would be: // // foo(${1:a int}, ${2: b int}, ${3: c int}) // placeholderSnippet *snippet.Builder } // Snippet is a convenience function that determines the snippet that should be // used for an item, depending on if the callee wants placeholders or not. func (i *CompletionItem) Snippet(usePlaceholders bool) string { if usePlaceholders { if i.placeholderSnippet != nil { return i.placeholderSnippet.String() } } if i.plainSnippet != nil { return i.plainSnippet.String() } return i.InsertText } type CompletionItemKind int const ( Unknown CompletionItemKind = iota InterfaceCompletionItem StructCompletionItem TypeCompletionItem ConstantCompletionItem FieldCompletionItem ParameterCompletionItem VariableCompletionItem FunctionCompletionItem MethodCompletionItem PackageCompletionItem ) // Scoring constants are used for weighting the relevance of different candidates. const ( // stdScore is the base score for all completion items. stdScore float64 = 1.0 // highScore indicates a very relevant completion item. highScore float64 = 10.0 // lowScore indicates an irrelevant or not useful completion item. lowScore float64 = 0.01 ) // completer contains the necessary information for a single completion request. type completer struct { // Package-specific fields. types *types.Package info *types.Info qf types.Qualifier // view is the View associated with this completion request. view View // ctx is the context associated with this completion request. ctx context.Context // pos is the position at which the request was triggered. pos token.Pos // path is the path of AST nodes enclosing the position. path []ast.Node // seen is the map that ensures we do not return duplicate results. seen map[types.Object]bool // items is the list of completion items returned. items []CompletionItem // surrounding describes the identifier surrounding the position. surrounding *Selection // expectedType is the type we expect the completion candidate to be. // It may not be set. expectedType types.Type // enclosingFunction is the function declaration enclosing the position. enclosingFunction *types.Signature // preferTypeNames is true if we are completing at a position that expects a type, // not a value. preferTypeNames bool // enclosingCompositeLiteral contains information about the composite literal // enclosing the position. enclosingCompositeLiteral *compLitInfo } type compLitInfo struct { // cl is the *ast.CompositeLit enclosing the position. cl *ast.CompositeLit // clType is the type of cl. clType types.Type // kv is the *ast.KeyValueExpr enclosing the position, if any. kv *ast.KeyValueExpr // inKey is true if we are certain the position is in the key side // of a key-value pair. inKey bool // maybeInFieldName is true if inKey is false and it is possible // we are completing a struct field name. For example, // "SomeStruct{<>}" will be inKey=false, but maybeInFieldName=true // because we _could_ be completing a field name. maybeInFieldName bool } // A Selection represents the cursor position and surrounding identifier. type Selection struct { Content string Range span.Range Cursor token.Pos } func (p Selection) Prefix() string { return p.Content[:p.Cursor-p.Range.Start] } func (c *completer) setSurrounding(ident *ast.Ident) { if c.surrounding != nil { return } if !(ident.Pos() <= c.pos && c.pos <= ident.End()) { return } c.surrounding = &Selection{ Content: ident.Name, Range: span.NewRange(c.view.Session().Cache().FileSet(), ident.Pos(), ident.End()), Cursor: c.pos, } } // found adds a candidate completion. // // Only the first candidate of a given name is considered. func (c *completer) found(obj types.Object, weight float64) { if obj.Pkg() != nil && obj.Pkg() != c.types && !obj.Exported() { return // inaccessible } if c.seen[obj] { return } c.seen[obj] = true if c.matchingType(obj.Type()) { weight *= highScore } if _, ok := obj.(*types.TypeName); !ok && c.preferTypeNames { weight *= lowScore } c.items = append(c.items, c.item(obj, weight)) } // Completion returns a list of possible candidates for completion, given a // a file and a position. // // The selection is computed based on the preceding identifier and can be used by // the client to score the quality of the completion. For instance, some clients // may tolerate imperfect matches as valid completion results, since users may make typos. func Completion(ctx context.Context, f GoFile, pos token.Pos) ([]CompletionItem, *Selection, error) { file := f.GetAST(ctx) if file == nil { return nil, nil, fmt.Errorf("no AST for %s", f.URI()) } pkg := f.GetPackage(ctx) if pkg == nil || pkg.IsIllTyped() { return nil, nil, fmt.Errorf("package for %s is ill typed", f.URI()) } // Completion is based on what precedes the cursor. // Find the path to the position before pos. path, _ := astutil.PathEnclosingInterval(file, pos-1, pos-1) if path == nil { return nil, nil, fmt.Errorf("cannot find node enclosing position") } // Skip completion inside comments. for _, g := range file.Comments { if g.Pos() <= pos && pos <= g.End() { return nil, nil, nil } } // Skip completion inside any kind of literal. if _, ok := path[0].(*ast.BasicLit); ok { return nil, nil, nil } clInfo := enclosingCompositeLiteral(path, pos, pkg.GetTypesInfo()) c := &completer{ types: pkg.GetTypes(), info: pkg.GetTypesInfo(), qf: qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo()), view: f.View(), ctx: ctx, path: path, pos: pos, seen: make(map[types.Object]bool), enclosingFunction: enclosingFunction(path, pos, pkg.GetTypesInfo()), preferTypeNames: preferTypeNames(path, pos), enclosingCompositeLiteral: clInfo, } // Set the filter surrounding. if ident, ok := path[0].(*ast.Ident); ok { c.setSurrounding(ident) } c.expectedType = expectedType(c) // Struct literals are handled entirely separately. if c.wantStructFieldCompletions() { if err := c.structLiteralFieldName(); err != nil { return nil, nil, err } return c.items, c.surrounding, nil } switch n := path[0].(type) { case *ast.Ident: // Is this the Sel part of a selector? if sel, ok := path[1].(*ast.SelectorExpr); ok && sel.Sel == n { if err := c.selector(sel); err != nil { return nil, nil, err } return c.items, c.surrounding, nil } // reject defining identifiers if obj, ok := pkg.GetTypesInfo().Defs[n]; ok { if v, ok := obj.(*types.Var); ok && v.IsField() { // An anonymous field is also a reference to a type. } else { of := "" if obj != nil { qual := types.RelativeTo(pkg.GetTypes()) of += ", of " + types.ObjectString(obj, qual) } return nil, nil, fmt.Errorf("this is a definition%s", of) } } if err := c.lexical(); err != nil { return nil, nil, err } // The function name hasn't been typed yet, but the parens are there: // recv.‸(arg) case *ast.TypeAssertExpr: // Create a fake selector expression. if err := c.selector(&ast.SelectorExpr{X: n.X}); err != nil { return nil, nil, err } case *ast.SelectorExpr: // The go parser inserts a phantom "_" Sel node when the selector is // not followed by an identifier or a "(". The "_" isn't actually in // the text, so don't think it is our surrounding. // TODO: Find a way to differentiate between phantom "_" and real "_", // perhaps by checking if "_" is present in file contents. if n.Sel.Name != "_" || c.pos != n.Sel.Pos() { c.setSurrounding(n.Sel) } if err := c.selector(n); err != nil { return nil, nil, err } default: // fallback to lexical completions if err := c.lexical(); err != nil { return nil, nil, err } } return c.items, c.surrounding, nil } func (c *completer) wantStructFieldCompletions() bool { clInfo := c.enclosingCompositeLiteral if clInfo == nil { return false } return clInfo.isStruct() && (clInfo.inKey || clInfo.maybeInFieldName) } // selector finds completions for the specified selector expression. func (c *completer) selector(sel *ast.SelectorExpr) error { // Is sel a qualified identifier? if id, ok := sel.X.(*ast.Ident); ok { if pkgname, ok := c.info.Uses[id].(*types.PkgName); ok { // Enumerate package members. scope := pkgname.Imported().Scope() for _, name := range scope.Names() { c.found(scope.Lookup(name), stdScore) } return nil } } // Invariant: sel is a true selector. tv, ok := c.info.Types[sel.X] if !ok { return fmt.Errorf("cannot resolve %s", sel.X) } // Add methods of T. mset := types.NewMethodSet(tv.Type) for i := 0; i < mset.Len(); i++ { c.found(mset.At(i).Obj(), stdScore) } // Add methods of *T. if tv.Addressable() && !types.IsInterface(tv.Type) && !isPointer(tv.Type) { mset := types.NewMethodSet(types.NewPointer(tv.Type)) for i := 0; i < mset.Len(); i++ { c.found(mset.At(i).Obj(), stdScore) } } // Add fields of T. for _, f := range fieldSelections(tv.Type) { c.found(f, stdScore) } return nil } // lexical finds completions in the lexical environment. func (c *completer) lexical() error { var scopes []*types.Scope // scopes[i], where i) or the completion request is triggered // from an already completed composite literal expression (e.g. &x{foo: 1, <>}) // // The position is not part of the composite literal unless it falls within the // curly braces (e.g. "foo.Foo<>Struct{}"). if !(n.Lbrace <= pos && pos <= n.Rbrace) { return nil } tv, ok := info.Types[n] if !ok { return nil } clInfo := compLitInfo{ cl: n, clType: tv.Type.Underlying(), } var ( expr ast.Expr hasKeys bool ) for _, el := range n.Elts { // Remember the expression that the position falls in, if any. if el.Pos() <= pos && pos <= el.End() { expr = el } if kv, ok := el.(*ast.KeyValueExpr); ok { hasKeys = true // If expr == el then we know the position falls in this expression, // so also record kv as the enclosing *ast.KeyValueExpr. if expr == el { clInfo.kv = kv break } } } if clInfo.kv != nil { // If in a *ast.KeyValueExpr, we know we are in the key if the position // is to the left of the colon (e.g. "Foo{F<>: V}". clInfo.inKey = pos <= clInfo.kv.Colon } else if hasKeys { // If we aren't in a *ast.KeyValueExpr but the composite literal has // other *ast.KeyValueExprs, we must be on the key side of a new // *ast.KeyValueExpr (e.g. "Foo{F: V, <>}"). clInfo.inKey = true } else { switch clInfo.clType.(type) { case *types.Struct: if len(n.Elts) == 0 { // If the struct literal is empty, next could be a struct field // name or an expression (e.g. "Foo{<>}" could become "Foo{F:}" // or "Foo{someVar}"). clInfo.maybeInFieldName = true } else if len(n.Elts) == 1 { // If there is one expression and the position is in that expression // and the expression is an identifier, we may be writing a field // name or an expression (e.g. "Foo{F<>}"). _, clInfo.maybeInFieldName = expr.(*ast.Ident) } case *types.Map: // If we aren't in a *ast.KeyValueExpr we must be adding a new key // to the map. clInfo.inKey = true } } return &clInfo default: if breaksExpectedTypeInference(n) { return nil } } } return nil } // enclosingFunction returns the signature of the function enclosing the given position. func enclosingFunction(path []ast.Node, pos token.Pos, info *types.Info) *types.Signature { for _, node := range path { switch t := node.(type) { case *ast.FuncDecl: if obj, ok := info.Defs[t.Name]; ok { return obj.Type().(*types.Signature) } case *ast.FuncLit: if typ, ok := info.Types[t]; ok { return typ.Type.(*types.Signature) } } } return nil } func (c *completer) expectedCompositeLiteralType() types.Type { clInfo := c.enclosingCompositeLiteral switch t := clInfo.clType.(type) { case *types.Slice: if clInfo.inKey { return types.Typ[types.Int] } return t.Elem() case *types.Array: if clInfo.inKey { return types.Typ[types.Int] } return t.Elem() case *types.Map: if clInfo.inKey { return t.Key() } return t.Elem() case *types.Struct: // If we are completing a key (i.e. field name), there is no expected type. if clInfo.inKey { return nil } // If we are in a key-value pair, but not in the key, then we must be on the // value side. The expected type of the value will be determined from the key. if clInfo.kv != nil { if key, ok := clInfo.kv.Key.(*ast.Ident); ok { for i := 0; i < t.NumFields(); i++ { if field := t.Field(i); field.Name() == key.Name { return field.Type() } } } } else { // If we aren't in a key-value pair and aren't in the key, we must be using // implicit field names. // The order of the literal fields must match the order in the struct definition. // Find the element that the position belongs to and suggest that field's type. if i := indexExprAtPos(c.pos, clInfo.cl.Elts); i < t.NumFields() { return t.Field(i).Type() } } } return nil } // typeModifier represents an operator that changes the expected type. type typeModifier int const ( dereference typeModifier = iota // dereference ("*") operator reference // reference ("&") operator chanRead // channel read ("<-") operator ) // expectedType returns the expected type for an expression at the query position. func expectedType(c *completer) types.Type { if c.enclosingCompositeLiteral != nil { return c.expectedCompositeLiteralType() } var ( modifiers []typeModifier typ types.Type ) Nodes: for i, node := range c.path { switch node := node.(type) { case *ast.BinaryExpr: // Determine if query position comes from left or right of op. e := node.X if c.pos < node.OpPos { e = node.Y } if tv, ok := c.info.Types[e]; ok { typ = tv.Type break Nodes } case *ast.AssignStmt: // Only rank completions if you are on the right side of the token. if c.pos > node.TokPos { i := indexExprAtPos(c.pos, node.Rhs) if i >= len(node.Lhs) { i = len(node.Lhs) - 1 } if tv, ok := c.info.Types[node.Lhs[i]]; ok { typ = tv.Type break Nodes } } return nil case *ast.CallExpr: // Only consider CallExpr args if position falls between parens. if node.Lparen <= c.pos && c.pos <= node.Rparen { if tv, ok := c.info.Types[node.Fun]; ok { if sig, ok := tv.Type.(*types.Signature); ok { if sig.Params().Len() == 0 { return nil } i := indexExprAtPos(c.pos, node.Args) // Make sure not to run past the end of expected parameters. if i >= sig.Params().Len() { i = sig.Params().Len() - 1 } typ = sig.Params().At(i).Type() break Nodes } } } return nil case *ast.ReturnStmt: if sig := c.enclosingFunction; sig != nil { // Find signature result that corresponds to our return statement. if resultIdx := indexExprAtPos(c.pos, node.Results); resultIdx < len(node.Results) { if resultIdx < sig.Results().Len() { typ = sig.Results().At(resultIdx).Type() break Nodes } } } return nil case *ast.CaseClause: if swtch, ok := findSwitchStmt(c.path[i+1:], c.pos, node).(*ast.SwitchStmt); ok { if tv, ok := c.info.Types[swtch.Tag]; ok { typ = tv.Type break Nodes } } return nil case *ast.SliceExpr: // Make sure position falls within the brackets (e.g. "foo[a:<>]"). if node.Lbrack < c.pos && c.pos <= node.Rbrack { typ = types.Typ[types.Int] break Nodes } return nil case *ast.IndexExpr: // Make sure position falls within the brackets (e.g. "foo[<>]"). if node.Lbrack < c.pos && c.pos <= node.Rbrack { if tv, ok := c.info.Types[node.X]; ok { switch t := tv.Type.Underlying().(type) { case *types.Map: typ = t.Key() case *types.Slice, *types.Array: typ = types.Typ[types.Int] default: return nil } break Nodes } } return nil case *ast.SendStmt: // Make sure we are on right side of arrow (e.g. "foo <- <>"). if c.pos > node.Arrow+1 { if tv, ok := c.info.Types[node.Chan]; ok { if ch, ok := tv.Type.Underlying().(*types.Chan); ok { typ = ch.Elem() break Nodes } } } return nil case *ast.StarExpr: modifiers = append(modifiers, dereference) case *ast.UnaryExpr: switch node.Op { case token.AND: modifiers = append(modifiers, reference) case token.ARROW: modifiers = append(modifiers, chanRead) } default: if breaksExpectedTypeInference(node) { return nil } } } if typ != nil { for _, mod := range modifiers { switch mod { case dereference: // For every "*" deref operator, add another pointer layer to expected type. typ = types.NewPointer(typ) case reference: // For every "&" ref operator, remove a pointer layer from expected type. typ = deref(typ) case chanRead: // For every "<-" operator, add another layer of channelness. typ = types.NewChan(types.SendRecv, typ) } } } return typ } // findSwitchStmt returns an *ast.CaseClause's corresponding *ast.SwitchStmt or // *ast.TypeSwitchStmt. path should start from the case clause's first ancestor. func findSwitchStmt(path []ast.Node, pos token.Pos, c *ast.CaseClause) ast.Stmt { // Make sure position falls within a "case <>:" clause. if exprAtPos(pos, c.List) == nil { return nil } // A case clause is always nested within a block statement in a switch statement. if len(path) < 2 { return nil } if _, ok := path[0].(*ast.BlockStmt); !ok { return nil } switch s := path[1].(type) { case *ast.SwitchStmt: return s case *ast.TypeSwitchStmt: return s default: return nil } } // breaksExpectedTypeInference reports if an expression node's type is unrelated // to its child expression node types. For example, "Foo{Bar: x.Baz(<>)}" should // expect a function argument, not a composite literal value. func breaksExpectedTypeInference(n ast.Node) bool { switch n.(type) { case *ast.FuncLit, *ast.CallExpr, *ast.TypeAssertExpr, *ast.IndexExpr, *ast.SliceExpr, *ast.CompositeLit: return true default: return false } } // preferTypeNames checks if given token position is inside func receiver, // type params, or type results. For example: // // func (<>) foo(<>) (<>) {} // func preferTypeNames(path []ast.Node, pos token.Pos) bool { for i, p := range path { switch n := p.(type) { case *ast.FuncDecl: if r := n.Recv; r != nil && r.Pos() <= pos && pos <= r.End() { return true } if t := n.Type; t != nil { if p := t.Params; p != nil && p.Pos() <= pos && pos <= p.End() { return true } if r := t.Results; r != nil && r.Pos() <= pos && pos <= r.End() { return true } } return false case *ast.CaseClause: _, isTypeSwitch := findSwitchStmt(path[i+1:], pos, n).(*ast.TypeSwitchStmt) return isTypeSwitch case *ast.TypeAssertExpr: if n.Lparen < pos && pos <= n.Rparen { return true } } } return false } // matchingTypes reports whether actual is a good candidate type // for a completion in a context of the expected type. func (c *completer) matchingType(actual types.Type) bool { if c.expectedType == nil { return false } // Use a function's return type as its type. if sig, ok := actual.(*types.Signature); ok { if sig.Results().Len() == 1 { actual = sig.Results().At(0).Type() } } return types.Identical(types.Default(c.expectedType), types.Default(actual)) }