Skip to content

Commit 63d946b

Browse files
committed
fix private config
1 parent 29a772f commit 63d946b

File tree

6 files changed

+192
-101
lines changed

6 files changed

+192
-101
lines changed

crates/emmylua_code_analysis/src/db_index/property/mod.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ mod property;
22

33
use std::collections::{HashMap, HashSet};
44

5-
use emmylua_parser::{LuaVersionCondition, VisibilityKind};
6-
use property::LuaCommonProperty;
5+
use emmylua_parser::{LuaAstNode, LuaDocTagField, LuaDocType, LuaVersionCondition, VisibilityKind};
6+
pub use property::LuaCommonProperty;
77
pub use property::{LuaDeprecated, LuaExport, LuaExportScope, LuaPropertyId};
88

9-
use crate::{db_index::property::property::LuaTagContent, FileId};
9+
use crate::{
10+
db_index::property::property::LuaTagContent, DbIndex, FileId, LuaMember, LuaSignatureId,
11+
};
1012

1113
use super::{traits::LuaIndex, LuaSemanticDeclId};
1214

@@ -240,3 +242,34 @@ impl LuaIndex for LuaPropertyIndex {
240242
self.id_count = 0;
241243
}
242244
}
245+
246+
/// 尝试从 @field 定义中提取函数类型的位置信息
247+
pub fn try_extract_signature_id_from_field(
248+
db: &DbIndex,
249+
member: &LuaMember,
250+
) -> Option<LuaSignatureId> {
251+
// 检查是否是 field 定义
252+
if !member.is_field() {
253+
return None;
254+
}
255+
256+
let root = db
257+
.get_vfs()
258+
.get_syntax_tree(&member.get_file_id())?
259+
.get_red_root();
260+
let field_node = member.get_syntax_id().to_node_from_root(&root)?;
261+
262+
// 尝试转换为 LuaDocTagField
263+
let field_tag = LuaDocTagField::cast(field_node)?;
264+
265+
// 获取类型定义
266+
let type_node = field_tag.get_type()?;
267+
268+
match &type_node {
269+
LuaDocType::Func(doc_func) => Some(LuaSignatureId::from_doc_func(
270+
member.get_file_id(),
271+
&doc_func,
272+
)),
273+
_ => None,
274+
}
275+
}

crates/emmylua_code_analysis/src/semantic/visibility/mod.rs

Lines changed: 88 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ use emmylua_parser::{
55
LuaSyntaxToken, LuaVarExpr, VisibilityKind,
66
};
77

8-
use crate::{DbIndex, Emmyrc, FileId, LuaMemberOwner, LuaSemanticDeclId, LuaType};
8+
use crate::{
9+
try_extract_signature_id_from_field, DbIndex, Emmyrc, FileId, LuaCommonProperty,
10+
LuaMemberOwner, LuaSemanticDeclId, LuaType,
11+
};
912

1013
use super::{infer_expr, type_check::is_sub_type_of, LuaInferCache};
1114

@@ -19,7 +22,13 @@ pub fn check_visibility(
1922
token: LuaSyntaxToken,
2023
property_owner: LuaSemanticDeclId,
2124
) -> Option<bool> {
22-
let property = db.get_property_index().get_property(&property_owner)?;
25+
let property = match get_property(db, &property_owner) {
26+
Some(property) => property,
27+
None => {
28+
return check_member_name(db, file_id, emmyrc, infer_config, token, property_owner);
29+
}
30+
};
31+
2332
if let Some(version_conds) = &property.version_conds {
2433
let version_number = emmyrc.runtime.version.to_lua_version_number();
2534
let visible = version_conds.iter().any(|cond| cond.check(&version_number));
@@ -59,37 +68,7 @@ pub fn check_visibility(
5968
}
6069
}
6170

62-
if let LuaSemanticDeclId::Member(member_id) = property_owner {
63-
if let Some(member) = db.get_member_index().get_member(&member_id) {
64-
if let Some(name) = member.get_key().get_name() {
65-
let config = emmyrc;
66-
for pattern in &config.doc.private_name {
67-
let is_match = if let Some(prefix) = pattern.strip_suffix('*') {
68-
name.starts_with(prefix)
69-
} else if let Some(suffix) = pattern.strip_prefix('*') {
70-
name.ends_with(suffix)
71-
} else {
72-
name == pattern
73-
};
74-
if is_match {
75-
return Some(
76-
check_visibility_by_visibility(
77-
db,
78-
infer_config,
79-
file_id,
80-
property_owner,
81-
token,
82-
VisibilityKind::Private,
83-
)
84-
.unwrap_or(false),
85-
);
86-
}
87-
}
88-
}
89-
}
90-
}
91-
92-
Some(true)
71+
check_member_name(db, file_id, emmyrc, infer_config, token, property_owner)
9372
}
9473

