mirror of
https://github.com/golang/go
synced 2024-11-18 11:14:39 -07:00
internal/lsp/source: prefer unexported and non-func candidates
A common annoying mis-completion is as follows: type foo struct { field int } func (f foo) Field() int { return f.field } func (f foo) logic() { if f.f<> } Now at <> we prefer "field" over "Field()". Similarly: type foo struct { } func (f foo) DoSomething() { } func (f foo) doSomething() { } func (f foo) logic() { f.d<> } Now at <> we prefer "doSomething()" over "DoSomething()". All else being equally, you normally want private objects over public objects when the private objects are available. The same logic is applied to deep completions so we prefer "c.foo.bar" over "c.Foo().bar". Change-Id: Ic91cba7721ddb1f2a30338037693ddcce8c621f7 Reviewed-on: https://go-review.googlesource.com/c/tools/+/223877 Run-TryBot: Muir Manders <muir@mnd.rs> Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
8849913b69
commit
ef1313dc6d
@ -345,8 +345,19 @@ func (c *completer) found(cand candidate) {
|
||||
}
|
||||
}
|
||||
|
||||
// Favor shallow matches by lowering weight according to depth.
|
||||
cand.score -= cand.score * float64(len(c.deepState.chain)) / 10
|
||||
// Lower score of function calls so we prefer fields and vars over calls.
|
||||
if cand.expandFuncCall {
|
||||
cand.score *= 0.9
|
||||
}
|
||||
|
||||
// Prefer private objects over public ones.
|
||||
if !obj.Exported() && obj.Parent() != types.Universe {
|
||||
cand.score *= 1.1
|
||||
}
|
||||
|
||||
// Favor shallow matches by lowering score according to depth.
|
||||
cand.score -= cand.score * c.deepState.scorePenalty()
|
||||
|
||||
if cand.score < 0 {
|
||||
cand.score = 0
|
||||
}
|
||||
|
@ -93,6 +93,28 @@ func (s *deepCompletionState) isHighScore(score float64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// scorePenalty computes a deep candidate score penalty. A candidate
|
||||
// is penalized based on depth to favor shallower candidates. We also
|
||||
// give a slight bonus to unexported objects and a slight additional
|
||||
// penalty to function objects.
|
||||
func (s *deepCompletionState) scorePenalty() float64 {
|
||||
var deepPenalty float64
|
||||
for _, dc := range s.chain {
|
||||
deepPenalty += 1
|
||||
|
||||
if !dc.Exported() {
|
||||
deepPenalty -= 0.1
|
||||
}
|
||||
|
||||
if _, isSig := dc.Type().Underlying().(*types.Signature); isSig {
|
||||
deepPenalty += 0.1
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize penalty to a max depth of 10.
|
||||
return deepPenalty / 10
|
||||
}
|
||||
|
||||
func (c *completer) inDeepCompletion() bool {
|
||||
return len(c.deepState.chain) > 0
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ type stateFunc func() stateFunc //@item(stateFunc, "stateFunc", "func() stateFun
|
||||
var a unknown //@item(global_a, "a", "unknown", "var"),diag("unknown", "compiler", "undeclared name: unknown", "error")
|
||||
|
||||
func random() int { //@item(random, "random", "func() int", "func")
|
||||
//@complete("", global_a, bob, random, random2, random3, stateFunc, stuff)
|
||||
//@complete("", global_a, bob, stateFunc, random, random2, random3, stuff)
|
||||
return 0
|
||||
}
|
||||
|
||||
@ -16,18 +16,18 @@ func random2(y int) int { //@item(random2, "random2", "func(y int) int", "func")
|
||||
x := 6 //@item(x, "x", "int", "var"),diag("x", "compiler", "x declared but not used", "error")
|
||||
var q blah //@item(q, "q", "blah", "var"),diag("q", "compiler", "q declared but not used", "error"),diag("blah", "compiler", "undeclared name: blah", "error")
|
||||
var t **blob //@item(t, "t", "**blob", "var"),diag("t", "compiler", "t declared but not used", "error"),diag("blob", "compiler", "undeclared name: blob", "error")
|
||||
//@complete("", q, t, x, bad_y_param, global_a, bob, random, random2, random3, stateFunc, stuff)
|
||||
//@complete("", q, t, x, bad_y_param, global_a, bob, stateFunc, random, random2, random3, stuff)
|
||||
|
||||
return y
|
||||
}
|
||||
|
||||
func random3(y ...int) { //@item(random3, "random3", "func(y ...int)", "func"),item(y_variadic_param, "y", "[]int", "var")
|
||||
//@complete("", y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff)
|
||||
//@complete("", y_variadic_param, global_a, bob, stateFunc, random, random2, random3, stuff)
|
||||
|
||||
var ch chan (favType1) //@item(ch, "ch", "chan (favType1)", "var"),diag("ch", "compiler", "ch declared but not used", "error"),diag("favType1", "compiler", "undeclared name: favType1", "error")
|
||||
var m map[keyType]int //@item(m, "m", "map[keyType]int", "var"),diag("m", "compiler", "m declared but not used", "error"),diag("keyType", "compiler", "undeclared name: keyType", "error")
|
||||
var arr []favType2 //@item(arr, "arr", "[]favType2", "var"),diag("arr", "compiler", "arr declared but not used", "error"),diag("favType2", "compiler", "undeclared name: favType2", "error")
|
||||
var fn1 func() badResult //@item(fn1, "fn1", "func() badResult", "var"),diag("fn1", "compiler", "fn1 declared but not used", "error"),diag("badResult", "compiler", "undeclared name: badResult", "error")
|
||||
var fn2 func(badParam) //@item(fn2, "fn2", "func(badParam)", "var"),diag("fn2", "compiler", "fn2 declared but not used", "error"),diag("badParam", "compiler", "undeclared name: badParam", "error")
|
||||
//@complete("", arr, ch, fn1, fn2, m, y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff)
|
||||
//@complete("", arr, ch, fn1, fn2, m, y_variadic_param, global_a, bob, stateFunc, random, random2, random3, stuff)
|
||||
}
|
||||
|
@ -20,6 +20,6 @@ func _() {
|
||||
func _() {
|
||||
defer func() {
|
||||
foo.F //@complete(" //", Foo),snippet(" //", Foo, "Foo()", "Foo()")
|
||||
foo. //@complete(" //", Foo, IntFoo, StructFoo)
|
||||
foo. //@complete(" //", IntFoo, StructFoo, Foo)
|
||||
}
|
||||
}
|
||||
|
@ -5,5 +5,5 @@ import (
|
||||
)
|
||||
|
||||
func _() {
|
||||
defer func() { foo. } //@complete(" }", Foo, IntFoo, StructFoo)
|
||||
defer func() { foo. } //@complete(" }", IntFoo, StructFoo, Foo)
|
||||
}
|
||||
|
@ -5,5 +5,5 @@ import (
|
||||
)
|
||||
|
||||
func _() {
|
||||
go foo. //@complete(" //", Foo, IntFoo, StructFoo)
|
||||
go foo. //@complete(" //", IntFoo, StructFoo, Foo)
|
||||
}
|
||||
|
@ -6,6 +6,6 @@ import (
|
||||
|
||||
func _() {
|
||||
go func() {
|
||||
defer foo. //@complete(" //", Foo, IntFoo, StructFoo)
|
||||
defer foo. //@complete(" //", IntFoo, StructFoo, Foo)
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,9 @@ func _() {
|
||||
|
||||
// Bar is a function.
|
||||
func Bar() { //@item(Bar, "Bar", "func()", "func", "Bar is a function.")
|
||||
foo.Foo() //@complete("F", Foo, IntFoo, StructFoo)
|
||||
foo.Foo() //@complete("F", IntFoo, StructFoo, Foo)
|
||||
var _ foo.IntFoo //@complete("I", IntFoo, StructFoo)
|
||||
foo.() //@complete("(", Foo, IntFoo, StructFoo)
|
||||
foo.() //@complete("(", IntFoo, StructFoo, Foo)
|
||||
}
|
||||
|
||||
func _() {
|
||||
@ -33,15 +33,15 @@ func _() {
|
||||
Value: 5, //@complete("a", Value)
|
||||
}
|
||||
_ = foo.StructFoo{
|
||||
//@complete("", Value, Valentine, foo, Bar, helper)
|
||||
//@complete("", Value, Valentine, foo, helper, Bar)
|
||||
}
|
||||
_ = foo.StructFoo{
|
||||
Value: Valen //@complete("le", Valentine)
|
||||
}
|
||||
_ = foo.StructFoo{
|
||||
Value: //@complete(" //", Valentine, foo, Bar, helper)
|
||||
Value: //@complete(" //", Valentine, foo, helper, Bar)
|
||||
}
|
||||
_ = foo.StructFoo{
|
||||
Value: //@complete(" ", Valentine, foo, Bar, helper)
|
||||
Value: //@complete(" ", Valentine, foo, helper, Bar)
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ type position struct { //@item(structPosition, "position", "struct{...}", "struc
|
||||
|
||||
func _() {
|
||||
_ = position{
|
||||
//@complete("", fieldX, fieldY, cVar, structPosition)
|
||||
//@complete("", fieldX, fieldY, structPosition, cVar)
|
||||
}
|
||||
_ = position{
|
||||
X: 1,
|
||||
@ -21,7 +21,7 @@ func _() {
|
||||
}
|
||||
_ = []*position{
|
||||
{
|
||||
//@complete("", fieldX, fieldY, cVar, structPosition)
|
||||
//@complete("", fieldX, fieldY, structPosition, cVar)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -37,7 +37,7 @@ func _() {
|
||||
}
|
||||
|
||||
_ = map[int]int{
|
||||
//@complete("", abVar, aaVar, cVar, structPosition)
|
||||
//@complete("", abVar, aaVar, structPosition, cVar)
|
||||
}
|
||||
|
||||
_ = []string{a: ""} //@complete(":", abVar, aaVar)
|
||||
@ -45,10 +45,10 @@ func _() {
|
||||
|
||||
_ = position{X: a} //@complete("}", abVar, aaVar)
|
||||
_ = position{a} //@complete("}", abVar, aaVar)
|
||||
_ = position{a, } //@complete("}", abVar, aaVar, cVar, structPosition)
|
||||
_ = position{a, } //@complete("}", abVar, aaVar, structPosition, cVar)
|
||||
|
||||
_ = []int{a} //@complete("a", abVar, aaVar, cVar, structPosition)
|
||||
_ = [1]int{a} //@complete("a", abVar, aaVar, cVar, structPosition)
|
||||
_ = []int{a} //@complete("a", abVar, aaVar, structPosition, cVar)
|
||||
_ = [1]int{a} //@complete("a", abVar, aaVar, structPosition, cVar)
|
||||
|
||||
type myStruct struct {
|
||||
AA int //@item(fieldAA, "AA", "int", "field")
|
||||
@ -73,7 +73,7 @@ func _() {
|
||||
|
||||
func _() {
|
||||
_ := position{
|
||||
X: 1, //@complete("X", fieldX),complete(" 1", cVar, structPosition)
|
||||
Y: , //@complete(":", fieldY),complete(" ,", cVar, structPosition)
|
||||
X: 1, //@complete("X", fieldX),complete(" 1", structPosition, cVar)
|
||||
Y: , //@complete(":", fieldY),complete(" ,", structPosition, cVar)
|
||||
}
|
||||
}
|
||||
|
@ -113,9 +113,23 @@ func _() {
|
||||
f foo
|
||||
)
|
||||
|
||||
f.b.ptrReceiver() //@item(deepBPtr, "f.b.ptrReceiver", "func() int", "method")
|
||||
f.bar().valueReceiver //@item(deepBarValue, "f.bar().valueReceiver", "func() int", "method")
|
||||
f.barPtr().ptrReceiver //@item(deepBarPtrPtr, "f.barPtr().ptrReceiver", "func() int", "method")
|
||||
f.bar().valueReceiver //@item(deepBarValue, "f.bar().valueReceiver", "func() int", "method")
|
||||
f.barPtr().ptrReceiver //@item(deepBarPtrPtr, "f.barPtr().ptrReceiver", "func() int", "method")
|
||||
f.barPtr().valueReceiver //@item(deepBarPtrValue, "f.barPtr().valueReceiver", "func() int", "method")
|
||||
|
||||
i = fb //@fuzzy(" //", deepBPtr, deepBarValue, deepBarPtrPtr)
|
||||
i = fbar //@fuzzy(" //", deepBarValue, deepBarPtrPtr, deepBarPtrValue)
|
||||
}
|
||||
|
||||
func (b baz) Thing() struct{ val int } {
|
||||
return b.thing
|
||||
}
|
||||
|
||||
type baz struct {
|
||||
thing struct{ val int }
|
||||
}
|
||||
|
||||
func (b baz) _() {
|
||||
b.Thing().val //@item(deepBazMethVal, "b.Thing().val", "int", "field")
|
||||
b.thing.val //@item(deepBazFieldVal, "b.thing.val", "int", "field")
|
||||
var _ int = b //@rank(" //", deepBazFieldVal, deepBazMethVal)
|
||||
}
|
||||
|
@ -42,3 +42,20 @@ func _() {
|
||||
return s.A //@complete(" //", rankAB, rankAA, rankAC)
|
||||
}
|
||||
}
|
||||
|
||||
type foo struct {
|
||||
fooPrivateField int //@item(rankFooPrivField, "fooPrivateField", "int", "field")
|
||||
FooPublicField int //@item(rankFooPubField, "FooPublicField", "int", "field")
|
||||
}
|
||||
|
||||
func (foo) fooPrivateMethod() int { //@item(rankFooPrivMeth, "fooPrivateMethod", "func() int", "method")
|
||||
return 0
|
||||
}
|
||||
|
||||
func (foo) FooPublicMethod() int { //@item(rankFooPubMeth, "FooPublicMethod", "func() int", "method")
|
||||
return 0
|
||||
}
|
||||
|
||||
func _() {
|
||||
var _ int = foo{}. //@rank(" //", rankFooPrivField, rankFooPubField),rank(" //", rankFooPrivMeth, rankFooPubMeth),rank(" //", rankFooPrivField, rankFooPrivMeth)
|
||||
}
|
||||
|
@ -5,5 +5,5 @@ import (
|
||||
)
|
||||
|
||||
func _() {
|
||||
foo.Foo() //@complete("F", Foo, IntFoo, StructFoo)
|
||||
}
|
||||
foo.Foo() //@complete("F", IntFoo, StructFoo, Foo)
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ func _() {
|
||||
b := &bob{}
|
||||
y := b.george().
|
||||
jack();
|
||||
y.; //@complete(";", jill, c)
|
||||
y.; //@complete(";", c, jill)
|
||||
}
|
||||
|
||||
func _() {
|
||||
@ -35,10 +35,10 @@ func _() {
|
||||
x := 5
|
||||
|
||||
var b *bob
|
||||
b. //@complete(" /", george, a)
|
||||
b. //@complete(" /", a, george)
|
||||
y, z := 5, 6
|
||||
|
||||
b. //@complete(" /", george, a)
|
||||
b. //@complete(" /", a, george)
|
||||
y, z, a, b, c := 5, 6
|
||||
}
|
||||
|
||||
@ -52,15 +52,15 @@ func _() {
|
||||
|
||||
func _() {
|
||||
var b *bob
|
||||
if y != b. //@complete(" /", george, a)
|
||||
if y != b. //@complete(" /", a, george)
|
||||
z := 5
|
||||
|
||||
if z + y + 1 + b. //@complete(" /", george, a)
|
||||
if z + y + 1 + b. //@complete(" /", a, george)
|
||||
r, s, t := 4, 5
|
||||
|
||||
if y != b. //@complete(" /", george, a)
|
||||
if y != b. //@complete(" /", a, george)
|
||||
z = 5
|
||||
|
||||
if z + y + 1 + b. //@complete(" /", george, a)
|
||||
if z + y + 1 + b. //@complete(" /", a, george)
|
||||
r = 4
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ func _() {
|
||||
// container/ring is extremely unlikely to be imported by anything, so shouldn't have type information.
|
||||
ring.Ring //@unimported("Ring", ringring)
|
||||
signature.Foo //@unimported("Foo", signaturefoo)
|
||||
context.Bac //@unimported("Bac", contextBackground, contextBackgroundErr)
|
||||
|
||||
context.Bac //@unimported(" //", contextBackground, contextBackgroundErr)
|
||||
}
|
||||
|
||||
// Create markers for unimported std lib packages. Only for use by this test.
|
||||
|
2
internal/lsp/testdata/lsp/summary.txt.golden
vendored
2
internal/lsp/testdata/lsp/summary.txt.golden
vendored
@ -5,7 +5,7 @@ CompletionSnippetCount = 75
|
||||
UnimportedCompletionsCount = 11
|
||||
DeepCompletionsCount = 5
|
||||
FuzzyCompletionsCount = 8
|
||||
RankedCompletionsCount = 116
|
||||
RankedCompletionsCount = 120
|
||||
CaseSensitiveCompletionsCount = 4
|
||||
DiagnosticsCount = 39
|
||||
FoldingRangesCount = 2
|
||||
|
Loading…
Reference in New Issue
Block a user