Skip to content

Commit 57e912d

Browse files
authored
Merge pull request #901 from xuhuanzy/update
update
2 parents e4b4e89 + 6c24bff commit 57e912d

File tree

16 files changed

+347
-304
lines changed

16 files changed

+347
-304
lines changed

crates/emmylua_code_analysis/src/diagnostic/checker/check_param_count.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ fn check_call_expr(
9696
let mut fake_params = func.get_params().to_vec();
9797
let call_args = call_expr.get_args_list()?.get_args().collect::<Vec<_>>();
9898
let mut call_args_count = call_args.len();
99+
let last_arg_is_dots = call_args.last().is_some_and(is_dots_expr);
99100
// 根据冒号定义与冒号调用的情况来调整调用参数的数量
100101
let colon_call = call_expr.is_colon_call();
101102
let colon_define = func.is_colon_define();
@@ -171,7 +172,16 @@ fn check_call_expr(
171172
}
172173
}
173174
// Check for redundant parameters
174-
else if call_args_count > fake_params.len() {
175+
else {
176+
let mut min_call_args_count = call_args_count;
177+
if last_arg_is_dots {
178+
min_call_args_count = min_call_args_count.saturating_sub(1);
179+
}
180+
181+
if min_call_args_count <= fake_params.len() {
182+
return Some(());
183+
}
184+
175185
// 参数定义中最后一个参数是 `...`
176186
if fake_params.last().is_some_and(|(name, typ)| {
177187
name == "..." || typ.as_ref().is_some_and(|typ| typ.is_variadic())
@@ -185,6 +195,10 @@ fn check_call_expr(
185195
}
186196

187197
for (i, arg) in call_args.iter().enumerate() {
198+
if last_arg_is_dots && i + 1 == call_args.len() {
199+
continue;
200+
}
201+
188202
let param_index = i as isize + adjusted_index;
189203

190204
if param_index < 0 || param_index < fake_params.len() as isize {
@@ -197,7 +211,7 @@ fn check_call_expr(
197211
t!(
198212
"expected %{num} parameters but found %{found_num}",
199213
num = fake_params.len(),
200-
found_num = call_args_count,
214+
found_num = min_call_args_count,
201215
)
202216
.to_string(),
203217
None,
@@ -208,6 +222,15 @@ fn check_call_expr(
208222
Some(())
209223
}
210224

225+
fn is_dots_expr(expr: &LuaExpr) -> bool {
226+
if let LuaExpr::LiteralExpr(literal_expr) = expr
227+
&& let Some(LuaLiteralToken::Dots(_)) = literal_expr.get_literal()
228+
{
229+
return true;
230+
}
231+
false
232+
}
233+
211234
fn get_params_len(params: &[(String, Option<LuaType>)]) -> Option<usize> {
212235
if let Some((name, typ)) = params.last() {
213236
// 如果最后一个参数是可变参数, 则直接返回, 不需要检查

crates/emmylua_code_analysis/src/diagnostic/test/redundant_parameter_test.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,20 @@ mod test {
159159
"#
160160
));
161161
}
162+
163+
#[test]
164+
fn test_issue_894() {
165+
let mut ws = VirtualWorkspace::new();
166+
ws.def(
167+
r#"
168+
_nop = function() end
169+
"#,
170+
);
171+
assert!(ws.check_code_for(
172+
DiagnosticCode::RedundantParameter,
173+
r#"
174+
function a(...) _nop(...) end
175+
"#
176+
));
177+
}
162178
}

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

Lines changed: 38 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use std::{collections::HashSet, sync::Arc, vec};
22

33
use emmylua_code_analysis::{
4-
AsyncState, DbIndex, InferGuard, LuaDocReturnInfo, LuaFunctionType, LuaMember, LuaMemberKey,
5-
LuaMemberOwner, LuaSemanticDeclId, LuaType, RenderLevel, TypeSubstitutor, VariadicType,
6-
humanize_type, infer_call_expr_func, instantiate_doc_function,
7-
try_extract_signature_id_from_field,
4+
AsyncState, DbIndex, InferGuard, LuaDocReturnInfo, LuaFunctionType, LuaMember, LuaMemberOwner,
5+
LuaSemanticDeclId, LuaType, RenderLevel, TypeSubstitutor, VariadicType, humanize_type,
6+
infer_call_expr_func, instantiate_doc_function, try_extract_signature_id_from_field,
87
};
98

109
use crate::handlers::hover::{
@@ -289,77 +288,69 @@ fn hover_doc_function_type(
289288
_ => "",
290289
};
291290
let mut is_method = func.is_colon_define();
292-
let mut type_label = "function ";
291+
let mut type_label = if is_local && owner_member.is_none() {
292+
"local function "
293+
} else {
294+
"function "
295+
};
296+
293297
// 有可能来源于类. 例如: `local add = class.add`, `add()`应被视为类方法
294298
let full_name = if let Some(owner_member) = owner_member {
295-
let mut name = String::new();
299+
if is_field {
300+
type_label = "(field) ";
301+
}
302+
303+
let member_key = owner_member.get_key().to_path();
304+
let mut name = String::with_capacity(member_key.len() + 16);
305+
306+
let mut push_typed_owner_prefix = |prefix: &str, type_decl_id| {
307+
name.push_str(prefix);
308+
let owner_ty = LuaType::Ref(type_decl_id);
309+
is_method = func.is_method(builder.semantic_model, Some(&owner_ty));
310+
if is_method {
311+
type_label = "(method) ";
312+
}
313+
name.push(if is_method { ':' } else { '.' });
314+
};
315+
296316
let parent_owner = db
297317
.get_member_index()
298318
.get_current_owner(&owner_member.get_id());
299319
if let Some(parent_owner) = parent_owner {
300320
match parent_owner {
301321
LuaMemberOwner::Type(type_decl_id) => {
302-
let global_name =
303-
infer_prefix_global_name(builder.semantic_model, owner_member);
304-
// 如果是全局定义, 则使用定义时的名称
305-
if let Some(global_name) = global_name {
306-
name.push_str(global_name);
307-
} else {
308-
name.push_str(type_decl_id.get_simple_name());
309-
}
310-
if is_field {
311-
type_label = "(field) ";
312-
}
313-
is_method = func.is_method(
314-
builder.semantic_model,
315-
Some(&LuaType::Ref(type_decl_id.clone())),
316-
);
317-
if is_method {
318-
type_label = "(method) ";
319-
name.push(':');
320-
} else {
321-
name.push('.');
322-
}
322+
let prefix = infer_prefix_global_name(builder.semantic_model, owner_member)
323+
.unwrap_or_else(|| type_decl_id.get_simple_name());
324+
push_typed_owner_prefix(prefix, type_decl_id.clone());
323325
}
324326
LuaMemberOwner::Element(element_id) => {
325327
if let Some(LuaType::Ref(type_decl_id) | LuaType::Def(type_decl_id)) =
326328
extract_parent_type_from_element(builder.semantic_model, element_id)
327329
{
328-
name.push_str(type_decl_id.get_simple_name());
329-
if is_field {
330-
type_label = "(field) ";
331-
}
332-
is_method = func.is_method(
333-
builder.semantic_model,
334-
Some(&LuaType::Ref(type_decl_id.clone())),
330+
push_typed_owner_prefix(
331+
type_decl_id.get_simple_name(),
332+
type_decl_id.clone(),
335333
);
336-
if is_method {
337-
type_label = "(method) ";
338-
name.push(':');
339-
} else {
340-
name.push('.');
341-
}
342334
} else if let Some(owner_name) =
343335
extract_owner_name_from_element(builder.semantic_model, element_id)
344336
{
345337
name.push_str(&owner_name);
346-
name.push('.');
338+
if is_method {
339+
type_label = "(method) ";
340+
}
341+
name.push(if is_method { ':' } else { '.' });
347342
}
348343
}
349344
_ => {}
350345
}
351346
}
352347

353-
if let LuaMemberKey::Name(n) = owner_member.get_key() {
354-
name.push_str(n.as_str());
355-
}
348+
name.push_str(&member_key);
356349
name
357350
} else {
358-
if is_local {
359-
type_label = "local function ";
360-
}
361351
func_name.to_string()
362352
};
353+
363354
let params = func
364355
.get_params()
365356
.iter()

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,4 +667,24 @@ mod tests {
667667
));
668668
Ok(())
669669
}
670+
671+
#[gtest]
672+
fn test_table_const_method() -> Result<()> {
673+
let mut ws = ProviderVirtualWorkspace::new();
674+
check!(ws.check_hover(
675+
r#"
676+
local M = {}
677+
678+
---@param x number
679+
function M:abc<??>d(x)
680+
end
681+
682+
M:abcd(1)
683+
"#,
684+
VirtualHoverResult {
685+
value: "```lua\n(method) M:abcd(x: number)\n```".to_string(),
686+
},
687+
));
688+
Ok(())
689+
}
670690
}

crates/emmylua_ls/std_i18n/builtin/meta.yaml

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -90,20 +90,20 @@ entries:
9090
line: 118
9191
col: 0
9292
end:
93-
line: 119
93+
line: 120
9494
col: 0
95-
hash: '38c2701334822d7a'
96-
context_hash: c1905bc5fdb3a411
95+
hash: b508ab78f8d1bc46
96+
context_hash: de7cc417de1b3246
9797
- key: std.Unpack
9898
kind:
9999
type: doc_block
100100
indent: ''
101101
range:
102102
start:
103-
line: 121
103+
line: 122
104104
col: 0
105105
end:
106-
line: 123
106+
line: 124
107107
col: 0
108108
hash: c7ad7bb74235dc8c
109109
context_hash: de7cc417de1b3246
@@ -113,10 +113,10 @@ entries:
113113
indent: ''
114114
range:
115115
start:
116-
line: 125
116+
line: 126
117117
col: 0
118118
end:
119-
line: 127
119+
line: 128
120120
col: 0
121121
hash: '7327558f3445dea6'
122122
context_hash: de7cc417de1b3246
@@ -126,10 +126,10 @@ entries:
126126
indent: ''
127127
range:
128128
start:
129-
line: 129
129+
line: 130
130130
col: 0
131131
end:
132-
line: 131
132+
line: 132
133133
col: 0
134134
hash: '0e263d1e0caa6b3b'
135135
context_hash: de7cc417de1b3246
@@ -139,36 +139,36 @@ entries:
139139
indent: ''
140140
range:
141141
start:
142-
line: 145
142+
line: 146
143143
col: 0
144144
end:
145-
line: 146
145+
line: 148
146146
col: 0
147-
hash: d949231b3fc3363d
148-
context_hash: ea58ce70c1a97a2a
147+
hash: '71b070c2fa27cbf9'
148+
context_hash: de7cc417de1b3246
149149
- key: ConstructorParameters
150150
kind:
151151
type: doc_block
152152
indent: ''
153153
range:
154154
start:
155-
line: 148
155+
line: 150
156156
col: 0
157157
end:
158-
line: 149
158+
line: 152
159159
col: 0
160-
hash: '6537def67aeb8537'
161-
context_hash: d32380b12ad01070
160+
hash: '2f4bebd14d7824cb'
161+
context_hash: de7cc417de1b3246
162162
- key: Partial
163163
kind:
164164
type: doc_block
165165
indent: ''
166166
range:
167167
start:
168-
line: 153
168+
line: 157
169169
col: 0
170170
end:
171-
line: 154
171+
line: 159
172172
col: 0
173-
hash: caabe7bd856c5ea6
174-
context_hash: '7f3cfe2b87b6d515'
173+
hash: '5e4213a7c3937182'
174+
context_hash: de7cc417de1b3246

crates/emmylua_ls/std_i18n/builtin/zh_CN.yaml

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@ boolean: |
77
都会使条件为假;任何其他值都会使条件为真。
88
99
number: |
10-
*number* 类型使用两种内部表示,或两个子类型,一个称为 *integer*,
11-
另一个称为 *float*。Lua 对何时使用哪种表示有明确的规则,但它也会
12-
根据需要在两者之间自动转换。因此,程序员可以选择大部分时候忽略整数
13-
和浮点数之间的差异,或者完全控制每个数字的表示。标准 Lua 使用64位
14-
整数和双精度(64位)浮点数,但你也可以编译 Lua 使其使用32位整数
15-
和/或单精度(32位)浮点数。对于小型机器和嵌入式系统,整数和浮点数
16-
都使用32位的选项特别有吸引力。(参见 luaconf.h 文件中的宏 LUA_32BITS。)
10+
**number** 类型在内部使用两种表示形式,或称为两种子类型,一种叫做
11+
*integer*,另一种叫做 *float*。Lua 对于何时使用哪种表示形式有明确的规则,
12+
但也会在需要时自动进行转换。因此,程序员可以选择忽略整数和浮点数之间的差异,
13+
也可以完全控制每个数字的表示形式。标准 Lua 使用 64 位整数和双精度(64 位)
14+
浮点数,但你也可以将 Lua 编译为使用 32 位整数和/或单精度(32 位)浮点数。
15+
对于小型机器和嵌入式系统来说,同时使用 32 位整数和 32 位浮点数的选项特别有吸引力。
16+
(参见 `luaconf.h` 文件中的宏 `LUA_32BITS`。)
1717
1818
userdata: |
1919
*userdata* 类型用于允许将任意 C 数据存储在 Lua 变量中。userdata 值
20-
表示一块原始内存。有两种 userdata:*完全 userdata*,是一个由 Lua
21-
管理内存块的对象;*轻量 userdata*,仅是一个 C 指针值。userdata 在
22-
Lua 中没有预定义的操作,除了赋值和身份测试。通过使用 *元表*,程序员
23-
可以为完全 userdata 值定义操作。userdata 值不能在 Lua 中创建或修改,
20+
表示一块原始内存。有两种 userdata:*full userdata*,是一个由 Lua
21+
管理内存块的对象;*light userdata*,它仅是一个 C 指针值。userdata 在
22+
Lua 中没有预定义的操作,除了赋值和相等性测试。通过使用 *metatables*,程序员
23+
可以为 full userdata 值定义操作。userdata 值不能在 Lua 中创建或修改,
2424
只能通过 C API 进行。这保证了宿主程序所拥有数据的完整性。
2525
2626
thread: |
@@ -32,15 +32,14 @@ table: |
3232
和 NaN 之外的任何 Lua 值的数组。(*NaN* 是 IEEE 754 标准用于表示
3333
未定义或不可表示的数值结果的特殊浮点值,例如 `0/0`。)表可以是异构的;
3434
也就是说,它们可以包含所有类型的值(除了 **nil**)。值为 **nil** 的
35-
任何键都不被视为表的一部分。相反,不属于表的任何键都有一个关联值 **nil**。
35+
任何键都不被视为表的一部分。相反,任何不属于表的键其关联值都为 **nil**。
3636
37-
表是 Lua 中唯一的数据组织机制;它们可以用来表示普通数组、列表、符号表、
37+
表是 Lua 中唯一的数据结构;它们可以用来表示普通数组、列表、符号表、
3838
集合、记录、图、树等。为了表示记录,Lua 使用字段名作为索引。语言通过
39-
提供 `a.name` 作为 `a["name"]` 的语法糖来支持这种表示。在 Lua 中有
40-
几种方便的方式来创建表。
39+
提供 `a.name` 作为 `a["name"]` 的语法糖来支持这种表示。
4140
42-
与索引一样,表字段的值可以是任何类型。特别是,由于函数是一等值,表
43-
字段可以包含函数。因此表也可以携带 *方法*。
41+
与索引一样,表字段的值可以是任何类型。特别地,由于函数是一等公民,表
42+
字段可以包含函数。因此表也可以携带 *methods*。
4443
4544
表的索引遵循语言中原始相等的定义。表达式 `a[i]` 和 `a[j]` 当且仅当
4645
`i` 和 `j` 原始相等(即不使用元方法的相等)时表示相同的表元素。特别地,

0 commit comments

Comments
 (0)