Skip to content

Commit

Permalink
refactor(tools/spxls): return all definition identifiers in `textDocu…
Browse files Browse the repository at this point in the history
…ment/documentLink` (#1170)

Signed-off-by: Aofei Sheng <[email protected]>
  • Loading branch information
aofei authored Dec 25, 2024
1 parent 3486960 commit b64a5ab
Show file tree
Hide file tree
Showing 13 changed files with 910 additions and 790 deletions.
1 change: 0 additions & 1 deletion tools/spxls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ For detailed API references, please check the [index.d.ts](index.d.ts) file.
|| [`textDocument/references`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_references) | Finds all references of a symbol. |
|| [`textDocument/documentHighlight`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_documentHighlight) | Highlights other occurrences of selected symbol. |
|| [`textDocument/documentLink`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_documentLink) | Provides clickable links within document content. |
|| [`documentLink/resolve`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#documentLink_resolve) | Provides detailed target information for selected document links. |
| **Code Quality** |||
|| [`textDocument/publishDiagnostics`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_publishDiagnostics) | Reports code errors and warnings in real-time. |
|| [`textDocument/diagnostic`](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_diagnostic) | Pulls diagnostics for documents on request (pull model). |
Expand Down
89 changes: 42 additions & 47 deletions tools/spxls/internal/server/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,22 +132,16 @@ func (s *Server) spxGetDefinitions(params []SpxGetDefinitionsParams) ([]SpxDefin
return nil, nil
}
innermostScope := result.innermostScopeAt(pos)
if innermostScope == nil {
return nil, nil
}

var definitions []SpxDefinitionIdentifier
addDefinition := func(pkg, name string, overloadID *string) {
def := SpxDefinitionIdentifier{
OverloadID: overloadID,
}
if pkg != "" {
def.Package = &pkg
}
if name != "" {
def.Name = &name
}
if !slices.ContainsFunc(definitions, func(def SpxDefinitionIdentifier) bool {
return fromStringPtr(def.Name) == name && fromStringPtr(def.OverloadID) == fromStringPtr(overloadID)
var definitionIDs []SpxDefinitionIdentifier
addDefinitionID := func(defID SpxDefinitionIdentifier) {
if !slices.ContainsFunc(definitionIDs, func(existingDefID SpxDefinitionIdentifier) bool {
return existingDefID.String() == defID.String()
}) {
definitions = append(definitions, def)
definitionIDs = append(definitionIDs, defID)
}
}

Expand Down Expand Up @@ -209,7 +203,10 @@ func (s *Server) spxGetDefinitions(params []SpxGetDefinitionsParams) ([]SpxDefin
if obj == nil {
continue
}
addDefinition(obj.Pkg().Name(), obj.Name(), nil)
addDefinitionID(SpxDefinitionIdentifier{
Package: util.ToPtr(obj.Pkg().Name()),
Name: util.ToPtr(obj.Name()),
})

isThis := name == "this"
isSpxFileMatch := spxFile == name+".spx" || (spxFile == result.mainSpxFile && name == "Game")
Expand All @@ -230,7 +227,10 @@ func (s *Server) spxGetDefinitions(params []SpxGetDefinitionsParams) ([]SpxDefin

switch member := member.(type) {
case *types.Var:
addDefinition(memberPkgPath, member.Name(), nil)
addDefinitionID(SpxDefinitionIdentifier{
Package: util.ToPtr(memberPkgPath),
Name: util.ToPtr(member.Name()),
})
case *types.Func:
var methodNames []string
if methodOverloads := expandGoptOverloadedMethod(member); len(methodOverloads) > 0 {
Expand All @@ -244,32 +244,36 @@ func (s *Server) spxGetDefinitions(params []SpxGetDefinitionsParams) ([]SpxDefin
}

for _, methodName := range methodNames {
funcName, overloadID := parseGopFuncName(methodName)
if _, ok := calledEventHandlers[named.String()+"."+funcName]; ok {
parsedName, overloadID := parseGopFuncName(methodName)
if _, ok := calledEventHandlers[named.String()+"."+parsedName]; ok {
return
}

receiverName := named.Obj().Name()
recvTypeName := named.Obj().Name()
if memberPkgPath == spxPkgPath {
if receiverName != "SpriteImpl" && receiverName != "Game" {
if recvTypeName != "SpriteImpl" && recvTypeName != "Game" {
for _, namedParent := range namedParents {
if namedParent.Obj().Pkg().Path() != spxPkgPath {
continue
}

namedParentName := namedParent.Obj().Name()
if namedParentName == "SpriteImpl" || namedParentName == "Game" {
receiverName = namedParentName
recvTypeName = namedParentName
break
}
}
}
if receiverName == "SpriteImpl" {
receiverName = "Sprite"
if recvTypeName == "SpriteImpl" {
recvTypeName = "Sprite"
}
}

addDefinition(memberPkgPath, receiverName+"."+funcName, overloadID)
addDefinitionID(SpxDefinitionIdentifier{
Package: util.ToPtr(memberPkgPath),
Name: util.ToPtr(recvTypeName + "." + parsedName),
OverloadID: overloadID,
})
}
}
})
Expand All @@ -287,35 +291,26 @@ func (s *Server) spxGetDefinitions(params []SpxGetDefinitionsParams) ([]SpxDefin
}

if obj.Exported() {
addDefinition(spxPkgPath, name, overloadID)
addDefinitionID(SpxDefinitionIdentifier{
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr(name),
OverloadID: overloadID,
})
}
}
}

// Add builtin definitions.
for _, name := range types.Universe.Names() {
if obj := types.Universe.Lookup(name); obj != nil && obj.Pkg() == nil {
addDefinition("builtin", obj.Name(), nil)
}
}

// Add other definitions.
for _, def := range generalDefinitions {
addDefinition("", *def.Name, nil)
for _, def := range GetSpxBuiltinDefinitions() {
addDefinitionID(def.ID)
}
for _, def := range SpxGeneralDefinitions {
addDefinitionID(def.ID)
}
if innermostScope == astFileScope {
addDefinition("", "func_declaration", nil)
for _, def := range SpxFileScopeDefinitions {
addDefinitionID(def.ID)
}
}

return definitions, nil
}

// generalDefinitions are general definitions that are scope-independent.
var generalDefinitions = []SpxDefinitionIdentifier{
{Name: toStringPtr("for_iterate")},
{Name: toStringPtr("for_loop_with_condition")},
{Name: toStringPtr("for_loop_with_range")},
{Name: toStringPtr("if_statement")},
{Name: toStringPtr("if_else_statement")},
{Name: toStringPtr("var_declaration")},
return definitionIDs, nil
}
107 changes: 54 additions & 53 deletions tools/spxls/internal/server/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"slices"
"testing"

"github.com/goplus/builder/tools/spxls/internal/util"
"github.com/goplus/builder/tools/spxls/internal/vfs"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -41,30 +42,30 @@ onStart => {
require.NoError(t, err)
require.NotNil(t, mainSpxFileScopeDefs)
assert.True(t, spxDefinitionIdentifierSliceContains(mainSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr("builtin"),
Name: toStringPtr("println"),
Package: util.ToPtr("builtin"),
Name: util.ToPtr("println"),
}))
assert.True(t, spxDefinitionIdentifierSliceContains(mainSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr("main"),
Name: toStringPtr("MySprite"),
Package: util.ToPtr("main"),
Name: util.ToPtr("MySprite"),
}))
assert.True(t, spxDefinitionIdentifierSliceContains(mainSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Game.play"),
OverloadID: toStringPtr("1"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Game.play"),
OverloadID: util.ToPtr("1"),
}))
assert.True(t, spxDefinitionIdentifierSliceContains(mainSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Game.onStart"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Game.onStart"),
}))
assert.False(t, spxDefinitionIdentifierSliceContains(mainSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Sprite.turn"),
OverloadID: toStringPtr("1"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Sprite.turn"),
OverloadID: util.ToPtr("1"),
}))
assert.False(t, spxDefinitionIdentifierSliceContains(mainSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Sprite.onStart"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Sprite.onStart"),
}))

mySpriteSpxFileScopeParams := []SpxGetDefinitionsParams{
Expand All @@ -79,26 +80,26 @@ onStart => {
require.NoError(t, err)
require.NotNil(t, mySpriteSpxFileScopeDefs)
assert.True(t, spxDefinitionIdentifierSliceContains(mySpriteSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr("builtin"),
Name: toStringPtr("println"),
Package: util.ToPtr("builtin"),
Name: util.ToPtr("println"),
}))
assert.True(t, spxDefinitionIdentifierSliceContains(mySpriteSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Game.play"),
OverloadID: toStringPtr("1"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Game.play"),
OverloadID: util.ToPtr("1"),
}))
assert.False(t, spxDefinitionIdentifierSliceContains(mySpriteSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Game.onStart"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Game.onStart"),
}))
assert.True(t, spxDefinitionIdentifierSliceContains(mySpriteSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Sprite.turn"),
OverloadID: toStringPtr("1"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Sprite.turn"),
OverloadID: util.ToPtr("1"),
}))
assert.True(t, spxDefinitionIdentifierSliceContains(mySpriteSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Sprite.onStart"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Sprite.onStart"),
}))

