Skip to content

Commit cda0ffd

Browse files
committed
Add built-in feature impl: deprecated, skip_diagnostic
1 parent 8a023e3 commit cda0ffd

File tree

11 files changed

+122
-67
lines changed

11 files changed

+122
-67
lines changed

crates/emmylua_code_analysis/resources/std/builtin.lua

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,19 @@
138138
---@alias TypeGuard<T> boolean
139139

140140
---@alias Language<T: string> string
141+
142+
--- attribute
143+
144+
--- Deprecated. Receives an optional message parameter.
145+
---@attribute deprecated(message: string?)
146+
147+
--- Skip partial diagnostics, typically used to optimize diagnostic performance.
148+
---
149+
--- Receives a parameter, the options are:
150+
--- - `table_field` - Skip diagnostic for `table` fields
151+
---@attribute skip_diagnostic(code: string)
152+
153+
--- Index field alias, will be displayed in `hint` and `completion`.
154+
---
155+
--- Receives a string parameter for the alias name.
156+
---@attribute index_alias(name: string)

crates/emmylua_code_analysis/src/compilation/analyzer/doc/attribute_tags.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use emmylua_parser::{
2-
LuaAst, LuaAstNode, LuaDocTagAttributeUse, LuaExpr, LuaKind, LuaLiteralExpr, LuaLiteralToken,
3-
LuaSyntaxKind, LuaSyntaxNode,
2+
LuaAst, LuaAstNode, LuaDocTagAttributeUse, LuaDocType, LuaExpr, LuaKind, LuaLiteralExpr,
3+
LuaLiteralToken, LuaSyntaxKind, LuaSyntaxNode,
44
};
55
use smol_str::SmolStr;
66

77
use crate::{
88
LuaAttributeUse, LuaType,
99
compilation::analyzer::doc::{
1010
DocAnalyzer,
11+
infer_type::infer_type,
1112
tags::{get_owner_id, report_orphan_tag},
1213
},
1314
};
@@ -33,14 +34,14 @@ pub fn analyze_tag_attribute_use(
3334
params.push(arg_type);
3435
}
3536
}
36-
analyzer.db.get_property_index_mut().add_attribute_use(
37-
analyzer.file_id,
38-
owner_id.clone(),
39-
LuaAttributeUse::new(
40-
attribute_use.get_name_token()?.get_name_text().to_string(),
41-
params,
42-
),
43-
);
37+
let attribute_type = infer_type(analyzer, LuaDocType::Name(attribute_use.get_type()?));
38+
if let LuaType::Ref(type_id) = attribute_type {
39+
analyzer.db.get_property_index_mut().add_attribute_use(
40+
analyzer.file_id,
41+
owner_id.clone(),
42+
LuaAttributeUse::new(type_id, params),
43+
);
44+
}
4445
}
4546
Some(())
4647
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ mod test {
55
#[test]
66
fn test_def_attribute() {
77
let mut ws = VirtualWorkspace::new();
8+
ws.def(
9+
r#"
10+
---@attribute Deprecated(message: string?)
11+
---@attribute SkipDiagnosticTable() -- 跳过对表的部分诊断, 用于优化性能, 通常来说对巨型配置表使用.
12+
---@attribute IndexFieldAlias(name: string) -- 索引字段别名, 将在`hint`与`completion`中显示别名.
13+
"#,
14+
);
815

916
// ws.def(
1017
// r#"
@@ -25,7 +32,7 @@ mod test {
2532
r#"
2633
---@class A
2734
---@field a string
28-
---@[deprecated]
35+
---@[Deprecated]
2936
---@field b string
3037
"#,
3138
);

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::sync::Arc;
33
use emmylua_parser::{LuaVersionCondition, VisibilityKind};
44

55
use crate::{
6-
LuaType,
6+
LuaType, LuaTypeDeclId,
77
db_index::property::decl_feature::{DeclFeatureFlag, PropertyDeclFeature},
88
};
99

@@ -105,6 +105,10 @@ impl LuaCommonProperty {
105105
)
106106
.push(attribute_use);
107107
}
108+
109+
pub fn attribute_uses(&self) -> Option<&Arc<Vec<LuaAttributeUse>>> {
110+
self.attribute_uses.as_ref()
111+
}
108112
}
109113

