Skip to content

Commit a2c722d

Browse files
committed
fix #572
1 parent 930b63e commit a2c722d

File tree

2 files changed

+175
-65
lines changed

2 files changed

+175
-65
lines changed
Lines changed: 139 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use emmylua_code_analysis::{
22
enum_variable_is_param, DbIndex, LuaMemberInfo, LuaSemanticDeclId, LuaType, LuaTypeDeclId,
3+
SemanticModel,
34
};
45
use emmylua_parser::{LuaAstNode, LuaAstToken, LuaIndexExpr, LuaStringToken};
56

@@ -40,7 +41,11 @@ pub fn add_completion(builder: &mut CompletionBuilder) -> Option<()> {
4041
}
4142

4243
let member_info_map = builder.semantic_model.get_member_info_map(&prefix_type)?;
43-
for (_, member_infos) in member_info_map.iter() {
44+
// 排序
45+
let mut sorted_entries: Vec<_> = member_info_map.iter().collect();
46+
sorted_entries.sort_unstable_by(|(name1, _), (name2, _)| name1.cmp(name2));
47+
48+
for (_, member_infos) in sorted_entries {
4449
add_resolve_member_infos(builder, &member_infos, completion_status);
4550
}
4651

@@ -53,11 +58,28 @@ fn add_resolve_member_infos(
5358
completion_status: CompletionTriggerStatus,
5459
) -> Option<()> {
5560
if member_infos.len() == 1 {
56-
let overload_count = count_function_overloads(
57-
builder.semantic_model.get_db(),
58-
&member_infos.iter().map(|info| info).collect::<Vec<_>>(),
59-
);
6061
let member_info = &member_infos[0];
62+
let overload_count = match &member_info.typ {
63+
LuaType::DocFunction(_) => None,
64+
LuaType::Signature(id) => {
65+
if let Some(signature) = builder
66+
.semantic_model
67+
.get_db()
68+
.get_signature_index()
69+
.get(&id)
70+
{
71+
let count = signature.overloads.len();
72+
if count == 0 {
73+
None
74+
} else {
75+
Some(count)
76+
}
77+
} else {
78+
None
79+
}
80+
}
81+
_ => None,
82+
};
6183
add_member_completion(
6284
builder,
6385
member_info.clone(),
@@ -67,46 +89,12 @@ fn add_resolve_member_infos(
6789
return Some(());
6890
}
6991

70-
let mut resolve_state = MemberResolveState::All;
71-
if builder
72-
.semantic_model
73-
.get_db()
74-
.get_emmyrc()
75-
.strict
76-
.meta_override_file_define
77-
{
78-
for member_info in member_infos {
79-
match member_info.feature {
80-
Some(feature) => {
81-
if feature.is_meta_decl() {
82-
resolve_state = MemberResolveState::Meta;
83-
break;
84-
} else if feature.is_file_decl() {
85-
resolve_state = MemberResolveState::FileDecl;
86-
}
87-
}
88-
None => {}
89-
}
90-
}
91-
}
92-
93-
// 屏蔽掉父类成员
94-
let first_owner = get_owner_type_id(builder.semantic_model.get_db(), member_infos.first()?);
95-
let member_infos: Vec<&LuaMemberInfo> = member_infos
96-
.iter()
97-
.filter(|member_info| {
98-
get_owner_type_id(builder.semantic_model.get_db(), member_info) == first_owner
99-
})
100-
.collect();
101-
102-
// 当全为`DocFunction`时, 只取第一个作为补全项
103-
let limit_doc_function = member_infos
104-
.iter()
105-
.all(|info| matches!(info.typ, LuaType::DocFunction(_)));
92+
let (filtered_member_infos, overload_count) =
93+
filter_member_infos(&builder.semantic_model, member_infos)?;
10694

107-
let overload_count = count_function_overloads(builder.semantic_model.get_db(), &member_infos);
95+
let resolve_state = get_resolve_state(builder.semantic_model.get_db(), &filtered_member_infos);
10896

109-
for member_info in member_infos {
97+
for member_info in filtered_member_infos {
11098
match resolve_state {
11199
MemberResolveState::All => {
112100
add_member_completion(
@@ -115,9 +103,6 @@ fn add_resolve_member_infos(
115103
completion_status,
116104
overload_count,
117105
);
118-
if limit_doc_function {
119-
break;
120-
}
121106
}
122107
MemberResolveState::Meta => {
123108
if let Some(feature) = member_info.feature {
@@ -128,9 +113,6 @@ fn add_resolve_member_infos(
128113
completion_status,
129114
overload_count,
130115
);
131-
if limit_doc_function {
132-
break;
133-
}
134116
}
135117
}
136118
}
@@ -143,9 +125,6 @@ fn add_resolve_member_infos(
143125
completion_status,
144126
overload_count,
145127
);
146-
if limit_doc_function {
147-
break;
148-
}
149128
}
150129
}
151130
}
@@ -155,30 +134,105 @@ fn add_resolve_member_infos(
155134
Some(())
156135
}
157136

158-
fn count_function_overloads(db: &DbIndex, member_infos: &Vec<&LuaMemberInfo>) -> Option<usize> {
159-
let mut count = 0;
137+
/// 过滤成员信息,返回需要的成员列表和重载数量
138+
fn filter_member_infos<'a>(
139+
semantic_model: &SemanticModel,
140+
member_infos: &'a Vec<LuaMemberInfo>,
141+
) -> Option<(Vec<&'a LuaMemberInfo>, Option<usize>)> {
142+
if member_infos.is_empty() {
143+
return None;
144+
}
145+
146+
let mut file_decl_member: Option<&LuaMemberInfo> = None;
147+
let mut member_with_owners: Vec<(&LuaMemberInfo, Option<LuaTypeDeclId>)> =
148+
Vec::with_capacity(member_infos.len());
149+
let mut all_doc_function = true;
150+
let mut overload_count = 0;
151+
152+
// 一次遍历收集所有信息
160153
for member_info in member_infos {
154+
let owner_id = get_owner_type_id(semantic_model.get_db(), member_info);
155+
member_with_owners.push((member_info, owner_id.clone()));
156+
157+
// 寻找第一个 file_decl 作为参考,如果没有则使用第一个
158+
if file_decl_member.is_none() {
159+
if let Some(feature) = member_info.feature {
160+
if feature.is_file_decl() {
161+
file_decl_member = Some(member_info);
162+
}
163+
}
164+
}
165+
166+
// 检查是否全为 DocFunction,同时计算重载数量
161167
match &member_info.typ {
162168
LuaType::DocFunction(_) => {
163-
count += 1;
169+
overload_count += 1;
164170
}
165171
LuaType::Signature(id) => {
166-
count += 1;
167-
if let Some(signature) = db.get_signature_index().get(&id) {
168-
count += signature.overloads.len();
172+
all_doc_function = false;
173+
overload_count += 1;
174+
if let Some(signature) = semantic_model.get_db().get_signature_index().get(&id) {
175+
overload_count += signature.overloads.len();
169176
}
170177
}
171-
_ => {}
178+
_ => {
179+
all_doc_function = false;
180+
}
172181
}
173182
}
174-
if count >= 1 {
175-
count -= 1;
176-
}
177-
if count == 0 {
178-
None
183+
184+
// 确定最终使用的参考 owner
185+
let final_reference_owner = if let Some(file_decl_member_info) = file_decl_member {
186+
// 与第一个成员进行类型检查, 确保子类成员的类型与父类成员的类型一致
187+
if let Some((first_member, first_owner)) = member_with_owners.first() {
188+
let type_check_result =
189+
semantic_model.type_check(&file_decl_member_info.typ, &first_member.typ);
190+
if type_check_result.is_ok() {
191+
get_owner_type_id(semantic_model.get_db(), file_decl_member_info)
192+
} else {
193+
first_owner.clone()
194+
}
195+
} else {
196+
get_owner_type_id(semantic_model.get_db(), file_decl_member_info)
197+
}
198+
} else {
199+
// 没有找到 file_decl,使用第一个成员作为参考
200+
member_with_owners
201+
.first()
202+
.map(|(_, owner)| owner.clone())
203+
.flatten()
204+
};
205+
206+
// 过滤出相同 owner_type_id 的成员
207+
let mut filtered_member_infos: Vec<&LuaMemberInfo> = member_with_owners
208+
.into_iter()
209+
.filter_map(|(member_info, owner_id)| {
210+
if owner_id == final_reference_owner {
211+
Some(member_info)
212+
} else {
213+
None
214+
}
215+
})
216+
.collect();
217+
218+
// 处理重载计数
219+
let final_overload_count = if overload_count >= 1 {
220+
let count = overload_count - 1;
221+
if count == 0 {
222+
None
223+
} else {
224+
Some(count)
225+
}
179226
} else {
180-
Some(count)
227+
None
228+
};
229+
230+
// 如果全为 DocFunction, 只保留第一个
231+
if all_doc_function && !filtered_member_infos.is_empty() {
232+
filtered_member_infos.truncate(1);
181233
}
234+
235+
Some((filtered_member_infos, final_overload_count))
182236
}
183237

184238
enum MemberResolveState {
@@ -198,3 +252,23 @@ fn get_owner_type_id(db: &DbIndex, info: &LuaMemberInfo) -> Option<LuaTypeDeclId
198252
_ => None,
199253
}
200254
}
255+
256+
fn get_resolve_state(db: &DbIndex, member_infos: &Vec<&LuaMemberInfo>) -> MemberResolveState {
257+
let mut resolve_state = MemberResolveState::All;
258+
if db.get_emmyrc().strict.meta_override_file_define {
259+
for member_info in member_infos.iter() {
260+
match member_info.feature {
261+
Some(feature) => {
262+
if feature.is_meta_decl() {
263+
resolve_state = MemberResolveState::Meta;
264+
break;
265+
} else if feature.is_file_decl() {
266+
resolve_state = MemberResolveState::FileDecl;
267+
}
268+
}
269+
None => {}
270+
}
271+
}
272+
}
273+
resolve_state
274+
}

crates/emmylua_ls/src/handlers/test/completion_test.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,4 +1095,40 @@ mod tests {
10951095
},],
10961096
));
10971097
}
1098+
1099+
#[test]
1100+
fn test_issue_572() {
1101+
let mut ws = ProviderVirtualWorkspace::new();
1102+
assert!(ws.check_completion(
1103+
r#"
1104+
---@class A
1105+
---@field optional_num number?
1106+
local a = {}
1107+
1108+
function a:set()
1109+
end
1110+
1111+
--- @class B : A
1112+
local b = {}
1113+
1114+
function b:set()
1115+
self.optional_num = 2
1116+
end
1117+
b.<??>
1118+
1119+
"#,
1120+
vec![
1121+
VirtualCompletionItem {
1122+
label: "optional_num".to_string(),
1123+
kind: CompletionItemKind::VARIABLE,
1124+
..Default::default()
1125+
},
1126+
VirtualCompletionItem {
1127+
label: "set".to_string(),
1128+
kind: CompletionItemKind::FUNCTION,
1129+
label_detail: Some("(self) -> nil".to_string()),
1130+
},
1131+
],
1132+
));
1133+
}
10981134
}

0 commit comments

Comments
 (0)