mySpriteSpxOnStartScopeParams := []SpxGetDefinitionsParams{
Expand All @@ -113,31 +114,31 @@ onStart => {
require.NoError(t, err)
require.NotNil(t, mySpriteSpxOnStartScopeDefs)
assert.True(t, spxDefinitionIdentifierSliceContains(mySpriteSpxOnStartScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr("builtin"),
Name: toStringPtr("println"),
Package: util.ToPtr("builtin"),
Name: util.ToPtr("println"),
}))
assert.True(t, spxDefinitionIdentifierSliceContains(mySpriteSpxOnStartScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Game.play"),
OverloadID: toStringPtr("1"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Game.play"),
OverloadID: util.ToPtr("1"),
}))
assert.False(t, spxDefinitionIdentifierSliceContains(mySpriteSpxOnStartScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Game.onStart"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Game.onStart"),
}))
assert.True(t, spxDefinitionIdentifierSliceContains(mySpriteSpxOnStartScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Sprite.turn"),
OverloadID: toStringPtr("1"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Sprite.turn"),
OverloadID: util.ToPtr("1"),
}))
assert.False(t, spxDefinitionIdentifierSliceContains(mySpriteSpxOnStartScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Sprite.onStart"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Sprite.onStart"),
}))
assert.True(t, spxDefinitionIdentifierSliceContains(mySpriteSpxOnStartScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Sprite.clone"),
OverloadID: toStringPtr("1"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Sprite.clone"),
OverloadID: util.ToPtr("1"),
}))
})