110114
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -162,12 +166,12 @@ impl LuaPropertyId {
162166

163167
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
164168
pub struct LuaAttributeUse {
165-
pub name: String,
169+
pub id: LuaTypeDeclId,
166170
pub params: Vec<LuaType>,
167171
}
168172

169173
impl LuaAttributeUse {
170-
pub fn new(name: String, params: Vec<LuaType>) -> Self {
171-
Self { name, params }
174+
pub fn new(name: LuaTypeDeclId, params: Vec<LuaType>) -> Self {
175+
Self { id: name, params }
172176
}
173177
}

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

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use std::ops::Deref;
22

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

99
use crate::{
1010
DiagnosticCode, LuaDeclExtra, LuaDeclId, LuaMemberKey, LuaSemanticDeclId, LuaType,
@@ -78,7 +78,7 @@ fn check_name_expr(
7878
rowan::NodeOrToken::Node(name_expr.syntax().clone()),
7979
SemanticDeclLevel::default(),
8080
)?;
81-
let source_type = match semantic_decl {
81+
let source_type = match semantic_decl.clone() {
8282
LuaSemanticDeclId::LuaDecl(decl_id) => {
8383
let decl = semantic_model
8484
.get_db()
@@ -116,9 +116,9 @@ fn check_name_expr(
116116
check_table_expr(
117117
context,
118118
semantic_model,
119+
rowan::NodeOrToken::Node(name_expr.syntax().clone()),
119120
&expr,
120121
source_type.as_ref(),
121-
Some(&value_type),
122122
);
123123
}
124124

@@ -152,9 +152,9 @@ fn check_index_expr(
152152
check_table_expr(
153153
context,
154154
semantic_model,
155+
rowan::NodeOrToken::Node(index_expr.syntax().clone()),
155156
&expr,
156157
source_type.as_ref(),
157-
Some(&value_type),
158158
);
159159
}
160160
Some(())
@@ -195,9 +195,9 @@ fn check_local_stat(
195195
check_table_expr(
196196
context,
197197
semantic_model,
198+
rowan::NodeOrToken::Node(var.syntax().clone()),
198199
expr,
199200
Some(&var_type),
200-
Some(&value_type),
201201
);
202202
}
203203
}
@@ -207,19 +207,32 @@ fn check_local_stat(
207207
pub fn check_table_expr(
208208
context: &mut DiagnosticContext,
209209
semantic_model: &SemanticModel,
210+
decl_node: NodeOrToken<LuaSyntaxNode, LuaSyntaxToken>,
210211
table_expr: &LuaExpr,
211212
table_type: Option<&LuaType>, // 记录的类型
212-
_expr_type: Option<&LuaType>, // 实际表达式推导出的类型
213213
) -> Option<bool> {
214-
// 需要进行一些过滤
215-
// if table_type == expr_type {
216-
// return Some(false);
217-
// }
214+
// 检查是否附加了元数据以跳过诊断
215+
if let Some(semantic_decl) = semantic_model.find_decl(decl_node, SemanticDeclLevel::default()) {
216+
if let Some(property) = semantic_model
217+
.get_db()
218+
.get_property_index()
219+
.get_property(&semantic_decl)
220+
{
221+
if let Some(attribute_uses) = property.attribute_uses() {
222+
for attribute_use in attribute_uses.iter() {
223+
if attribute_use.id.get_name() == "skip_diagnostic" {
224+
if let Some(LuaType::DocStringConst(code)) = attribute_use.params.get(0) {
225+
if code.as_ref() == "table_field" {
226+
return Some(false);
227+
}
228+
};
229+
}
230+
}
231+
}
232+
}
233+
}
234+
218235
let table_type = table_type?;
219-
// match table_type {
220-
// LuaType::Def(_) => return Some(false),
221-
// _ => {}
222-
// }
223236
if let Some(table_expr) = LuaTableExpr::cast(table_expr.syntax().clone()) {
224237
return check_table_expr_content(context, semantic_model, table_type, &table_expr);
225238
}

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

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use emmylua_parser::{LuaAst, LuaAstNode, LuaIndexExpr, LuaNameExpr};
22

33
use crate::{
4-
DiagnosticCode, LuaDeclId, LuaDeprecated, LuaMemberId, LuaSemanticDeclId, SemanticDeclLevel,
5-
SemanticModel,
4+
DiagnosticCode, LuaDeclId, LuaDeprecated, LuaMemberId, LuaSemanticDeclId, LuaType,
5+
SemanticDeclLevel, SemanticModel,
66
};
77

88
use super::{Checker, DiagnosticContext};
@@ -45,23 +45,12 @@ fn check_name_expr(
4545
return Some(());
4646
}
4747

48-
let property = semantic_model
49-
.get_db()
50-
.get_property_index()
51-
.get_property(&semantic_decl)?;
52-
if let Some(deprecated) = property.deprecated() {
53-
let depreacated_message = match deprecated {
54-
LuaDeprecated::Deprecated => "deprecated".to_string(),
55-
LuaDeprecated::DeprecatedWithMessage(message) => message.to_string(),
56-
};
57-
58-
context.add_diagnostic(
59-
DiagnosticCode::Deprecated,
60-
name_expr.get_range(),
61-
depreacated_message,
62-
None,
63-
);
64-
}
48+
check_deprecated(
49+
context,
50+
semantic_model,
51+
&semantic_decl,
52+
name_expr.get_range(),
53+
);
6554
Some(())
6655
}
6756

@@ -80,24 +69,47 @@ fn check_index_expr(
8069
{
8170
return Some(());
8271
}
72+
let index_name_range = index_expr.get_index_name_token()?.text_range();
73+
check_deprecated(context, semantic_model, &semantic_decl, index_name_range);
74+
Some(())
75+
}
76+
77+
fn check_deprecated(
78+
context: &mut DiagnosticContext,
79+
semantic_model: &SemanticModel,
80+
semantic_decl: &LuaSemanticDeclId,
81+
range: rowan::TextRange,
82+
) {
8383
let property = semantic_model
8484
.get_db()
8585
.get_property_index()
86-
.get_property(&semantic_decl)?;
86+
.get_property(semantic_decl);
87+
let Some(property) = property else {
88+
return;
89+
};
8790
if let Some(deprecated) = property.deprecated() {
8891
let depreacated_message = match deprecated {
8992
LuaDeprecated::Deprecated => "deprecated".to_string(),
9093
LuaDeprecated::DeprecatedWithMessage(message) => message.to_string(),
9194
};
9295

93-
let index_name_range = index_expr.get_index_name_token()?.text_range();
94-
95-
context.add_diagnostic(
96-
DiagnosticCode::Deprecated,
97-
index_name_range,
98-
depreacated_message,
99-
None,
100-
);
96+
context.add_diagnostic(DiagnosticCode::Deprecated, range, depreacated_message, None);
97+
}
98+
// 检查特性
99+
if let Some(attribute_uses) = property.attribute_uses() {
100+
for attribute_use in attribute_uses.iter() {
101+
if attribute_use.id.get_name() == "deprecated" {
102+
let depreacated_message = match attribute_use.params.first() {
103+
Some(LuaType::DocStringConst(message)) => message.as_ref().to_string(),
104+
_ => "deprecated".to_string(),
105+
};
106+
context.add_diagnostic(
107+
DiagnosticCode::Deprecated,
108+
range,
109+
depreacated_message,
110+
None,
111+
);
112+
}
113+
}
101114
}
102-
Some(())
103115
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ fn check_call_expr(
105105
&& let Some(add_diagnostic) = check_table_expr(
106106
context,
107107
semantic_model,
108+
rowan::NodeOrToken::Node(arg_expr.syntax().clone()),
108109
arg_expr,
109110
Some(&param_type),
110-
Some(arg_type),
111111
)
112112
&& add_diagnostic
113113
{

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,9 @@ fn check_return_stat(
9494
check_table_expr(
9595
context,
9696
semantic_model,
97+
rowan::NodeOrToken::Node(return_expr.syntax().clone()),
9798
return_expr,
9899
Some(check_type),
99-
Some(return_expr_type),
100100
);
101101
}
102102

@@ -132,9 +132,9 @@ fn check_return_stat(
132132
if let Some(add_diagnostic) = check_table_expr(
133133
context,
134134
semantic_model,
135+
rowan::NodeOrToken::Node(return_expr.syntax().clone()),
135136
return_expr,
136137
Some(return_type),
137-
Some(return_expr_type),
138138
) && add_diagnostic
139139
{
140140
return Some(());

crates/emmylua_parser/src/grammar/doc/tag.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ pub fn parse_attribute_use(p: &mut LuaDocParser) -> DocParseResult {
708708
fn parse_doc_attribute_use(p: &mut LuaDocParser) -> DocParseResult {
709709
let m = p.mark(LuaSyntaxKind::DocAttributeUse);
710710

711-
expect_token(p, LuaTokenKind::TkName)?;
711+
parse_type(p)?;
712712

713713
// 解析参数列表, 允许没有参数的特性在使用时省略括号
714714
if p.current_token() == LuaTokenKind::TkLeftParen {

crates/emmylua_parser/src/grammar/doc/test.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2913,11 +2913,13 @@ Syntax(Chunk)@0..105
29132913
Syntax(DocTagAttributeUse)@69..96
29142914
Token(TkDocAttribute)@69..70 "["
29152915
Syntax(DocAttributeUse)@70..74
2916-
Token(TkName)@70..74 "Skip"
2916+
Syntax(TypeName)@70..74
2917+
Token(TkName)@70..74 "Skip"
29172918
Token(TkComma)@74..75 ","
29182919
Token(TkWhitespace)@75..76 " "
29192920
Syntax(DocAttributeUse)@76..95
2920-
Token(TkName)@76..87 "check_point"
2921+
Syntax(TypeName)@76..87
2922+
Token(TkName)@76..87 "check_point"
29212923
Syntax(DocAttributeCallArgList)@87..95
29222924
Token(TkLeftParen)@87..88 "("
29232925
Syntax(LiteralExpr)@88..91

0 commit comments

Comments
 (0)