2019-12-30 17:49:53 -07:00
|
|
|
// Copyright 2020 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 (
|
2020-04-05 23:18:15 -06:00
|
|
|
"context"
|
2019-12-30 17:49:53 -07:00
|
|
|
"go/ast"
|
|
|
|
"go/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
// builtinArgKind determines the expected object kind for a builtin
|
|
|
|
// argument. It attempts to use the AST hints from builtin.go where
|
|
|
|
// possible.
|
2020-04-05 23:18:15 -06:00
|
|
|
func (c *completer) builtinArgKind(ctx context.Context, obj types.Object, call *ast.CallExpr) objKind {
|
2020-06-05 15:30:52 -06:00
|
|
|
builtin, err := c.snapshot.View().BuiltinPackage(ctx)
|
2020-01-11 18:29:13 -07:00
|
|
|
if err != nil {
|
2019-12-30 17:49:53 -07:00
|
|
|
return 0
|
|
|
|
}
|
2020-01-25 16:22:03 -07:00
|
|
|
exprIdx := exprAtPos(c.pos, call.Args)
|
2019-12-30 17:49:53 -07:00
|
|
|
|
2020-06-05 15:30:52 -06:00
|
|
|
decl, ok := builtin.Package().Scope.Lookup(obj.Name()).Decl.(*ast.FuncDecl)
|
2019-12-30 17:49:53 -07:00
|
|
|
if !ok || exprIdx >= len(decl.Type.Params.List) {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ptyp := decl.Type.Params.List[exprIdx].Type.(type) {
|
|
|
|
case *ast.ChanType:
|
|
|
|
return kindChan
|
|
|
|
case *ast.ArrayType:
|
|
|
|
return kindSlice
|
|
|
|
case *ast.MapType:
|
|
|
|
return kindMap
|
|
|
|
case *ast.Ident:
|
|
|
|
switch ptyp.Name {
|
|
|
|
case "Type":
|
|
|
|
switch obj.Name() {
|
|
|
|
case "make":
|
|
|
|
return kindChan | kindSlice | kindMap
|
|
|
|
case "len":
|
|
|
|
return kindSlice | kindMap | kindArray | kindString | kindChan
|
|
|
|
case "cap":
|
|
|
|
return kindSlice | kindArray | kindChan
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// builtinArgType infers the type of an argument to a builtin
|
internal/lsp/source: untangle completion type comparison
The code to check if a candidate object matches our candidate
inference had become complicated, messy, and in some cases incorrect.
The main source of the complexity is the "derived" expected and
candidate types. When considering a candidate object "foo", we also
consider "&foo", "foo()", and "*foo", as appropriate. On the expected
side of things, when completing the a variadic function parameter we
expect either the variadic slice type and the scalar element type.
The code had grown organically to handle the expanding concerns, but
that resulted in confused code that didn't handle the interplay
between the various facets of candidate inference.
For example, we were inappropriately invoking func candidates when
completing variadic args:
func foo(...func())
func bar() {}
foo(bar<>) // oops - expanded to "bar()"
and we weren't type matching functions properly as builtin args:
func myMap() map[string]int { ... }
delete(myM<>) // we weren't preferring (or invoking) "myMap()"
We also had methods like "typeMatches" which took both a "candidate"
object and a "candType" type, which doesn't make sense because the
candidate contains the type already.
Now instead we explicitly iterate over all the derived candidate and
expected types so they are treated the same. There are still some
warts left but I think this is a step in the right direction.
Change-Id: If84a84b34a8fb771a32231f7ab64ca192f611b3d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218877
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-02-08 20:59:28 -07:00
|
|
|
// function. parentInf is the inferred type info for the builtin
|
|
|
|
// call's parent node.
|
|
|
|
func (c *completer) builtinArgType(obj types.Object, call *ast.CallExpr, parentInf candidateInference) candidateInference {
|
|
|
|
var (
|
|
|
|
exprIdx = exprAtPos(c.pos, call.Args)
|
|
|
|
inf = candidateInference{}
|
|
|
|
)
|
2019-12-30 17:49:53 -07:00
|
|
|
|
|
|
|
switch obj.Name() {
|
|
|
|
case "append":
|
2020-04-02 11:31:57 -06:00
|
|
|
if parentInf.objType == nil {
|
|
|
|
break
|
|
|
|
}
|
internal/lsp/source: untangle completion type comparison
The code to check if a candidate object matches our candidate
inference had become complicated, messy, and in some cases incorrect.
The main source of the complexity is the "derived" expected and
candidate types. When considering a candidate object "foo", we also
consider "&foo", "foo()", and "*foo", as appropriate. On the expected
side of things, when completing the a variadic function parameter we
expect either the variadic slice type and the scalar element type.
The code had grown organically to handle the expanding concerns, but
that resulted in confused code that didn't handle the interplay
between the various facets of candidate inference.
For example, we were inappropriately invoking func candidates when
completing variadic args:
func foo(...func())
func bar() {}
foo(bar<>) // oops - expanded to "bar()"
and we weren't type matching functions properly as builtin args:
func myMap() map[string]int { ... }
delete(myM<>) // we weren't preferring (or invoking) "myMap()"
We also had methods like "typeMatches" which took both a "candidate"
object and a "candType" type, which doesn't make sense because the
candidate contains the type already.
Now instead we explicitly iterate over all the derived candidate and
expected types so they are treated the same. There are still some
warts left but I think this is a step in the right direction.
Change-Id: If84a84b34a8fb771a32231f7ab64ca192f611b3d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218877
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-02-08 20:59:28 -07:00
|
|
|
inf.objType = parentInf.objType
|
2019-12-30 17:49:53 -07:00
|
|
|
|
internal/lsp/source: untangle completion type comparison
The code to check if a candidate object matches our candidate
inference had become complicated, messy, and in some cases incorrect.
The main source of the complexity is the "derived" expected and
candidate types. When considering a candidate object "foo", we also
consider "&foo", "foo()", and "*foo", as appropriate. On the expected
side of things, when completing the a variadic function parameter we
expect either the variadic slice type and the scalar element type.
The code had grown organically to handle the expanding concerns, but
that resulted in confused code that didn't handle the interplay
between the various facets of candidate inference.
For example, we were inappropriately invoking func candidates when
completing variadic args:
func foo(...func())
func bar() {}
foo(bar<>) // oops - expanded to "bar()"
and we weren't type matching functions properly as builtin args:
func myMap() map[string]int { ... }
delete(myM<>) // we weren't preferring (or invoking) "myMap()"
We also had methods like "typeMatches" which took both a "candidate"
object and a "candType" type, which doesn't make sense because the
candidate contains the type already.
Now instead we explicitly iterate over all the derived candidate and
expected types so they are treated the same. There are still some
warts left but I think this is a step in the right direction.
Change-Id: If84a84b34a8fb771a32231f7ab64ca192f611b3d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218877
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-02-08 20:59:28 -07:00
|
|
|
// Check if we are completing the variadic append() param.
|
|
|
|
if exprIdx == 1 && len(call.Args) <= 2 {
|
|
|
|
inf.variadicType = deslice(inf.objType)
|
|
|
|
} else if exprIdx > 0 {
|
|
|
|
// If we are completing an individual element of the variadic
|
|
|
|
// param, "deslice" the expected type.
|
|
|
|
inf.objType = deslice(inf.objType)
|
2019-12-30 17:49:53 -07:00
|
|
|
}
|
|
|
|
case "delete":
|
|
|
|
if exprIdx > 0 && len(call.Args) > 0 {
|
|
|
|
// Try to fill in expected type of map key.
|
|
|
|
firstArgType := c.pkg.GetTypesInfo().TypeOf(call.Args[0])
|
|
|
|
if firstArgType != nil {
|
|
|
|
if mt, ok := firstArgType.Underlying().(*types.Map); ok {
|
internal/lsp/source: untangle completion type comparison
The code to check if a candidate object matches our candidate
inference had become complicated, messy, and in some cases incorrect.
The main source of the complexity is the "derived" expected and
candidate types. When considering a candidate object "foo", we also
consider "&foo", "foo()", and "*foo", as appropriate. On the expected
side of things, when completing the a variadic function parameter we
expect either the variadic slice type and the scalar element type.
The code had grown organically to handle the expanding concerns, but
that resulted in confused code that didn't handle the interplay
between the various facets of candidate inference.
For example, we were inappropriately invoking func candidates when
completing variadic args:
func foo(...func())
func bar() {}
foo(bar<>) // oops - expanded to "bar()"
and we weren't type matching functions properly as builtin args:
func myMap() map[string]int { ... }
delete(myM<>) // we weren't preferring (or invoking) "myMap()"
We also had methods like "typeMatches" which took both a "candidate"
object and a "candType" type, which doesn't make sense because the
candidate contains the type already.
Now instead we explicitly iterate over all the derived candidate and
expected types so they are treated the same. There are still some
warts left but I think this is a step in the right direction.
Change-Id: If84a84b34a8fb771a32231f7ab64ca192f611b3d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218877
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-02-08 20:59:28 -07:00
|
|
|
inf.objType = mt.Key()
|
2019-12-30 17:49:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case "copy":
|
|
|
|
var t1, t2 types.Type
|
|
|
|
if len(call.Args) > 0 {
|
|
|
|
t1 = c.pkg.GetTypesInfo().TypeOf(call.Args[0])
|
|
|
|
if len(call.Args) > 1 {
|
|
|
|
t2 = c.pkg.GetTypesInfo().TypeOf(call.Args[1])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fill in expected type of either arg if the other is already present.
|
|
|
|
if exprIdx == 1 && t1 != nil {
|
internal/lsp/source: untangle completion type comparison
The code to check if a candidate object matches our candidate
inference had become complicated, messy, and in some cases incorrect.
The main source of the complexity is the "derived" expected and
candidate types. When considering a candidate object "foo", we also
consider "&foo", "foo()", and "*foo", as appropriate. On the expected
side of things, when completing the a variadic function parameter we
expect either the variadic slice type and the scalar element type.
The code had grown organically to handle the expanding concerns, but
that resulted in confused code that didn't handle the interplay
between the various facets of candidate inference.
For example, we were inappropriately invoking func candidates when
completing variadic args:
func foo(...func())
func bar() {}
foo(bar<>) // oops - expanded to "bar()"
and we weren't type matching functions properly as builtin args:
func myMap() map[string]int { ... }
delete(myM<>) // we weren't preferring (or invoking) "myMap()"
We also had methods like "typeMatches" which took both a "candidate"
object and a "candType" type, which doesn't make sense because the
candidate contains the type already.
Now instead we explicitly iterate over all the derived candidate and
expected types so they are treated the same. There are still some
warts left but I think this is a step in the right direction.
Change-Id: If84a84b34a8fb771a32231f7ab64ca192f611b3d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218877
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-02-08 20:59:28 -07:00
|
|
|
inf.objType = t1
|
2019-12-30 17:49:53 -07:00
|
|
|
} else if exprIdx == 0 && t2 != nil {
|
internal/lsp/source: untangle completion type comparison
The code to check if a candidate object matches our candidate
inference had become complicated, messy, and in some cases incorrect.
The main source of the complexity is the "derived" expected and
candidate types. When considering a candidate object "foo", we also
consider "&foo", "foo()", and "*foo", as appropriate. On the expected
side of things, when completing the a variadic function parameter we
expect either the variadic slice type and the scalar element type.
The code had grown organically to handle the expanding concerns, but
that resulted in confused code that didn't handle the interplay
between the various facets of candidate inference.
For example, we were inappropriately invoking func candidates when
completing variadic args:
func foo(...func())
func bar() {}
foo(bar<>) // oops - expanded to "bar()"
and we weren't type matching functions properly as builtin args:
func myMap() map[string]int { ... }
delete(myM<>) // we weren't preferring (or invoking) "myMap()"
We also had methods like "typeMatches" which took both a "candidate"
object and a "candType" type, which doesn't make sense because the
candidate contains the type already.
Now instead we explicitly iterate over all the derived candidate and
expected types so they are treated the same. There are still some
warts left but I think this is a step in the right direction.
Change-Id: If84a84b34a8fb771a32231f7ab64ca192f611b3d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218877
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-02-08 20:59:28 -07:00
|
|
|
inf.objType = t2
|
2019-12-30 17:49:53 -07:00
|
|
|
}
|
|
|
|
case "new":
|
internal/lsp/source: untangle completion type comparison
The code to check if a candidate object matches our candidate
inference had become complicated, messy, and in some cases incorrect.
The main source of the complexity is the "derived" expected and
candidate types. When considering a candidate object "foo", we also
consider "&foo", "foo()", and "*foo", as appropriate. On the expected
side of things, when completing the a variadic function parameter we
expect either the variadic slice type and the scalar element type.
The code had grown organically to handle the expanding concerns, but
that resulted in confused code that didn't handle the interplay
between the various facets of candidate inference.
For example, we were inappropriately invoking func candidates when
completing variadic args:
func foo(...func())
func bar() {}
foo(bar<>) // oops - expanded to "bar()"
and we weren't type matching functions properly as builtin args:
func myMap() map[string]int { ... }
delete(myM<>) // we weren't preferring (or invoking) "myMap()"
We also had methods like "typeMatches" which took both a "candidate"
object and a "candType" type, which doesn't make sense because the
candidate contains the type already.
Now instead we explicitly iterate over all the derived candidate and
expected types so they are treated the same. There are still some
warts left but I think this is a step in the right direction.
Change-Id: If84a84b34a8fb771a32231f7ab64ca192f611b3d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218877
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-02-08 20:59:28 -07:00
|
|
|
inf.typeName.wantTypeName = true
|
|
|
|
if parentInf.objType != nil {
|
2019-12-30 17:49:53 -07:00
|
|
|
// Expected type for "new" is the de-pointered parent type.
|
internal/lsp/source: untangle completion type comparison
The code to check if a candidate object matches our candidate
inference had become complicated, messy, and in some cases incorrect.
The main source of the complexity is the "derived" expected and
candidate types. When considering a candidate object "foo", we also
consider "&foo", "foo()", and "*foo", as appropriate. On the expected
side of things, when completing the a variadic function parameter we
expect either the variadic slice type and the scalar element type.
The code had grown organically to handle the expanding concerns, but
that resulted in confused code that didn't handle the interplay
between the various facets of candidate inference.
For example, we were inappropriately invoking func candidates when
completing variadic args:
func foo(...func())
func bar() {}
foo(bar<>) // oops - expanded to "bar()"
and we weren't type matching functions properly as builtin args:
func myMap() map[string]int { ... }
delete(myM<>) // we weren't preferring (or invoking) "myMap()"
We also had methods like "typeMatches" which took both a "candidate"
object and a "candType" type, which doesn't make sense because the
candidate contains the type already.
Now instead we explicitly iterate over all the derived candidate and
expected types so they are treated the same. There are still some
warts left but I think this is a step in the right direction.
Change-Id: If84a84b34a8fb771a32231f7ab64ca192f611b3d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218877
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-02-08 20:59:28 -07:00
|
|
|
if ptr, ok := parentInf.objType.Underlying().(*types.Pointer); ok {
|
|
|
|
inf.objType = ptr.Elem()
|
2019-12-30 17:49:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case "make":
|
|
|
|
if exprIdx == 0 {
|
internal/lsp/source: untangle completion type comparison
The code to check if a candidate object matches our candidate
inference had become complicated, messy, and in some cases incorrect.
The main source of the complexity is the "derived" expected and
candidate types. When considering a candidate object "foo", we also
consider "&foo", "foo()", and "*foo", as appropriate. On the expected
side of things, when completing the a variadic function parameter we
expect either the variadic slice type and the scalar element type.
The code had grown organically to handle the expanding concerns, but
that resulted in confused code that didn't handle the interplay
between the various facets of candidate inference.
For example, we were inappropriately invoking func candidates when
completing variadic args:
func foo(...func())
func bar() {}
foo(bar<>) // oops - expanded to "bar()"
and we weren't type matching functions properly as builtin args:
func myMap() map[string]int { ... }
delete(myM<>) // we weren't preferring (or invoking) "myMap()"
We also had methods like "typeMatches" which took both a "candidate"
object and a "candType" type, which doesn't make sense because the
candidate contains the type already.
Now instead we explicitly iterate over all the derived candidate and
expected types so they are treated the same. There are still some
warts left but I think this is a step in the right direction.
Change-Id: If84a84b34a8fb771a32231f7ab64ca192f611b3d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218877
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-02-08 20:59:28 -07:00
|
|
|
inf.typeName.wantTypeName = true
|
|
|
|
inf.objType = parentInf.objType
|
2020-02-01 22:45:01 -07:00
|
|
|
} else {
|
internal/lsp/source: untangle completion type comparison
The code to check if a candidate object matches our candidate
inference had become complicated, messy, and in some cases incorrect.
The main source of the complexity is the "derived" expected and
candidate types. When considering a candidate object "foo", we also
consider "&foo", "foo()", and "*foo", as appropriate. On the expected
side of things, when completing the a variadic function parameter we
expect either the variadic slice type and the scalar element type.
The code had grown organically to handle the expanding concerns, but
that resulted in confused code that didn't handle the interplay
between the various facets of candidate inference.
For example, we were inappropriately invoking func candidates when
completing variadic args:
func foo(...func())
func bar() {}
foo(bar<>) // oops - expanded to "bar()"
and we weren't type matching functions properly as builtin args:
func myMap() map[string]int { ... }
delete(myM<>) // we weren't preferring (or invoking) "myMap()"
We also had methods like "typeMatches" which took both a "candidate"
object and a "candType" type, which doesn't make sense because the
candidate contains the type already.
Now instead we explicitly iterate over all the derived candidate and
expected types so they are treated the same. There are still some
warts left but I think this is a step in the right direction.
Change-Id: If84a84b34a8fb771a32231f7ab64ca192f611b3d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218877
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-02-08 20:59:28 -07:00
|
|
|
inf.objType = types.Typ[types.Int]
|
2019-12-30 17:49:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
internal/lsp/source: untangle completion type comparison
The code to check if a candidate object matches our candidate
inference had become complicated, messy, and in some cases incorrect.
The main source of the complexity is the "derived" expected and
candidate types. When considering a candidate object "foo", we also
consider "&foo", "foo()", and "*foo", as appropriate. On the expected
side of things, when completing the a variadic function parameter we
expect either the variadic slice type and the scalar element type.
The code had grown organically to handle the expanding concerns, but
that resulted in confused code that didn't handle the interplay
between the various facets of candidate inference.
For example, we were inappropriately invoking func candidates when
completing variadic args:
func foo(...func())
func bar() {}
foo(bar<>) // oops - expanded to "bar()"
and we weren't type matching functions properly as builtin args:
func myMap() map[string]int { ... }
delete(myM<>) // we weren't preferring (or invoking) "myMap()"
We also had methods like "typeMatches" which took both a "candidate"
object and a "candType" type, which doesn't make sense because the
candidate contains the type already.
Now instead we explicitly iterate over all the derived candidate and
expected types so they are treated the same. There are still some
warts left but I think this is a step in the right direction.
Change-Id: If84a84b34a8fb771a32231f7ab64ca192f611b3d
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218877
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
2020-02-08 20:59:28 -07:00
|
|
|
return inf
|
2019-12-30 17:49:53 -07:00
|
|
|
}
|