Skip to content

Commit 4628ccf

Browse files
authored
Merge pull request #778 from xuhuanzy/attribute
Add new feature `attribute`
2 parents 5e04abf + a8ec1af commit 4628ccf

File tree

93 files changed

+2426
-489
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+2426
-489
lines changed

CHANGELOG.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,57 @@
33
*All notable changes to the EmmyLua Analyzer Rust project will be documented in this file.*
44

55
---
6+
## [0.17.0] - Unreleased
7+
8+
### 🔧 Changed
9+
- **Refactor IndexAliasName**: 删除原先的索引别名实现(`-- [IndexAliasName]`), 现在使用`---@[index_alias("name")]`
10+
- **Refactor ClassDefaultCall**: 删除配置项`runtime.class_default_call`, 转为使用`---@[constructor("<constructor_method_name>")]`
11+
12+
### ✨ Added
13+
- **Attribute**: 实现了新的特性`---@attribute`,用于定义附加元数据,内置多个特性:
14+
```lua
15+
--- Deprecated. Receives an optional message parameter.
16+
---@attribute deprecated(message: string?)
17+
18+
--- Language Server Performance Optimization Items.
19+
---
20+
--- Receives a parameter, the options are:
21+
--- - `check_table_field` - Skip the assign check for table fields. It is recommended to use this option for all large configuration tables.
22+
---@attribute lsp_perf_optim(code: "check_table_field"|string)
23+
24+
--- Index field alias, will be displayed in `hint` and `completion`.
25+
---
26+
--- Receives a string parameter for the alias name.
27+
---@attribute index_alias(name: string)
28+
29+
--- This attribute must be applied to function parameters, and the function parameter's type must be a string template generic,
30+
--- used to specify the default constructor of a class.
31+
---
32+
--- Parameters:
33+
--- - `name` - The name of the method as a constructor.
34+
--- - `root_class` - Used to mark the root class, will implicitly inherit this class, such as `System.Object` in c#. Defaults to empty.
35+
--- - `strip_self` - Whether the `self` parameter can be omitted when calling the constructor, defaults to `true`
36+
--- - `return_self` - Whether the constructor is forced to return `self`, defaults to `true`
37+
---@attribute constructor(name: string, root_class: string?, strip_self: boolean?, return_self: boolean?)
38+
39+
--- Associates `getter` and `setter` methods with a field. Currently provides only definition navigation functionality,
40+
--- and the target methods must reside within the same class.
41+
---
42+
--- Parameters:
43+
--- - convention: Naming convention, defaults to `camelCase`. Implicitly adds `get` and `set` prefixes. eg: `_age` -> `getAge`, `setAge`.
44+
--- - getter: Getter method name. Takes precedence over `convention`.
45+
--- - setter: Setter method name. Takes precedence over `convention`.
46+
---@attribute field_accessor(convention: "camelCase"|"PascalCase"|"snake_case"|nil, getter: string?, setter: string?)
47+
```
48+
49+
使用语法为 `---@[attribute_name_1(arg...), attribute_name_2(arg...), ...]`, 可以同时使用多个特性, 示例:
50+
```lua
51+
---@class A
52+
---@[deprecated] # 如果特性可以省略参数, 则可以省略`()`
53+
---@field b string # b 此时被标记为弃用
54+
---@[index_alias("b")]
55+
---@field [1] string # 此时在提示和补全中会显示为 `b`
56+
```
657

758
## [0.16.0] - 2025-10-17
859
### ✨ Added

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/emmylua_code_analysis/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ include = [
1414
"src/**",
1515
"resources/**",
1616
]
17+
[dev-dependencies]
18+
googletest.workspace = true
1719

1820
# Inherit workspace lints configuration
1921
[lints]

