Skip to content

Commit 656a1e1

Browse files
committed
Removes skip_table_fields_check LSP optimization
1 parent 17e4c3f commit 656a1e1

10 files changed

Lines changed: 23 additions & 203 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
*All notable changes to the EmmyLua Analyzer Rust project will be documented in this file.*
44

5+
## [Unreleased]
6+
7+
### 🗑️ Removed
8+
9+
- **`lsp_optimization`**: Removed the `skip_table_fields_check` optimization (including the old `check_table_field` alias). Table field diagnostics are no longer skipped via this attribute.
10+
511
## [0.24.0] - 2026-7-10
612

713
### ✨ Added

crates/emmylua_code_analysis/resources/std/builtin.lua

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,10 @@
181181
--- Language Server Optimization Items.
182182
---
183183
--- Parameters:
184-
--- - `skip_table_fields_check`: Skip table field diagnostics. It is recommended to use this option for all large configuration tables.
185184
--- - `delayed_definition`: Indicates that the type of the variable is determined by the first assignment.
186185
--- Only valid for `local` declarations with no initial value.
187186
--- @class lsp_optimization: Attribute
188-
--- @overload fun(code: "skip_table_fields_check"|"delayed_definition")
187+
--- @overload fun(code: "delayed_definition")
189188

190189
---
191190
--- Index field alias, will be displayed in `hint` and `completion`.

crates/emmylua_code_analysis/src/compilation/test/attribute_test.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,6 @@ mod test {
3434
assert_eq!(ws.humanize_type(ty), "A");
3535
}
3636

37-
#[test]
38-
fn test_def_attribute() {
39-
let mut ws = VirtualWorkspace::new_with_init_std_lib();
40-
41-
ws.has_no_diagnostic(
42-
DiagnosticCode::AssignTypeMismatch,
43-
r#"
44-
---@[lsp_optimization("skip_table_fields_check")]
45-
local config = {}
46-
"#,
47-
);
48-
}
49-
5037
#[test]
5138
fn test_attribute_overload_uses_arg_type_for_diagnostic() {
5239
let mut ws = VirtualWorkspace::new();

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

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,6 @@ impl LuaAttributeUse {
189189
}
190190

191191
let code = match self.get_string_param("code")? {
192-
"skip_table_fields_check" | "check_table_field" => {
193-
LuaLspOptimizationCode::SkipTableFieldsCheck
194-
}
195192
"delayed_definition" => LuaLspOptimizationCode::DelayedDefinition,
196193
_ => return None,
197194
};
@@ -252,14 +249,12 @@ pub struct LuaDeprecatedAttribute<'a> {
252249

253250
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
254251
pub enum LuaLspOptimizationCode {
255-
SkipTableFieldsCheck,
256252
DelayedDefinition,
257253
}
258254

259255
impl LuaLspOptimizationCode {
260256
pub const fn as_str(self) -> &'static str {
261257
match self {
262-
Self::SkipTableFieldsCheck => "skip_table_fields_check",
263258
Self::DelayedDefinition => "delayed_definition",
264259
}
265260
}
@@ -271,10 +266,6 @@ pub struct LuaLspOptimizationAttribute {
271266
}
272267

273268
impl LuaLspOptimizationAttribute {
274-
pub fn is_skip_table_fields_check(self) -> bool {
275-
self.code == LuaLspOptimizationCode::SkipTableFieldsCheck
276-
}
277-
278269
pub fn is_delayed_definition(self) -> bool {
279270
self.code == LuaLspOptimizationCode::DelayedDefinition
280271
}
@@ -408,20 +399,4 @@ mod tests {
408399
LuaLspOptimizationCode::DelayedDefinition
409400
);
410401
}
411-
412-
#[test]
413-
fn lsp_optimization_accepts_skip_table_fields_check_aliases() {
414-
for code in ["skip_table_fields_check", "check_table_field"] {
415-
let attribute = LuaAttributeUse::new(
416-
LuaTypeDeclId::global("lsp_optimization"),
417-
vec![("code".into(), Some(doc_string(code)))],
418-
);
419-
420-
let lsp_optimization = attribute.as_lsp_optimization().unwrap();
421-
assert_eq!(
422-
lsp_optimization.code,
423-
LuaLspOptimizationCode::SkipTableFieldsCheck
424-
);
425-
}
426-
}
427402
}

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