9574
fn check_visibility_by_visibility(
@@ -180,7 +159,7 @@ fn check_block_visibility(
180159
fn check_def_visibility(
181160
db: &DbIndex,
182161
infer_config: &mut LuaInferCache,
183-
file_id: FileId,
162+
_file_id: FileId,
184163
member_owner: &LuaMemberOwner,
185164
token: LuaGeneralToken,
186165
visibility: VisibilityKind,
@@ -189,9 +168,10 @@ fn check_def_visibility(
189168
let prefix_expr = index_expr.get_prefix_expr()?;
190169
let typ = infer_expr(db, infer_config, prefix_expr.into()).ok()?;
191170

192-
if !in_def_file(db, &typ, file_id) {
193-
return Some(false);
194-
}
171+
// 这是为解决 require 后仍然是`Def`类型的问题, 但现在不需要了, 不过还是留着以防万一
172+
// if !in_def_file(db, &typ, file_id) {
173+
// return Some(false);
174+
// }
195175

196176
match visibility {
197177
VisibilityKind::Protected => match (typ, member_owner) {
@@ -209,19 +189,77 @@ fn check_def_visibility(
209189
}
210190
}
211191

212-
fn in_def_file(db: &DbIndex, typ: &LuaType, file_id: FileId) -> bool {
213-
match typ {
214-
LuaType::Def(id) => {
215-
let decl = db.get_type_index().get_type_decl(id);
216-
if let Some(decl) = decl {
217-
decl.get_locations()
218-
.iter()
219-
.any(|location| location.file_id == file_id)
220-
} else {
221-
false
222-
}
192+
// fn in_def_file(db: &DbIndex, typ: &LuaType, file_id: FileId) -> bool {
193+
// match typ {
194+
// LuaType::Def(id) => {
195+
// let decl = db.get_type_index().get_type_decl(id);
196+
// if let Some(decl) = decl {
197+
// decl.get_locations()
198+
// .iter()
199+
// .any(|location| location.file_id == file_id)
200+
// } else {
201+
// false
202+
// }
203+
// }
204+
// LuaType::TableConst(in_file) => in_file.file_id == file_id,
205+
// _ => false,
206+
// }
207+
// }
208+
209+
fn get_property<'a>(
210+
db: &'a DbIndex,
211+
property_owner: &'a LuaSemanticDeclId,
212+
) -> Option<&'a LuaCommonProperty> {
213+
match db.get_property_index().get_property(&property_owner) {
214+
Some(common_property) => Some(common_property),
215+
None => {
216+
let LuaSemanticDeclId::Member(member_id) = property_owner else {
217+
return None;
218+
};
219+
let member = db.get_member_index().get_member(&member_id)?;
220+
let signature_id = try_extract_signature_id_from_field(db, member)?;
221+
db.get_property_index()
222+
.get_property(&LuaSemanticDeclId::Signature(signature_id))
223223
}
224-
LuaType::TableConst(in_file) => in_file.file_id == file_id,
225-
_ => false,
226224
}
227225
}
226+
227+
fn check_member_name(
228+
db: &DbIndex,
229+
file_id: FileId,
230+
emmyrc: &Emmyrc,
231+
infer_config: &mut LuaInferCache,
232+
token: LuaSyntaxToken,
233+
property_owner: LuaSemanticDeclId,
234+
) -> Option<bool> {
235+
if let LuaSemanticDeclId::Member(member_id) = property_owner {
236+
if let Some(member) = db.get_member_index().get_member(&member_id) {
237+
if let Some(name) = member.get_key().get_name() {
238+
let config = emmyrc;
239+
for pattern in &config.doc.private_name {
240+
let is_match = if let Some(prefix) = pattern.strip_suffix('*') {
241+
name.starts_with(prefix)
242+
} else if let Some(suffix) = pattern.strip_prefix('*') {
243+
name.ends_with(suffix)
244+
} else {
245+
name == pattern
246+
};
247+
if is_match {
248+
return Some(
249+
check_visibility_by_visibility(
250+
db,
251+
infer_config,
252+
file_id,
253+
property_owner,
254+
token,
255+
VisibilityKind::Private,
256+
)
257+
.unwrap_or(false),
258+
);
259+
}
260+
}
261+
}
262+
}
263+
};
264+
Some(true)
265+
}

crates/emmylua_ls/src/handlers/completion/add_completions/add_member_completion.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
use emmylua_code_analysis::{
2-
DbIndex, LuaMemberInfo, LuaMemberKey, LuaSemanticDeclId, LuaType, SemanticModel,
2+
try_extract_signature_id_from_field, DbIndex, LuaMemberInfo, LuaMemberKey, LuaSemanticDeclId,
3+
LuaType, SemanticModel,
34
};
45
use emmylua_parser::{
56
LuaAssignStat, LuaAstNode, LuaAstToken, LuaFuncStat, LuaGeneralToken, LuaIndexExpr,
67
LuaParenExpr, LuaTokenKind,
78
};
89
use lsp_types::CompletionItem;
910

10-
use crate::handlers::{
11-
completion::{
12-
completion_builder::CompletionBuilder, completion_data::CompletionData,
13-
providers::get_function_remove_nil,
14-
},
15-
hover::try_extract_signature_id_from_field,
11+
use crate::handlers::completion::{
12+
completion_builder::CompletionBuilder, completion_data::CompletionData,
13+
providers::get_function_remove_nil,
1614
};
1715

1816
use super::{
@@ -361,7 +359,8 @@ pub fn extract_index_member_alias(
361359
None => {
362360
// field定义的`signature`的`common_property`绑定位置稍有不同, 需要特殊处理
363361
let member = db.get_member_index().get_member(member_id)?;
364-
let signature_id = try_extract_signature_id_from_field(semantic_model, member)?;
362+
let signature_id =
363+
try_extract_signature_id_from_field(semantic_model.get_db(), member)?;
365364
db.get_property_index()
366365
.get_property(&LuaSemanticDeclId::Signature(signature_id))?
367366
}

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

Lines changed: 4 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use std::collections::HashSet;
22

33
use emmylua_code_analysis::{
4-
humanize_type, DbIndex, LuaDocReturnInfo, LuaFunctionType, LuaMember, LuaMemberKey,
5-
LuaMemberOwner, LuaSemanticDeclId, LuaSignature, LuaSignatureId, LuaType, RenderLevel,
6-
SemanticModel,
4+
humanize_type, try_extract_signature_id_from_field, DbIndex, LuaDocReturnInfo, LuaFunctionType,
5+
LuaMember, LuaMemberKey, LuaMemberOwner, LuaSemanticDeclId, LuaSignature, LuaSignatureId,
6+
LuaType, RenderLevel,
77
};
8-
use emmylua_parser::{LuaAstNode, LuaDocTagField, LuaDocType};
98

109
use crate::handlers::{
1110
definition::extract_semantic_decl_from_signature,
@@ -76,9 +75,7 @@ pub fn hover_function_type(
7675
let member = db.get_member_index().get_member(&id)?;
7776
// 以 @field 定义的 function 描述信息绑定的 id 并不是 member, 需要特殊处理
7877
if is_new && function_info.description.is_none() {
79-
if let Some(signature_id) =
80-
try_extract_signature_id_from_field(builder.semantic_model, &member)
81-
{
78+
if let Some(signature_id) = try_extract_signature_id_from_field(db, &member) {
8279
function_info.description = extract_description_from_property_owner(
8380
&builder.semantic_model,
8481
&LuaSemanticDeclId::Signature(signature_id),
@@ -781,35 +778,3 @@ pub fn is_function(typ: &LuaType) -> bool {
781778
_ => false,
782779
}
783780
}
784-
785-
/// 尝试从 @field 定义中提取函数类型的位置信息
786-
pub fn try_extract_signature_id_from_field(
787-
semantic_model: &SemanticModel,
788-
member: &LuaMember,
789-
) -> Option<LuaSignatureId> {
790-
// 检查是否是 field 定义
791-
if !member.is_field() {
792-
return None;
793-
}
794-
795-
let root = semantic_model
796-
.get_db()
797-
.get_vfs()
798-
.get_syntax_tree(&member.get_file_id())?
799-
.get_red_root();
800-
let field_node = member.get_syntax_id().to_node_from_root(&root)?;
801-
802-
// 尝试转换为 LuaDocTagField
803-
let field_tag = LuaDocTagField::cast(field_node)?;
804-
805-
// 获取类型定义
806-
let type_node = field_tag.get_type()?;
807-
808-
match &type_node {
809-
LuaDocType::Func(doc_func) => Some(LuaSignatureId::from_doc_func(
810-
member.get_file_id(),
811-
&doc_func,
812-
)),
813-
_ => None,
814-
}
815-
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use build_hover::build_semantic_info_hover;
1111
use emmylua_code_analysis::{EmmyLuaAnalysis, FileId};
1212
use emmylua_parser::LuaAstNode;
1313
pub use find_origin::{find_all_same_named_members, find_member_origin_owner};
14-
pub use function_humanize::try_extract_signature_id_from_field;
1514
pub use hover_builder::HoverBuilder;
1615
pub use hover_humanize::infer_prefix_global_name;
1716
use keyword_hover::{hover_keyword, is_keyword};

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,4 +1167,61 @@ mod tests {
11671167
},],
11681168
));
11691169
}
1170+
1171+
#[test]
1172+
fn test_private_config() {
1173+
let mut ws = ProviderVirtualWorkspace::new();
1174+
let mut emmyrc = ws.get_emmyrc();
1175+
emmyrc.doc.private_name = vec!["_*".to_string()];
1176+
ws.update_emmyrc(emmyrc);
1177+
ws.def(
1178+
r#"
1179+
---@class A
1180+
---@field _abc number
1181+
---@field _next fun()
1182+
A = {}
1183+
"#,
1184+
);
1185+
assert!(ws.check_completion(
1186+
r#"
1187+
---@type A
1188+
local a
1189+
a.<??>
1190+
"#,
1191+
vec![],
1192+
));
1193+
assert!(!ws.check_completion(
1194+
r#"
1195+
A.<??>
1196+
"#,
1197+
vec![],
1198+
));
1199+
}
1200+
1201+
#[test]
1202+
fn test_require_private() {
1203+
let mut ws = ProviderVirtualWorkspace::new();
1204+
let mut emmyrc = ws.get_emmyrc();
1205+
emmyrc.doc.private_name = vec!["_*".to_string()];
1206+
ws.update_emmyrc(emmyrc);
1207+
ws.def_file(
1208+
"a.lua",
1209+
r#"
1210+
---@class A
1211+
---@field _next fun()
1212+
local A = {}
1213+
1214+
return {
1215+
A = A,
1216+
}
1217+
"#,
1218+
);
1219+
assert!(ws.check_completion(
1220+
r#"
1221+
local A = require("a").A
1222+
A.<??>
1223+
"#,
1224+
vec![],
1225+
));
1226+
}
11701227
}

0 commit comments

Comments
 (0)