crates/emmylua_code_analysis/resources/schema.json

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,6 @@
110110
"runtime": {
111111
"$ref": "#/$defs/EmmyrcRuntime",
112112
"default": {
113-
"classDefaultCall": {
114-
"forceNonColon": false,
115-
"forceReturnSelf": false,
116-
"functionName": ""
117-
},
118113
"extensions": [],
119114
"frameworkVersions": [],
120115
"nonstandardSymbol": [],
@@ -163,26 +158,6 @@
163158
}
164159
},
165160
"$defs": {
166-
"ClassDefaultCall": {
167-
"type": "object",
168-
"properties": {
169-
"forceNonColon": {
170-
"description": "Mandatory non`:` definition. When `function_name` is not empty, it takes effect.",
171-
"type": "boolean",
172-
"default": true
173-
},
174-
"forceReturnSelf": {
175-
"description": "Force to return `self`.",
176-
"type": "boolean",
177-
"default": true
178-
},
179-
"functionName": {
180-
"description": "class default overload function. eg. \"__init\".",
181-
"type": "string",
182-
"default": ""
183-
}
184-
}
185-
},
186161
"DiagnosticCode": {
187162
"oneOf": [
188163
{
@@ -435,6 +410,21 @@
435410
"description": "Global variable defined in non-module scope",
436411
"type": "string",
437412
"const": "global-in-non-module"
413+
},
414+
{
415+
"description": "attribute-param-type-mismatch",
416+
"type": "string",
417+
"const": "attribute-param-type-mismatch"
418+
},
419+
{
420+
"description": "attribute-missing-parameter",
421+
"type": "string",
422+
"const": "attribute-missing-parameter"
423+
},
424+
{
425+
"description": "attribute-redundant-parameter",
426+
"type": "string",
427+
"const": "attribute-redundant-parameter"
438428
}
439429
]
440430
},
@@ -942,15 +932,6 @@
942932
"EmmyrcRuntime": {
943933
"type": "object",
944934
"properties": {
945-
"classDefaultCall": {
946-
"description": "class default overload function.",
947-
"$ref": "#/$defs/ClassDefaultCall",
948-
"default": {
949-
"forceNonColon": false,
950-
"forceReturnSelf": false,
951-
"functionName": ""
952-
}
953-
},
954935
"extensions": {
955936
"description": "file Extensions. eg: .lua, .lua.txt",
956937
"type": "array",

crates/emmylua_code_analysis/resources/std/builtin.lua

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,38 @@
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+
--- Language Server Performance Optimization Items.
148+
---
149+
--- Receives a parameter, the options are:
150+
--- - `check_table_field` - Skip the assign check for table fields. It is recommended to use this option for all large configuration tables.
151+
---@attribute lsp_perf_optim(code: "check_table_field"|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)
157+
158+
--- This attribute must be applied to function parameters, and the function parameter's type must be a string template generic,
159+
--- used to specify the default constructor of a class.
160+
---
161+
--- Parameters:
162+
--- - `name` - The name of the method as a constructor.
163+
--- - `root_class` - Used to mark the root class, will implicitly inherit this class, such as `System.Object` in c#. Defaults to empty.
164+
--- - `strip_self` - Whether the `self` parameter can be omitted when calling the constructor, defaults to `true`
165+
--- - `return_self` - Whether the constructor is forced to return `self`, defaults to `true`
166+
---@attribute constructor(name: string, root_class: string?, strip_self: boolean?, return_self: boolean?)
167+
168+
--- Associates `getter` and `setter` methods with a field. Currently provides only definition navigation functionality,
169+
--- and the target methods must reside within the same class.
170+
---
171+
--- Parameters:
172+
--- - convention: Naming convention, defaults to `camelCase`. Implicitly adds `get` and `set` prefixes. eg: `_age` -> `getAge`, `setAge`.
173+
--- - getter: Getter method name. Takes precedence over `convention`.
174+
--- - setter: Setter method name. Takes precedence over `convention`.
175+
---@attribute field_accessor(convention: "camelCase"|"PascalCase"|"snake_case"|nil, getter: string?, setter: string?)

crates/emmylua_code_analysis/src/compilation/analyzer/decl/docs.rs

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
use emmylua_parser::{
2-
LuaAstNode, LuaAstToken, LuaComment, LuaDocAttribute, LuaDocTag, LuaDocTagAlias,
2+
LuaAstNode, LuaAstToken, LuaComment, LuaDocTag, LuaDocTagAlias, LuaDocTagAttribute,
33
LuaDocTagClass, LuaDocTagEnum, LuaDocTagMeta, LuaDocTagNamespace, LuaDocTagUsing,
4+
LuaDocTypeFlag,
45
};
56
use flagset::FlagSet;
67
use rowan::TextRange;
78

89
use crate::{
910
LuaTypeDecl, LuaTypeDeclId,
10-
db_index::{LuaDeclTypeKind, LuaTypeAttribute},
11+
db_index::{LuaDeclTypeKind, LuaTypeFlag},
1112
};
1213

1314
use super::DeclAnalyzer;
@@ -16,39 +17,39 @@ pub fn analyze_doc_tag_class(analyzer: &mut DeclAnalyzer, class: LuaDocTagClass)
1617
let name_token = class.get_name_token()?;
1718
let name = name_token.get_name_text().to_string();
1819
let range = name_token.syntax().text_range();
19-
let attrib = get_attrib_value(analyzer, class.get_attrib());
20+
let type_flag = get_type_flag_value(analyzer, class.get_type_flag());
2021

21-
add_type_decl(analyzer, &name, range, LuaDeclTypeKind::Class, attrib);
22+
add_type_decl(analyzer, &name, range, LuaDeclTypeKind::Class, type_flag);
2223
Some(())
2324
}
2425

25-
fn get_attrib_value(
26+
fn get_type_flag_value(
2627
analyzer: &mut DeclAnalyzer,
27-
attrib: Option<LuaDocAttribute>,
28-
) -> FlagSet<LuaTypeAttribute> {
29-
let mut attr: FlagSet<LuaTypeAttribute> = if analyzer.is_meta {
30-
LuaTypeAttribute::Meta.into()
28+
flag: Option<LuaDocTypeFlag>,
29+
) -> FlagSet<LuaTypeFlag> {
30+
let mut attr: FlagSet<LuaTypeFlag> = if analyzer.is_meta {
31+
LuaTypeFlag::Meta.into()
3132
} else {
32-
LuaTypeAttribute::None.into()
33+
LuaTypeFlag::None.into()
3334
};
3435

35-
if let Some(attrib) = attrib {
36-
for token in attrib.get_attrib_tokens() {
36+
if let Some(flag) = flag {
37+
for token in flag.get_attrib_tokens() {
3738
match token.get_name_text() {
3839
"partial" => {
39-
attr |= LuaTypeAttribute::Partial;
40+
attr |= LuaTypeFlag::Partial;
4041
}
4142
"key" => {
42-
attr |= LuaTypeAttribute::Key;
43+
attr |= LuaTypeFlag::Key;
4344
}
4445
// "global" => {
4546
// attr |= LuaTypeAttribute::Global;
4647
// }
4748
"exact" => {
48-
attr |= LuaTypeAttribute::Exact;
49+
attr |= LuaTypeFlag::Exact;
4950
}
5051
"constructor" => {
51-
attr |= LuaTypeAttribute::Constructor;
52+
attr |= LuaTypeFlag::Constructor;
5253
}
5354
_ => {}
5455
}
@@ -62,9 +63,9 @@ pub fn analyze_doc_tag_enum(analyzer: &mut DeclAnalyzer, enum_: LuaDocTagEnum) -
6263
let name_token = enum_.get_name_token()?;
6364
let name = name_token.get_name_text().to_string();
6465
let range = name_token.syntax().text_range();
65-
let attrib = get_attrib_value(analyzer, enum_.get_attrib());
66+
let flag = get_type_flag_value(analyzer, enum_.get_type_flag());
6667

67-
add_type_decl(analyzer, &name, range, LuaDeclTypeKind::Enum, attrib);
68+
add_type_decl(analyzer, &name, range, LuaDeclTypeKind::Enum, flag);
6869
Some(())
6970
}
7071

@@ -78,7 +79,25 @@ pub fn analyze_doc_tag_alias(analyzer: &mut DeclAnalyzer, alias: LuaDocTagAlias)
7879
&name,
7980
range,
8081
LuaDeclTypeKind::Alias,
81-
LuaTypeAttribute::None.into(),
82+
LuaTypeFlag::None.into(),
83+
);
84+
Some(())
85+
}
86+
87+
pub fn analyze_doc_tag_attribute(
88+
analyzer: &mut DeclAnalyzer,
89+
attribute: LuaDocTagAttribute,
90+
) -> Option<()> {
91+
let name_token = attribute.get_name_token()?;
92+
let name = name_token.get_name_text().to_string();
93+
let range = name_token.syntax().text_range();
94+
95+
add_type_decl(
96+
analyzer,
97+
&name,
98+
range,
99+
LuaDeclTypeKind::Attribute,
100+
LuaTypeFlag::None.into(),
82101
);
83102
Some(())
84103
}
@@ -166,7 +185,7 @@ fn add_type_decl(
166185
name: &str,
167186
range: TextRange,
168187
kind: LuaDeclTypeKind,
169-
attrib: FlagSet<LuaTypeAttribute>,
188+
flag: FlagSet<LuaTypeFlag>,
170189
) {
171190
let file_id = analyzer.get_file_id();
172191
let type_index = analyzer.db.get_type_index_mut();
@@ -180,6 +199,6 @@ fn add_type_decl(
180199
let simple_name = id.get_simple_name();
181200
type_index.add_type_decl(
182201
file_id,
183-
LuaTypeDecl::new(file_id, range, simple_name.to_string(), kind, attrib, id),
202+
LuaTypeDecl::new(file_id, range, simple_name.to_string(), kind, flag, id),
184203
);
185204
}

crates/emmylua_code_analysis/src/compilation/analyzer/decl/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ fn walk_node_enter(analyzer: &mut DeclAnalyzer, node: LuaAst) {
107107
LuaAst::LuaDocTagAlias(doc_tag) => {
108108
docs::analyze_doc_tag_alias(analyzer, doc_tag);
109109
}
110+
LuaAst::LuaDocTagAttribute(doc_tag) => {
111+
docs::analyze_doc_tag_attribute(analyzer, doc_tag);
112+
}
110113
LuaAst::LuaDocTagNamespace(doc_tag) => {
111114
docs::analyze_doc_tag_namespace(analyzer, doc_tag);
112115
}

0 commit comments

Comments
 (0)