Lines changed: 7 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ use std::ops::Deref;
22

33
use emmylua_parser::{
44
LuaAssignStat, LuaAst, LuaAstNode, LuaAstToken, LuaExpr, LuaIndexExpr, LuaLocalStat,
5-
LuaNameExpr, LuaSyntaxNode, LuaSyntaxToken, LuaTableExpr, LuaVarExpr,
5+
LuaNameExpr, LuaTableExpr, LuaVarExpr,
66
};
77
use rowan::{NodeOrToken, TextRange};
88

99
use crate::{
10-
DbIndex, DiagnosticCode, LuaBuiltinAttributeKind, LuaDeclExtra, LuaDeclId, LuaMemberKey,
11-
LuaSemanticDeclId, LuaType, SemanticDeclLevel, SemanticModel, TypeCheckFailReason,
12-
TypeCheckResult, VariadicType, get_real_type, infer_index_expr,
10+
DbIndex, DiagnosticCode, LuaDeclExtra, LuaDeclId, LuaMemberKey, LuaSemanticDeclId, LuaType,
11+
SemanticDeclLevel, SemanticModel, TypeCheckFailReason, TypeCheckResult, VariadicType,
12+
get_real_type, infer_index_expr,
1313
};
1414

1515
use super::{Checker, DiagnosticContext, humanize_lint_type};
@@ -117,13 +117,7 @@ fn check_name_expr(
117117
false,
118118
);
119119
if let Some(expr) = expr {
120-
check_table_expr(
121-
context,
122-
semantic_model,
123-
NodeOrToken::Node(name_expr.syntax().clone()),
124-
&expr,
125-
source_type.as_ref(),
126-
);
120+
check_table_expr(context, semantic_model, &expr, source_type.as_ref());
127121
}
128122

