1
- use std:: collections:: HashMap ;
1
+ use std:: collections:: { HashMap , HashSet } ;
2
2
3
3
use emmylua_code_analysis:: {
4
- LuaCompilation , LuaDeclId , LuaMemberId , LuaMemberKey , LuaSemanticDeclId , LuaTypeDeclId ,
5
- SemanticDeclLevel , SemanticModel ,
4
+ DeclReference , LuaCompilation , LuaDeclId , LuaMemberId , LuaMemberKey , LuaSemanticDeclId ,
5
+ LuaTypeDeclId , SemanticDeclLevel , SemanticModel ,
6
6
} ;
7
7
use emmylua_parser:: {
8
- LuaAst , LuaAstNode , LuaAstToken , LuaNameToken , LuaStringToken , LuaSyntaxNode , LuaSyntaxToken ,
8
+ LuaAssignStat , LuaAst , LuaAstNode , LuaAstToken , LuaNameToken , LuaStringToken , LuaSyntaxNode ,
9
+ LuaSyntaxToken ,
9
10
} ;
10
11
use lsp_types:: Location ;
11
12
@@ -20,7 +21,7 @@ pub fn search_references(
20
21
{
21
22
match semantic_decl {
22
23
LuaSemanticDeclId :: LuaDecl ( decl_id) => {
23
- search_decl_references ( semantic_model, decl_id, & mut result) ;
24
+ search_decl_references ( semantic_model, compilation , decl_id, & mut result) ;
24
25
}
25
26
LuaSemanticDeclId :: Member ( member_id) => {
26
27
search_member_references ( semantic_model, compilation, member_id, & mut result) ;
@@ -36,11 +37,16 @@ pub fn search_references(
36
37
fuzzy_search_references ( compilation, token, & mut result) ;
37
38
}
38
39
40
+ // 简单过滤, 同行的多个引用只保留一个
41
+ // let filtered_result = filter_duplicate_and_covered_locations(result);
42
+ // Some(filtered_result)
43
+
39
44
Some ( result)
40
45
}
41
46
42
47
pub fn search_decl_references (
43
48
semantic_model : & SemanticModel ,
49
+ compilation : & LuaCompilation ,
44
50
decl_id : LuaDeclId ,
45
51
result : & mut Vec < Location > ,
46
52
) -> Option < ( ) > {
@@ -58,9 +64,15 @@ pub fn search_decl_references(
58
64
if let Some ( location) = document. to_lsp_location ( decl. get_range ( ) ) {
59
65
result. push ( location) ;
60
66
}
67
+ let typ = semantic_model. get_type ( decl. get_id ( ) . into ( ) ) ;
68
+ let is_signature = typ. is_signature ( ) ;
69
+
61
70
for decl_ref in decl_refs {
62
71
let location = document. to_lsp_location ( decl_ref. range . clone ( ) ) ?;
63
72
result. push ( location) ;
73
+ if is_signature {
74
+ get_signature_decl_member_references ( semantic_model, compilation, result, decl_ref) ;
75
+ }
64
76
}
65
77
66
78
return Some ( ( ) ) ;
@@ -119,7 +131,7 @@ pub fn search_member_references(
119
131
let range = in_filed_syntax_id. value . get_range ( ) ;
120
132
let location = document. to_lsp_location ( range) ?;
121
133
result. push ( location) ;
122
- search_member_secondary_references ( semantic_model, node, result) ;
134
+ search_member_secondary_references ( semantic_model, compilation , node, result) ;
123
135
}
124
136
}
125
137
@@ -128,6 +140,7 @@ pub fn search_member_references(
128
140
129
141
fn search_member_secondary_references (
130
142
semantic_model : & SemanticModel ,
143
+ compilation : & LuaCompilation ,
131
144
node : LuaSyntaxNode ,
132
145
result : & mut Vec < Location > ,
133
146
) -> Option < ( ) > {
@@ -141,7 +154,7 @@ fn search_member_secondary_references(
141
154
. position ( |value| value. get_position ( ) == position) ?;
142
155
let var = vars. get ( idx) ?;
143
156
let decl_id = LuaDeclId :: new ( semantic_model. get_file_id ( ) , var. get_position ( ) ) ;
144
- search_decl_references ( semantic_model, decl_id, result) ;
157
+ search_decl_references ( semantic_model, compilation , decl_id, result) ;
145
158
let document = semantic_model. get_document ( ) ;
146
159
let range = document. to_lsp_location ( var. get_range ( ) ) ?;
147
160
result. push ( range) ;
@@ -152,7 +165,7 @@ fn search_member_secondary_references(
152
165
let idx = values. position ( |value| value. get_position ( ) == position) ?;
153
166
let name = local_names. get ( idx) ?;
154
167
let decl_id = LuaDeclId :: new ( semantic_model. get_file_id ( ) , name. get_position ( ) ) ;
155
- search_decl_references ( semantic_model, decl_id, result) ;
168
+ search_decl_references ( semantic_model, compilation , decl_id, result) ;
156
169
let document = semantic_model. get_document ( ) ;
157
170
let range = document. to_lsp_location ( name. get_range ( ) ) ?;
158
171
result. push ( range) ;
@@ -241,3 +254,80 @@ fn search_type_decl_references(
241
254
242
255
Some ( ( ) )
243
256
}
257
+
258
+ fn get_signature_decl_member_references (
259
+ semantic_model : & SemanticModel ,
260
+ compilation : & LuaCompilation ,
261
+ result : & mut Vec < Location > ,
262
+ decl_ref : & DeclReference ,
263
+ ) -> Option < Vec < Location > > {
264
+ let root = semantic_model. get_root ( ) ;
265
+ let position = decl_ref. range . start ( ) ;
266
+ let token = root. syntax ( ) . token_at_offset ( position) . right_biased ( ) ?;
267
+ let parent = token. parent ( ) ?;
268
+
269
+ match parent. parent ( ) ? {
270
+ assign_stat_node if LuaAssignStat :: can_cast ( assign_stat_node. kind ( ) . into ( ) ) => {
271
+ let assign_stat = LuaAssignStat :: cast ( assign_stat_node) ?;
272
+ let ( vars, values) = assign_stat. get_var_and_expr_list ( ) ;
273
+ let idx = values
274
+ . iter ( )
275
+ . position ( |value| value. get_position ( ) == position) ?;
276
+ let var = vars. get ( idx) ?;
277
+ let decl_id = semantic_model
278
+ . find_decl ( var. syntax ( ) . clone ( ) . into ( ) , SemanticDeclLevel :: default ( ) ) ?;
279
+ if let LuaSemanticDeclId :: Member ( member_id) = decl_id {
280
+ search_member_references ( semantic_model, compilation, member_id, result) ;
281
+ }
282
+ }
283
+
284
+ _ => { }
285
+ }
286
+ None
287
+ }
288
+
289
+ #[ allow( unused) ]
290
+ fn filter_duplicate_and_covered_locations ( locations : Vec < Location > ) -> Vec < Location > {
291
+ if locations. is_empty ( ) {
292
+ return locations;
293
+ }
294
+ let mut sorted_locations = locations;
295
+ sorted_locations. sort_by ( |a, b| {
296
+ a. uri
297
+ . to_string ( )
298
+ . cmp ( & b. uri . to_string ( ) )
299
+ . then_with ( || a. range . start . line . cmp ( & b. range . start . line ) )
300
+ . then_with ( || b. range . end . line . cmp ( & a. range . end . line ) )
301
+ } ) ;
302
+
303
+ let mut result = Vec :: new ( ) ;
304
+ let mut seen_lines_by_uri: HashMap < String , HashSet < u32 > > = HashMap :: new ( ) ;
305
+
306
+ for location in sorted_locations {
307
+ let uri_str = location. uri . to_string ( ) ;
308
+ let seen_lines = seen_lines_by_uri. entry ( uri_str) . or_default ( ) ;
309
+
310
+ let start_line = location. range . start . line ;
311
+ let end_line = location. range . end . line ;
312
+
313
+ let is_covered = ( start_line..=end_line) . any ( |line| seen_lines. contains ( & line) ) ;
314
+
315
+ if !is_covered {
316
+ for line in start_line..=end_line {
317
+ seen_lines. insert ( line) ;
318
+ }
319
+ result. push ( location) ;
320
+ }
321
+ }
322
+
323
+ // 最终按位置排序
324
+ result. sort_by ( |a, b| {
325
+ a. uri
326
+ . to_string ( )
327
+ . cmp ( & b. uri . to_string ( ) )
328
+ . then_with ( || a. range . start . line . cmp ( & b. range . start . line ) )
329
+ . then_with ( || a. range . start . character . cmp ( & b. range . start . character ) )
330
+ } ) ;
331
+
332
+ result
333
+ }
0 commit comments