Skip to content

Commit 790612e

Browse files
authored
fix:(rust) fix bugs (#11)
1 parent f0d9d08 commit 790612e

File tree

13 files changed

+113
-23
lines changed

13 files changed

+113
-23
lines changed

src/lang/collect/collect.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,6 @@ func (c *Collector) Collect(ctx context.Context) error {
250250
log.Error("dep token %v not found: %v\n", token, err)
251251
continue
252252
}
253-
// remove self
254-
if sym.Location.Include(dep.Location) {
255-
continue
256-
}
257253

258254
// NOTICE: some internal symbols may not been get by DocumentSymbols, thus we let Unknown symbol pass
259255
if dep.Kind == SKUnknown && c.internal(dep.Location) {
@@ -264,6 +260,14 @@ func (c *Collector) Collect(ctx context.Context) error {
264260
dep.Name = token.Text
265261
}
266262
}
263+
264+
// remove local symbols
265+
if sym.Location.Include(dep.Location) {
266+
continue
267+
} else {
268+
c.syms[dep.Location] = dep
269+
}
270+
267271
c.deps[sym] = append(c.deps[sym], dependency{
268272
Location: token.Location,
269273
Symbol: dep,

src/lang/collect/collect_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"encoding/json"
2020
"fmt"
2121
"os"
22+
"path/filepath"
2223
"testing"
2324
"time"
2425

@@ -31,8 +32,10 @@ var testroot = "../../../testdata"
3132

3233
func TestCollector_Collect(t *testing.T) {
3334
root := testroot + "/rust2"
35+
36+
root, _ = filepath.Abs(root)
3437
log.SetLogLevel(log.DebugLevel)
35-
rustLSP, err := lsp.NewLSPClient(root, root+"/src/main.rs", time.Second*15, lsp.ClientOptions{
38+
rustLSP, err := lsp.NewLSPClient(root, root+"/src/main.rs", time.Second*5, lsp.ClientOptions{
3639
Server: "rust-analyzer",
3740
Language: "rust",
3841
Verbose: true,

src/lang/collect/export.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ func (c *Collector) Export(ctx context.Context) (*uniast.Repository, error) {
7070
repo.Modules[name] = newModule(name, rel)
7171
}
7272

73+
// not allow local symbols inside another symbol
74+
c.filterLocalSymbols()
75+
7376
// export symbols
7477
for _, symbol := range c.syms {
7578
visited := make(map[*lsp.DocumentSymbol]*uniast.Identity)
@@ -90,6 +93,23 @@ func (c *Collector) Export(ctx context.Context) (*uniast.Repository, error) {
9093
return &repo, nil
9194
}
9295

96+
// NOTICE: for rust and golang, each entity has separate location
97+
// TODO: some language may allow local symbols inside another symbol,
98+
func (c *Collector) filterLocalSymbols() {
99+
// filter symbols
100+
for loc1 := range c.syms {
101+
for loc2 := range c.syms {
102+
if loc1 == loc2 {
103+
continue
104+
}
105+
if loc2.Include(loc1) {
106+
delete(c.syms, loc1)
107+
break
108+
}
109+
}
110+
}
111+
}
112+
93113
func (c *Collector) exportSymbol(repo *uniast.Repository, symbol *DocumentSymbol, refName string, visited map[*DocumentSymbol]*uniast.Identity) (*uniast.Identity, error) {
94114
if symbol == nil {
95115
return nil, errors.New("symbol is nil")

src/lang/lsp/client.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// Copyright 2025 CloudWeGo Authors
2-
//
2+
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
55
// You may obtain a copy of the License at
6-
//
6+
//
77
// https://www.apache.org/licenses/LICENSE-2.0
8-
//
8+
//
99
// Unless required by applicable law or agreed to in writing, software
1010
// distributed under the License is distributed on an "AS IS" BASIS,
1111
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -50,7 +50,7 @@ func NewLSPClient(repo string, openfile string, wait time.Duration, opts ClientO
5050
return nil, err
5151
}
5252

53-
cli, err := initLSPClient(context.Background(), svr, "file://"+repo, opts.Verbose)
53+
cli, err := initLSPClient(context.Background(), svr, lsp.DocumentURI(NewURI(repo)), opts.Verbose)
5454
if err != nil {
5555
return nil, err
5656
}
@@ -110,7 +110,7 @@ type initializeResult struct {
110110
Capabilities interface{} `json:"capabilities,omitempty"`
111111
}
112112

113-
func initLSPClient(ctx context.Context, svr io.ReadWriteCloser, dir string, verbose bool) (*LSPClient, error) {
113+
func initLSPClient(ctx context.Context, svr io.ReadWriteCloser, dir lsp.DocumentURI, verbose bool) (*LSPClient, error) {
114114
h := newLSPHandler()
115115
stream := jsonrpc2.NewBufferedStream(svr, jsonrpc2.VSCodeObjectCodec{})
116116
conn := jsonrpc2.NewConn(ctx, stream, h)
@@ -131,7 +131,7 @@ func initLSPClient(ctx context.Context, svr io.ReadWriteCloser, dir string, verb
131131

132132
initParams := initializeParams{
133133
ProcessID: os.Getpid(),
134-
RootURI: lsp.DocumentURI(dir),
134+
RootURI: dir,
135135
Capabilities: cs,
136136
Trace: lsp.Trace(trace),
137137
ClientInfo: lsp.ClientInfo{Name: "vscode"},

src/lang/lsp/client_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func TestRust(t *testing.T) {
220220

221221
// definition
222222
t.Run("definition", func(t *testing.T) {
223-
uri := NewURI("/root/codes/abcoder/testdata/rust2/src/main.rs")
223+
uri := NewURI(rootDir + "/rust2/src/main.rs")
224224
definition, err := rustLSP.Definition(context.Background(), uri, Position{9, 27})
225225
if err != nil {
226226
t.Fatalf("Find Definition failed: %v", err)

src/lang/lsp/lsp.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"fmt"
2121
"math"
2222
"os"
23+
"path/filepath"
2324
"sort"
2425
"strings"
2526

@@ -127,6 +128,9 @@ func (l DocumentURI) File() string {
127128
}
128129

129130
func NewURI(file string) DocumentURI {
131+
if !filepath.IsAbs(file) {
132+
file, _ = filepath.Abs(file)
133+
}
130134
return DocumentURI("file://" + file)
131135
}
132136

src/lang/lsp/spec.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ type LanguageSpec interface {
7676

7777
// if a symbol is a Function or Method symbol, return the token index of Receiver (-1 means not found),TypeParameters, InputParameters and Outputs
7878
FunctionSymbol(sym DocumentSymbol) (int, []int, []int, []int)
79+
80+
// Handle a unloaded internal symbol, like `lazy_static!` in rust
81+
GetUnloadedSymbol(from Token, define Location) (string, error)
7982
}
8083

8184
// Patcher is used to patch the AST of a module

src/lang/rust/get_merge_use.go renamed to src/lang/rust/ast.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,12 @@ package rust
1717
import (
1818
"bufio"
1919
"fmt"
20+
"os"
2021
"strings"
2122

23+
"github.com/cloudwego/abcoder/src/lang/lsp"
2224
"github.com/cloudwego/abcoder/src/lang/uniast"
25+
"github.com/cloudwego/abcoder/src/lang/utils"
2326
)
2427

2528
// UseNode represents a module node in the dependency tree
@@ -281,3 +284,47 @@ func GetRustContentDefine(name, fileContent string) (string, error) {
281284

282285
return buffer.String(), nil
283286
}
287+
288+
func ExtractLazyStaticeSymbol(loc lsp.Location) (string, error) {
289+
file := loc.URI.File()
290+
bs, err := os.ReadFile(file)
291+
if err != nil {
292+
return "", err
293+
}
294+
src := string(bs)
295+
lines := utils.CountLines(src)
296+
is := false
297+
for i := loc.Range.Start.Line; i >= 0; i-- {
298+
if strings.Contains(src[lines[i]:], "lazy_static::") || strings.Contains(src[lines[i]:], "lazy_static!") {
299+
is = true
300+
break
301+
}
302+
}
303+
if !is {
304+
return "", fmt.Errorf("not found lazy_static")
305+
}
306+
// find first `;` outside code block
307+
i := lines[loc.Range.Start.Line]
308+
count := 0
309+
codes := ""
310+
ss := src[i:]
311+
for x, c := range ss {
312+
if c == '{' {
313+
count++
314+
}
315+
if c == '}' {
316+
count--
317+
}
318+
if c == ';' && count == 0 {
319+
if x >= len(ss) {
320+
x = len(ss) - 1
321+
}
322+
codes = strings.TrimSpace(ss[:x+1])
323+
break
324+
}
325+
}
326+
if codes != "" {
327+
codes = fmt.Sprintf("lazy_static::lazy_static! {\n%s\n}", codes)
328+
}
329+
return codes, nil
330+
}
File renamed without changes.

src/lang/rust/patch.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ type RustModulePatcher struct {
2727
}
2828

2929
func (p *RustModulePatcher) Patch(ast *uniast.Module) {
30-
filepath.Walk(p.Root, func(path string, info os.FileInfo, err error) error {
30+
if ast.Dir == "" {
31+
return
32+
}
33+
filepath.Walk(filepath.Join(p.Root, ast.Dir), func(path string, info os.FileInfo, err error) error {
3134
if err != nil {
3235
return err
3336
}

0 commit comments

Comments
 (0)