129123
Some(())
@@ -157,13 +151,7 @@ fn check_index_expr(
157151
true,
158152
);
159153
if let Some(expr) = expr {
160-
check_table_expr(
161-
context,
162-
semantic_model,
163-
NodeOrToken::Node(index_expr.syntax().clone()),
164-
&expr,
165-
source_type.as_ref(),
166-
);
154+
check_table_expr(context, semantic_model, &expr, source_type.as_ref());
167155
}
168156
Some(())
169157
}
@@ -200,13 +188,7 @@ fn check_local_stat(
200188
false,
201189
);
202190
if let Some(expr) = value_exprs.get(idx) {
203-
check_table_expr(
204-
context,
205-
semantic_model,
206-
NodeOrToken::Node(var.syntax().clone()),
207-
expr,
208-
Some(&var_type),
209-
);
191+
check_table_expr(context, semantic_model, expr, Some(&var_type));
210192
}
211193
}
212194
Some(())
@@ -216,27 +198,9 @@ fn check_local_stat(
216198
pub fn check_table_expr(
217199
context: &mut DiagnosticContext,
218200
semantic_model: &SemanticModel,
219-
decl_node: NodeOrToken<LuaSyntaxNode, LuaSyntaxToken>,
220201
table_expr: &LuaExpr,
221202
table_type: Option<&LuaType>, // 记录的类型
222203
) -> Option<bool> {
223-
// 检查是否附加了元数据以跳过诊断
224-
if let Some(semantic_decl) = semantic_model.find_decl(decl_node, SemanticDeclLevel::default()) {
225-
if let Some(property) = semantic_model
226-
.get_db()
227-
.get_property_index()
228-
.get_property(&semantic_decl)
229-
{
230-
if property
231-
.find_builtin_attribute(LuaBuiltinAttributeKind::LspOptimization)
232-
.and_then(|attribute_use| attribute_use.as_lsp_optimization())
233-
.is_some_and(|attribute| attribute.is_skip_table_fields_check())
234-
{
235-
return Some(false);
236-
}
237-
}
238-
}
239-
240204
let table_type = table_type?;
241205
let Some(table_expr) = LuaTableExpr::cast(table_expr.syntax().clone()) else {
242206
return Some(false);

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

Lines changed: 2 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
use hashbrown::{HashMap, HashSet};
22

3-
use emmylua_parser::{LuaAst, LuaAstNode, LuaExpr, LuaSyntaxId, LuaTableExpr};
4-
use rowan::NodeOrToken;
3+
use emmylua_parser::{LuaAstNode, LuaExpr, LuaTableExpr};
54

6-
use crate::{
7-
DbIndex, DiagnosticCode, LuaBuiltinAttributeKind, LuaMemberOwner, LuaType, SemanticDeclLevel,
8-
SemanticModel,
9-
};
5+
use crate::{DbIndex, DiagnosticCode, LuaMemberOwner, LuaType, SemanticModel};
106

117
use super::{Checker, DiagnosticContext, humanize_lint_type};
128
use itertools::Itertools;
@@ -24,22 +20,7 @@ impl Checker for MissingFieldsChecker {
2420

2521
let mut required_fields_cache = HashMap::new();
2622
let mut optional_field_type_cache = HashMap::new();
27-
let mut skipped_table_exprs: HashSet<LuaSyntaxId> = HashSet::new();
2823
for expr in root.descendants::<LuaTableExpr>() {
29-
let expr_syntax_id = expr.get_syntax_id();
30-
if skipped_table_exprs.contains(&expr_syntax_id) {
31-
continue;
32-
}
33-
34-
if table_expr_has_skip_table_fields_check_optimization(semantic_model, &expr) {
35-
skipped_table_exprs.insert(expr_syntax_id);
36-
skipped_table_exprs.extend(
37-
expr.descendants::<LuaTableExpr>()
38-
.map(|expr| expr.get_syntax_id()),
39-
);
40-
continue;
41-
}
42-
4324
check_table_expr(
4425
context,
4526
semantic_model,
@@ -160,61 +141,6 @@ fn check_table_expr(
160141
Some(())
161142
}
162143

163-
fn table_expr_has_skip_table_fields_check_optimization(
164-
semantic_model: &SemanticModel,
165-
expr: &LuaTableExpr,
166-
) -> bool {
167-
let Some(parent) = expr.syntax().parent().and_then(LuaAst::cast) else {
168-
return false;
169-
};
170-
171-
let decl_node = match parent {
172-
LuaAst::LuaLocalStat(local) => {
173-
let Some(idx) = local
174-
.get_value_exprs()
175-
.position(|value| value.get_position() == expr.get_position())
176-
else {
177-
return false;
178-
};
179-
let Some(local_name) = local.get_local_name_list().nth(idx) else {
180-
return false;
181-
};
182-
NodeOrToken::Node(local_name.syntax().clone())
183-
}
184-
LuaAst::LuaAssignStat(assign) => {
185-
let (vars, exprs) = assign.get_var_and_expr_list();
186-
let Some(idx) = exprs
187-
.iter()
188-
.position(|value| value.get_position() == expr.get_position())
189-
else {
190-
return false;
191-
};
192-
let Some(var) = vars.get(idx) else {
193-
return false;
194-
};
195-
NodeOrToken::Node(var.syntax().clone())
196-
}
197-
_ => return false,
198-
};
199-
200-
let Some(semantic_decl) = semantic_model.find_decl(decl_node, SemanticDeclLevel::default())
201-
else {
202-
return false;
203-
};
204-
let Some(property) = semantic_model
205-
.get_db()
206-
.get_property_index()
207-
.get_property(&semantic_decl)
208-
else {
209-
return false;
210-
};
211-
212-
property
213-
.find_builtin_attribute(LuaBuiltinAttributeKind::LspOptimization)
214-
.and_then(|attribute_use| attribute_use.as_lsp_optimization())
215-
.is_some_and(|attribute| attribute.is_skip_table_fields_check())
216-
}
217-
218144
fn get_required_fields<'a>(
219145
db: &DbIndex,
220146
table_type: &LuaType,

crates/emmylua_code_analysis/src/diagnostic/checker/param_check/type_mismatch.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::sync::Arc;
22

33
use emmylua_parser::{LuaAstNode, LuaAstToken, LuaCallExpr};
4-
use rowan::{NodeOrToken, TextRange};
4+
use rowan::TextRange;
55

66
use crate::{
77
DiagnosticCode, LuaFunctionType, LuaType, RenderLevel, SemanticModel, TypeCheckFailReason,
@@ -72,13 +72,8 @@ pub(super) fn check_param_types(
7272
if failed_arg.typ.is_table()
7373
&& let Some(arg_expr_idx) = failed_arg.expr_index
7474
&& let Some(arg_expr) = facts.arg_exprs.get(arg_expr_idx)
75-
&& let Some(add_diagnostic) = check_table_expr(
76-
context,
77-
semantic_model,
78-
NodeOrToken::Node(arg_expr.syntax().clone()),
79-
arg_expr,
80-
Some(&param_type),
81-
)
75+
&& let Some(add_diagnostic) =
76+
check_table_expr(context, semantic_model, arg_expr, Some(&param_type))
8277
&& add_diagnostic
8378
{
8479
return Some(());

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

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,7 @@ fn check_return_stat(
9191
if return_expr_type.is_table()
9292
&& let Some(return_expr) = return_exprs.get(index)
9393
{
94-
check_table_expr(
95-
context,
96-
semantic_model,
97-
NodeOrToken::Node(return_expr.syntax().clone()),
98-
return_expr,
99-
Some(check_type),
100-
);
94+
check_table_expr(context, semantic_model, return_expr, Some(check_type));
10195
}
10296

10397
add_type_check_diagnostic(
@@ -129,13 +123,9 @@ fn check_return_stat(
129123
&& let Some(return_expr) = return_exprs.first()
130124
{
131125
// 表字段已经报错了, 则不添加返回值不匹配的诊断避免干扰
132-
if let Some(add_diagnostic) = check_table_expr(
133-
context,
134-
semantic_model,
135-
NodeOrToken::Node(return_expr.syntax().clone()),
136-
return_expr,
137-
Some(return_type),
138-
) && add_diagnostic
126+
if let Some(add_diagnostic) =
127+
check_table_expr(context, semantic_model, return_expr, Some(return_type))
128+
&& add_diagnostic
139129
{
140130
return Some(());
141131
}

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

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -338,27 +338,6 @@ foo({})
338338
));
339339
}
340340

341-
#[test]
342-
fn test_lsp_optimization_skip_table_fields_check_skips_missing_fields() {
343-
let mut ws = VirtualWorkspace::new_with_init_std_lib();
344-
assert!(ws.has_no_diagnostic(
345-
DiagnosticCode::MissingFields,
346-
r#"
347-
---@class D32.Child
348-
---@field name string
349-
350-
---@class D32.Config
351-
---@field child D32.Child
352-
353-
---@[lsp_optimization("skip_table_fields_check")]
354-
---@type D32.Config
355-
local config = {
356-
child = {},
357-
}
358-
"#
359-
));
360-
}
361-
362341
#[test]
363342
fn test_call_argument_comment_does_not_shift_missing_fields_range() {
364343
let mut ws = VirtualWorkspace::new();

crates/emmylua_ls/std_i18n/builtin/zh_CN.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ lsp_optimization: |
8686
8787
### 参数
8888
89-
- `skip_table_fields_check`: 跳过表字段诊断。建议对所有大型配置表使用此选项。
9089
- `delayed_definition`: 表示变量类型由第一次赋值决定,仅对没有初始值的 `local` 声明有效。
9190
9291
index_alias: |

0 commit comments

Comments
 (0)