Expand Down Expand Up @@ -174,21 +175,21 @@ onStart => {
require.NoError(t, err)
require.NotNil(t, mainSpxFileScopeDefs)
assert.True(t, spxDefinitionIdentifierSliceContains(mainSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Game.play"),
OverloadID: toStringPtr("1"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Game.play"),
OverloadID: util.ToPtr("1"),
}))
assert.False(t, spxDefinitionIdentifierSliceContains(mainSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Game.onStart"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Game.onStart"),
}))
assert.True(t, spxDefinitionIdentifierSliceContains(mainSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Sprite.onStart"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Sprite.onStart"),
}))
assert.True(t, spxDefinitionIdentifierSliceContains(mainSpxFileScopeDefs, SpxDefinitionIdentifier{
Package: toStringPtr(spxPkgPath),
Name: toStringPtr("Sprite.onClick"),
Package: util.ToPtr(spxPkgPath),
Name: util.ToPtr("Sprite.onClick"),
}))
})
}
Expand All @@ -197,8 +198,8 @@ onStart => {
// contains a specific [SpxDefinitionIdentifier].
func spxDefinitionIdentifierSliceContains(defs []SpxDefinitionIdentifier, def SpxDefinitionIdentifier) bool {
return slices.ContainsFunc(defs, func(d SpxDefinitionIdentifier) bool {
return fromStringPtr(d.Package) == fromStringPtr(def.Package) &&
fromStringPtr(d.Name) == fromStringPtr(def.Name) &&
fromStringPtr(d.OverloadID) == fromStringPtr(def.OverloadID)
return util.FromPtr(d.Package) == util.FromPtr(def.Package) &&
util.FromPtr(d.Name) == util.FromPtr(def.Name) &&
util.FromPtr(d.OverloadID) == util.FromPtr(def.OverloadID)
})
}
Loading

0 comments on commit b64a5ab

Please sign in to comment.