internal/lsp: produce "method" in place of "member" as per the spec

As per the current specification, the correct token name that represents methods is `method`. The current implementation does not produce the correct set of result and results in methods being incorrectly highlighted. Furthermore, the parameter names of interface methods are treated as `method` which is not true, so a fix has been applied to handle `ast.FuncType` being `parameter`.

Spec: https://microsoft.github.io/language-server-protocol/specifications/specification-3-16/#textDocument_semanticTokens

Change-Id: Id5d2fafe9f948a4a175ae19b4c94cca8f48a4b79
GitHub-Last-Rev: 9a3b65ca4dd3bb0542969c043a2042001c7fcb63
GitHub-Pull-Request: golang/tools#340
Reviewed-on: https://go-review.googlesource.com/c/tools/+/349449
Run-TryBot: Peter Weinberger <pjw@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Rebecca Stambler <rstambler@golang.org>
Trust: Peter Weinberger <pjw@google.com>
Reviewed-by: Peter Weinberger <pjw@google.com>
This commit is contained in:
Chitoku 2021-09-12 16:27:28 +00:00 committed by Rebecca Stambler
parent 915f620947
commit e7de6523a2
4 changed files with 15 additions and 13 deletions

View File

@ -16,7 +16,7 @@ don't make intuitive sense (although `async documentation` has a certain appeal)
The 22 semantic tokens are `namespace`, `type`, `class`, `enum`, `interface`,
`struct`, `typeParameter`, `parameter`, `variable`, `property`, `enumMember`,
`event`, `function`, `member`, `macro`, `keyword`, `modifier`, `comment`,
`event`, `function`, `method`, `macro`, `keyword`, `modifier`, `comment`,
`string`, `number`, `regexp`, `operator`.
The 10 modifiers are `declaration`, `definition`, `readonly`, `static`,
@ -72,7 +72,7 @@ alias, it would be marked. Otherwise the last component of the import path is ma
1. __`type`__ Objects of type ```types.TypeName``` are marked `type`.
If they are also ```types.Basic```
the modifier is `defaultLibrary`. (And in ```type B struct{C}```, ```B``` has modifier `definition`.)
1. __`parameter`__ The formal arguments in ```ast.FuncDecl``` nodes are marked `parameter`.
1. __`parameter`__ The formal arguments in ```ast.FuncDecl``` and ```ast.FuncType``` nodes are marked `parameter`.
1. __`variable`__ Identifiers in the
scope of ```const``` are modified with `readonly`. ```nil``` is usually a `variable` modified with both
`readonly` and `defaultLibrary`. (```nil``` is a predefined identifier; the user can redefine it,
@ -80,8 +80,8 @@ in which case it would just be a variable, or whatever.) Identifiers of type ```
not surprisingly, marked `variable`. Identifiers being defined (node ```ast.GenDecl```) are modified
by `definition` and, if appropriate, `readonly`. Receivers (in method declarations) are
`variable`.
1. __`member`__ Members are marked at their definition (```func (x foo) bar() {}```) or declaration
in an ```interface```. Members are not marked where they are used.
1. __`method`__ Methods are marked at their definition (```func (x foo) bar() {}```) or declaration
in an ```interface```. Methods are not marked where they are used.
In ```x.bar()```, ```x``` will be marked
either as a `namespace` if it is a package name, or as a `variable` if it is an interface value,
so distinguishing ```bar``` seemed superfluous.

View File

@ -155,7 +155,7 @@ const (
tokInterface tokenType = "interface"
tokParameter tokenType = "parameter"
tokVariable tokenType = "variable"
tokMember tokenType = "member"
tokMethod tokenType = "method"
tokFunction tokenType = "function"
tokKeyword tokenType = "keyword"
tokComment tokenType = "comment"
@ -598,7 +598,7 @@ func (e *encoded) unkIdent(x *ast.Ident) {
_, okit := e.stack[n-2].(*ast.InterfaceType)
_, okfl := e.stack[n-1].(*ast.FieldList)
if okit && okfl {
tok(tokMember, def)
tok(tokMethod, def)
return
}
}
@ -645,7 +645,7 @@ func (e *encoded) definitionFor(x *ast.Ident) (tokenType, []string) {
if x.Name == "_" {
return "", nil // not really a variable
}
return "variable", mods
return tokVariable, mods
case *ast.GenDecl:
if isDeprecated(y.Doc) {
mods = append(mods, "deprecated")
@ -661,7 +661,7 @@ func (e *encoded) definitionFor(x *ast.Ident) (tokenType, []string) {
mods = append(mods, "deprecated")
}
if y.Recv != nil {
return tokMember, mods
return tokMethod, mods
}
return tokFunction, mods
}
@ -671,8 +671,10 @@ func (e *encoded) definitionFor(x *ast.Ident) (tokenType, []string) {
}
// if x < ... < FieldList < FuncType < FuncDecl, this is a param
return tokParameter, mods
case *ast.FuncType:
return tokParameter, mods
case *ast.InterfaceType:
return tokMember, mods
return tokMethod, mods
case *ast.TypeSpec:
// GenDecl/Typespec/FuncType/FieldList/Field/Ident
// (type A func(b uint64)) (err error)
@ -878,7 +880,7 @@ var (
semanticTypes = [...]string{
"namespace", "type", "class", "enum", "interface",
"struct", "typeParameter", "parameter", "variable", "property", "enumMember",
"event", "function", "member", "macro", "keyword", "modifier", "comment",
"event", "function", "method", "macro", "keyword", "modifier", "comment",
"string", "number", "regexp", "operator",
}
semanticModifiers = [...]string{

View File

@ -31,12 +31,12 @@
}
/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/B /*⇒9,keyword,[]*/interface {
/*⇒1,type,[]*/A
/*⇒3,member,[definition]*/sad(/*⇒3,type,[defaultLibrary]*/int) /*⇒4,type,[defaultLibrary]*/bool
/*⇒3,method,[definition]*/sad(/*⇒3,type,[defaultLibrary]*/int) /*⇒4,type,[defaultLibrary]*/bool
}
/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/F /*⇒3,type,[defaultLibrary]*/int
/*⇒4,keyword,[]*/func (/*⇒1,variable,[]*/a /*⇒1,operator,[]*/*/*⇒1,type,[]*/A) /*⇒1,member,[definition]*/f() /*⇒4,type,[defaultLibrary]*/bool {
/*⇒4,keyword,[]*/func (/*⇒1,variable,[]*/a /*⇒1,operator,[]*/*/*⇒1,type,[]*/A) /*⇒1,method,[definition]*/f() /*⇒4,type,[defaultLibrary]*/bool {
/*⇒3,keyword,[]*/var /*⇒1,variable,[definition]*/z /*⇒6,type,[defaultLibrary]*/string
/*⇒1,variable,[definition]*/x /*⇒2,operator,[]*/:= /*⇒5,string,[]*/"foo"
/*⇒1,variable,[]*/a(/*⇒1,variable,[]*/x)

View File

@ -31,6 +31,6 @@
/*⇒4,keyword,[]*/type /*⇒2,type,[definition]*/CC /*⇒6,keyword,[]*/struct {
/*⇒2,variable,[definition]*/AA /*⇒3,type,[defaultLibrary]*/int
}
/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/D /*⇒4,keyword,[]*/func(/*⇒2,variable,[definition]*/aa /*⇒2,type,[]*/AA) (/*⇒2,variable,[definition]*/BB /*⇒5,type,[]*/error)
/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/D /*⇒4,keyword,[]*/func(/*⇒2,parameter,[definition]*/aa /*⇒2,type,[]*/AA) (/*⇒2,parameter,[definition]*/BB /*⇒5,type,[]*/error)
/*⇒4,keyword,[]*/type /*⇒1,type,[definition]*/E /*⇒4,keyword,[]*/func(/*⇒2,type,[]*/AA) /*⇒2,type,[]*/BB