Skip to content

Commit 7317314

Browse files
committed
goto_def_definition 可以跳转到实例的定义
1 parent c8b41ca commit 7317314

File tree

7 files changed

+276
-140
lines changed

7 files changed

+276
-140
lines changed

crates/emmylua_ls/src/handlers/definition/goto_def_definition.rs

Lines changed: 100 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
use std::str::FromStr;
22

3-
use emmylua_code_analysis::{LuaSemanticDeclId, LuaType, LuaTypeDeclId, SemanticModel};
4-
use emmylua_parser::{LuaAstNode, LuaAstToken, LuaCallExpr, LuaExpr, LuaStringToken};
3+
use emmylua_code_analysis::{
4+
LuaDeclId, LuaMemberId, LuaMemberInfo, LuaMemberKey, LuaSemanticDeclId, LuaType, LuaTypeDeclId,
5+
SemanticDeclLevel, SemanticModel,
6+
};
7+
use emmylua_parser::{
8+
LuaAstNode, LuaAstToken, LuaCallExpr, LuaExpr, LuaIndexExpr, LuaStringToken, LuaSyntaxToken,
9+
LuaTableExpr,
10+
};
511
use lsp_types::{GotoDefinitionResponse, Location, Position, Range, Uri};
612

13+
use crate::handlers::hover::find_member_origin_owner;
14+
715
pub fn goto_def_definition(
816
semantic_model: &SemanticModel,
917
property_owner: LuaSemanticDeclId,
18+
trigger_token: &LuaSyntaxToken,
1019
) -> Option<GotoDefinitionResponse> {
1120
if let Some(property) = semantic_model
1221
.get_db()
@@ -31,20 +40,48 @@ pub fn goto_def_definition(
3140
return Some(GotoDefinitionResponse::Scalar(location));
3241
}
3342
LuaSemanticDeclId::Member(member_id) => {
34-
let member = semantic_model
43+
if let Some(property_owner) = find_member_origin_owner(semantic_model, member_id) {
44+
return goto_def_definition(semantic_model, property_owner, trigger_token);
45+
}
46+
47+
let member_key = semantic_model
3548
.get_db()
3649
.get_member_index()
37-
.get_member(&member_id)?;
38-
let document = semantic_model.get_document_by_file_id(member_id.file_id)?;
39-
let location = document.to_lsp_location(member.get_range())?;
40-
return Some(GotoDefinitionResponse::Scalar(location));
50+
.get_member(&member_id)?
51+
.get_key();
52+
53+
let mut locations: Vec<Location> = Vec::new();
54+
55+
// 添加原始成员的位置
56+
if let Some(location) = get_member_location(semantic_model, &member_id) {
57+
locations.push(location);
58+
}
59+
60+
// 查找实体的定义, 例如在 ---@field 时声明, obj = {} 时实际定义
61+
if let Some(table_field_info) =
62+
find_table_member_definition(semantic_model, trigger_token, member_key)
63+
{
64+
if let Some(LuaSemanticDeclId::Member(table_member_id)) =
65+
table_field_info.property_owner_id
66+
{
67+
if let Some(location) = get_member_location(semantic_model, &table_member_id) {
68+
if !locations.contains(&location) {
69+
locations.push(location);
70+
}
71+
}
72+
}
73+
}
74+
75+
if !locations.is_empty() {
76+
return Some(GotoDefinitionResponse::Array(locations));
77+
}
4178
}
4279
LuaSemanticDeclId::TypeDecl(type_decl_id) => {
4380
let type_decl = semantic_model
4481
.get_db()
4582
.get_type_index()
4683
.get_type_decl(&type_decl_id)?;
47-
let mut locations = Vec::new();
84+
let mut locations: Vec<Location> = Vec::new();
4885
for lua_location in type_decl.get_locations() {
4986
let document = semantic_model.get_document_by_file_id(lua_location.file_id)?;
5087
let location = document.to_lsp_location(lua_location.range)?;
@@ -55,7 +92,6 @@ pub fn goto_def_definition(
5592
}
5693
_ => {}
5794
}
58-
5995
None
6096
}
6197

@@ -142,3 +178,58 @@ pub fn goto_str_tpl_ref_definition(
142178

143179
None
144180
}
181+
182+
fn find_table_member_definition(
183+
semantic_model: &SemanticModel,
184+
trigger_token: &LuaSyntaxToken,
185+
member_key: &LuaMemberKey,
186+
) -> Option<LuaMemberInfo> {
187+
let index_expr = trigger_token.parent().and_then(LuaIndexExpr::cast)?;
188+
let prefix_expr = index_expr.get_prefix_expr()?;
189+
190+
let decl = semantic_model.find_decl(
191+
prefix_expr.syntax().clone().into(),
192+
SemanticDeclLevel::default(),
193+
);
194+
195+
if let Some(LuaSemanticDeclId::LuaDecl(decl_id)) = decl {
196+
return find_member_in_table_decl(semantic_model, &decl_id, member_key);
197+
}
198+
199+
None
200+
}
201+
202+
fn find_member_in_table_decl(
203+
semantic_model: &SemanticModel,
204+
decl_id: &LuaDeclId,
205+
member_key: &LuaMemberKey,
206+
) -> Option<LuaMemberInfo> {
207+
let root = semantic_model
208+
.get_db()
209+
.get_vfs()
210+
.get_syntax_tree(&decl_id.file_id)?
211+
.get_red_root();
212+
213+
let node = semantic_model
214+
.get_db()
215+
.get_decl_index()
216+
.get_decl(decl_id)?
217+
.get_value_syntax_id()?
218+
.to_node_from_root(&root)?;
219+
220+
let table_expr = LuaTableExpr::cast(node)?;
221+
let typ = semantic_model
222+
.infer_expr(LuaExpr::TableExpr(table_expr))
223+
.ok()?;
224+
225+
let member_infos = semantic_model.get_member_infos(&typ)?;
226+
member_infos.iter().find(|m| m.key == *member_key).cloned()
227+
}
228+
229+
fn get_member_location(
230+
semantic_model: &SemanticModel,
231+
member_id: &LuaMemberId,
232+
) -> Option<Location> {
233+
let document = semantic_model.get_document_by_file_id(member_id.file_id)?;
234+
document.to_lsp_location(member_id.get_syntax_id().get_range())
235+
}

crates/emmylua_ls/src/handlers/definition/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ pub fn definition(
6767
if let Some(semantic_decl) =
6868
semantic_model.find_decl(token.clone().into(), SemanticDeclLevel::default())
6969
{
70-
return goto_def_definition(&semantic_model, semantic_decl);
70+
return goto_def_definition(&semantic_model, semantic_decl, &token);
7171
} else if let Some(string_token) = LuaStringToken::cast(token.clone()) {
7272
if let Some(module_response) = goto_module_file(&semantic_model, string_token.clone()) {
7373
return Some(module_response);

crates/emmylua_ls/src/handlers/hover/build_hover.rs

Lines changed: 134 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
use emmylua_code_analysis::{
22
DbIndex, LuaDeclId, LuaDocument, LuaMember, LuaMemberId, LuaMemberKey, LuaSemanticDeclId,
3-
LuaSignatureId, LuaType, LuaTypeDeclId, RenderLevel, SemanticInfo, SemanticModel,
3+
LuaSignatureId, LuaType, LuaTypeDeclId, RenderLevel, SemanticDeclLevel, SemanticInfo,
4+
SemanticModel,
5+
};
6+
use emmylua_parser::{
7+
LuaAssignStat, LuaAstNode, LuaExpr, LuaSyntaxKind, LuaSyntaxToken, LuaTableExpr, LuaTableField,
48
};
5-
use emmylua_parser::{LuaAssignStat, LuaAstNode, LuaExpr, LuaSyntaxToken};
69
use lsp_types::{Hover, HoverContents, MarkedString, MarkupContent};
10+
use std::collections::HashSet;
711

812
use emmylua_code_analysis::humanize_type;
913

10-
use crate::handlers::hover::{
11-
find_function_member_origin_owner, function_humanize::is_function,
12-
hover_humanize::hover_humanize_type,
13-
};
14+
use crate::handlers::hover::{function_humanize::is_function, hover_humanize::hover_humanize_type};
1415

1516
use super::{
16-
function_humanize::find_function_decl_origin_owner,
1717
hover_builder::HoverBuilder,
1818
hover_humanize::{hover_const_type, hover_function_type},
1919
};
@@ -119,8 +119,7 @@ fn build_decl_hover(
119119

120120
// 处理类型签名
121121
if is_function(&typ) {
122-
let origin_decl_id =
123-
find_function_decl_origin_owner(builder.semantic_model, decl_id.clone());
122+
let origin_decl_id = find_decl_origin_owner(builder.semantic_model, decl_id.clone());
124123
match origin_decl_id {
125124
Some(LuaSemanticDeclId::Member(member_id)) => {
126125
origin_member = Some(db.get_member_index().get_member(&member_id).unwrap());
@@ -209,7 +208,7 @@ fn build_member_hover(
209208
let mut origin_function_member = None;
210209
let mut origin_decl = None;
211210
if is_function(&typ) {
212-
let origin_decl_id = find_function_member_origin_owner(&builder.semantic_model, member_id);
211+
let origin_decl_id = find_member_origin_owner(&builder.semantic_model, member_id);
213212
match origin_decl_id {
214213
Some(LuaSemanticDeclId::Member(member_id)) => {
215214
origin_function_member = Some(db.get_member_index().get_member(&member_id)?);
@@ -383,3 +382,128 @@ pub fn get_hover_type(builder: &HoverBuilder, semantic_model: &SemanticModel) ->
383382

384383
None
385384
}
385+
386+
pub fn find_decl_origin_owner(
387+
semantic_model: &SemanticModel,
388+
decl_id: LuaDeclId,
389+
) -> Option<LuaSemanticDeclId> {
390+
let root = semantic_model
391+
.get_db()
392+
.get_vfs()
393+
.get_syntax_tree(&decl_id.file_id)?
394+
.get_red_root();
395+
let node = semantic_model
396+
.get_db()
397+
.get_decl_index()
398+
.get_decl(&decl_id)?
399+
.get_value_syntax_id()?
400+
.to_node_from_root(&root)?;
401+
let semantic_decl = semantic_model.find_decl(node.into(), SemanticDeclLevel::default());
402+
match semantic_decl {
403+
Some(LuaSemanticDeclId::Member(member_id)) => {
404+
find_member_origin_owner(semantic_model, member_id).or(semantic_decl)
405+
}
406+
Some(LuaSemanticDeclId::LuaDecl(_)) => semantic_decl,
407+
_ => None,
408+
}
409+
}
410+
411+
pub fn find_member_origin_owner(
412+
semantic_model: &SemanticModel,
413+
member_id: LuaMemberId,
414+
) -> Option<LuaSemanticDeclId> {
415+
const MAX_ITERATIONS: usize = 50;
416+
let mut visited_members = HashSet::new();
417+
418+
let mut current_owner = resolve_member_owner(semantic_model, &member_id);
419+
let mut final_owner = current_owner.clone();
420+
let mut iteration_count = 0;
421+
422+
while let Some(LuaSemanticDeclId::Member(current_member_id)) = &current_owner {
423+
if visited_members.contains(current_member_id) || iteration_count >= MAX_ITERATIONS {
424+
break;
425+
}
426+
427+
visited_members.insert(current_member_id.clone());
428+
iteration_count += 1;
429+
430+
match resolve_member_owner(semantic_model, current_member_id) {
431+
Some(next_owner) => {
432+
final_owner = Some(next_owner.clone());
433+
current_owner = Some(next_owner);
434+
}
435+
None => break,
436+
}
437+
}
438+
439+
final_owner
440+
}
441+
442+
fn resolve_member_owner(
443+
semantic_model: &SemanticModel,
444+
member_id: &LuaMemberId,
445+
) -> Option<LuaSemanticDeclId> {
446+
let root = semantic_model
447+
.get_db()
448+
.get_vfs()
449+
.get_syntax_tree(&member_id.file_id)?
450+
.get_red_root();
451+
let current_node = member_id.get_syntax_id().to_node_from_root(&root)?;
452+
match member_id.get_syntax_id().get_kind() {
453+
LuaSyntaxKind::TableFieldAssign => {
454+
if LuaTableField::can_cast(current_node.kind().into()) {
455+
let table_field = LuaTableField::cast(current_node.clone())?;
456+
// 如果表是类, 那么通过类型推断获取 owner
457+
if let Some(owner_id) =
458+
resolve_table_field_through_type_inference(semantic_model, &table_field)
459+
{
460+
return Some(owner_id);
461+
}
462+
// 非类, 那么通过右值推断
463+
let value_expr = table_field.get_value_expr()?;
464+
let value_node = value_expr.get_syntax_id().to_node_from_root(&root)?;
465+
semantic_model.find_decl(value_node.into(), SemanticDeclLevel::default())
466+
} else {
467+
None
468+
}
469+
}
470+
LuaSyntaxKind::IndexExpr => {
471+
let assign_node = current_node.parent()?;
472+
let assign_stat = LuaAssignStat::cast(assign_node)?;
473+
let (vars, exprs) = assign_stat.get_var_and_expr_list();
474+
475+
for (var, expr) in vars.iter().zip(exprs.iter()) {
476+
if var.syntax().text_range() == current_node.text_range() {
477+
let expr_node = expr.get_syntax_id().to_node_from_root(&root)?;
478+
return semantic_model
479+
.find_decl(expr_node.into(), SemanticDeclLevel::default());
480+
}
481+
}
482+
None
483+
}
484+
_ => None,
485+
}
486+
}
487+
488+
fn resolve_table_field_through_type_inference(
489+
semantic_model: &SemanticModel,
490+
table_field: &LuaTableField,
491+
) -> Option<LuaSemanticDeclId> {
492+
let parent = table_field.syntax().parent()?;
493+
let table_expr = LuaTableExpr::cast(parent)?;
494+
let table_type = semantic_model.infer_table_should_be(table_expr)?;
495+
496+
if !matches!(table_type, LuaType::Ref(_) | LuaType::Def(_)) {
497+
return None;
498+
}
499+
500+
let field_key = table_field.get_field_key()?;
501+
let key = semantic_model.get_member_key(&field_key)?;
502+
let member_infos = semantic_model.get_member_infos(&table_type)?;
503+
504+
member_infos
505+
.iter()
506+
.find(|m| m.key == key)?
507+
.property_owner_id
508+
.clone()
509+
}

0 commit comments

Comments
 (0)