Skip to content
Open

update #1017

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
bd1dcec
fix: #1007
xuhuanzy Apr 5, 2026
ec80f0e
fix: #1008
xuhuanzy Apr 5, 2026
cf70a39
refactor: `constructor`特性参数从`return_self`更改为`return_mode`
xuhuanzy Apr 5, 2026
044ccfe
fix(parse): attributeuse supports more types
xuhuanzy Apr 5, 2026
b1d4bd6
update: IncompleteSignatureDoc
xuhuanzy Apr 6, 2026
de897d5
fix: `constructor` attribute
xuhuanzy Apr 6, 2026
13b57fe
fix: correct TypeGuard narrowing for inherited types
xuhuanzy Apr 6, 2026
2369877
fix: test_generic_infer_function
xuhuanzy Apr 6, 2026
8707614
refactor: instantiate conditional generic
xuhuanzy Apr 7, 2026
7b08378
fix: conditional generic
xuhuanzy Apr 7, 2026
23eb092
Merge remote-tracking branch 'EmmyLuaLs/main' into fix
xuhuanzy Apr 7, 2026
952f1de
ci: update test.yml
xuhuanzy Apr 7, 2026
e35dad1
Merge remote-tracking branch 'EmmyLuaLs/main' into fix
xuhuanzy Apr 10, 2026
f9df1d2
update i18n
xuhuanzy Apr 10, 2026
0a664d2
Merge remote-tracking branch 'EmmyLuaLs/main' into fix
xuhuanzy Apr 13, 2026
d941081
fix #1034
xuhuanzy Apr 14, 2026
befdfae
update completion postfixprovider
xuhuanzy Apr 14, 2026
63ab73e
update IncompleteSignatureDocChecker
xuhuanzy Apr 17, 2026
8e755ac
Merge remote-tracking branch 'EmmyLuaLs/main' into fix
xuhuanzy Apr 17, 2026
22b4140
fix diagnostic test
xuhuanzy Apr 17, 2026
9203723
fix semantic_token
xuhuanzy Apr 18, 2026
4652f52
Merge remote-tracking branch 'EmmyLuaLs/main' into fix
xuhuanzy Apr 25, 2026
59f28d0
feat: 使用泛型类时必须声明泛型参数
xuhuanzy Apr 26, 2026
4bd4e4b
Adds generic default types to doc parser
xuhuanzy Apr 27, 2026
13f3a69
feat: 支持泛型参数默认类型
xuhuanzy Apr 28, 2026
e96ff1c
Fixes nested generic defaults at function
xuhuanzy Apr 28, 2026
836709c
Adds pre-commit schema regeneration hook
xuhuanzy Apr 28, 2026
9626d71
fix test
xuhuanzy Apr 28, 2026
f407e4b
feat: 重构条件类型推断
xuhuanzy Apr 29, 2026
ccdb922
Merge remote-tracking branch 'EmmyLuaLs/main' into fix
xuhuanzy Apr 29, 2026
ca67d4b
fix #1048
xuhuanzy Apr 30, 2026
a5eb0f5
fix: 绑定变量时 @type 优先级高于 @class/@enum
xuhuanzy May 1, 2026
5b61a75
update generic diagnostic
xuhuanzy May 1, 2026
36008f2
refactor: std i18n
xuhuanzy May 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run Tests
run: cargo test
run: cargo test --workspace --features emmylua_ls/full-test

check-schema:
name: Check schema generation
Expand Down
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ repos:
types: [rust]
args: ["--all"]
pass_filenames: false
- id: generate-schema-json
name: generate schema.json
description: regenerate schema.json from schema_json_gen
entry: cargo run --package schema_json_gen --bin schema_json_gen
language: system
files: ^tools/schema_json_gen/src/main\.rs$
pass_filenames: false
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
Expand Down
9 changes: 9 additions & 0 deletions crates/emmylua_code_analysis/locales/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,10 @@ Cannot use `...` outside a vararg function.:
en: "type `%{found}` does not satisfy the constraint `%{source}`. %{reason}"
zh_CN: "泛型约束要求为 `%{source}` 的子类, 但找到了 `%{found}`. %{reason}"
zh_HK: "泛型约束要求为 `%{source}` 的子类, 但找到了 `%{found}`. %{reason}"
"Generic type '%{name}' requires %{count} type argument(s)":
en: "Generic type '%{name}' requires %{count} type argument(s)"
zh_CN: "泛型类型“%{name}”需要 %{count} 个类型参数"
zh_HK: "泛型類型「%{name}」需要 %{count} 個類型參數"
"the string template type does not match any type declaration":
en: "the string template type does not match any type declaration"
zh_CN: "字符串模板类型与任何类型声明不匹配"
Expand Down Expand Up @@ -278,3 +282,8 @@ Cannot use `...` outside a vararg function.:
en: "Type '%{name}' has inconsistent access modifiers: %{modifiers}."
zh_CN: "类型 '%{name}' 具有不一致的访问修饰符: %{modifiers}."
zh_HK: "類型 '%{name}' 具有不一致的訪問修飾符: %{modifiers}."

"Missing comment for function `%{name}`.":
en: "Missing comment for function `%{name}`."
zh_CN: "函数 `%{name}` 缺少注解。"
zh_HK: "函式 `%{name}` 缺少註解。"
5 changes: 5 additions & 0 deletions crates/emmylua_code_analysis/resources/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,11 @@
"description": "inconsistent-type-access-modifier",
"type": "string",
"const": "inconsistent-type-access-modifier"
},
{
"description": "missing-type-argument",
"type": "string",
"const": "missing-type-argument"
}
]
},
Expand Down
6 changes: 4 additions & 2 deletions crates/emmylua_code_analysis/resources/std/builtin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,10 @@
--- - `name`: The name of the method as a constructor.
--- - `root_class`: Used to mark the root class, will implicitly inherit this class, such as `System.Object` in c#. Defaults to empty.
--- - `strip_self`: Whether the `self` parameter can be omitted when calling the constructor, defaults to `true`
--- - `return_self`: Whether the constructor is forced to return `self`, defaults to `true`
--- @attribute constructor(name: string, root_class: string?, strip_self: boolean?, return_self: boolean?)
--- - `return_mode`: Constructor return strategy. `"self"` forces `self`, `"doc"` uses the documented return type,
--- and `"default"` prefers the documented return type and falls back to `self`.
--- Defaults to `"default"`
--- @attribute constructor(name: string, root_class: string?, strip_self: boolean?, return_mode: "self"|"doc"|"default"?)

---
--- Associates `getter` and `setter` methods with a field. Currently provides only definition navigation functionality,
Expand Down
32 changes: 29 additions & 3 deletions crates/emmylua_code_analysis/resources/std/string.lua
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,37 @@ function string.format(fmt, ...) end
--- @return fun(): string?...
function string.gmatch(s, pattern) end

---
--- Returns an iterator function that, each time it is called, returns the
--- next captures from `pattern` over the string `s`. If `pattern` specifies no
--- captures, then the whole match is produced in each call. A third,
--- optional numeric argument init specifies where to start the search;
--- its default value is 1 and can be negative.
---
--- As an example, the following loop will iterate over all the words from
--- string `s`, printing one per line:
---
--- `s = "hello world from Lua"`
--- `for w in string.gmatch(s, "%a+") do`
--- > `print(w)`
--- `end`
---
--- The next example collects all pairs `key=value` from the given string into a
--- table:
---
--- `t = {}`
--- s = "from=world, to=Lua"`
--- `for k, v in string.gmatch(s, "(%w+)=(%w+)") do`
--- > `t[k] = v`
--- `end`
---
--- For this function, a caret '`^`' at the start of a pattern does not work as
--- an anchor, as this would prevent the iteration.
--- @version > 5.4
--- @param s string
--- @param s string
--- @param pattern string
--- @param init? integer
--- @return fun(): string?...
--- @param init? integer
--- @return fun():string?...
function string.gmatch(s, pattern, init) end

---
Expand Down
33 changes: 29 additions & 4 deletions crates/emmylua_code_analysis/src/compilation/analyzer/decl/docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,15 @@ pub fn analyze_doc_tag_class(analyzer: &mut DeclAnalyzer, class: LuaDocTagClass)
let range = name_token.syntax().text_range();
let type_flag = get_type_flag_value(analyzer, class.get_type_flag());

add_type_decl(analyzer, &name, range, LuaDeclTypeKind::Class, type_flag);
let decl_id = add_type_decl(analyzer, &name, range, LuaDeclTypeKind::Class, type_flag);
if let Some(generic_decl) = class.get_generic_decl() {
analyzer.context.add_pending_type_generic_header(
analyzer.get_file_id(),
decl_id,
generic_decl,
);
}

Some(())
}

Expand Down Expand Up @@ -80,7 +88,15 @@ pub fn analyze_doc_tag_alias(analyzer: &mut DeclAnalyzer, alias: LuaDocTagAlias)
let name = name_token.get_name_text().to_string();
let range = name_token.syntax().text_range();
let type_flag = get_type_flag_value(analyzer, alias.get_type_flag());
add_type_decl(analyzer, &name, range, LuaDeclTypeKind::Alias, type_flag);
let decl_id = add_type_decl(analyzer, &name, range, LuaDeclTypeKind::Alias, type_flag);
if let Some(generic_decl) = alias.get_generic_decl_list() {
analyzer.context.add_pending_type_generic_header(
analyzer.get_file_id(),
decl_id,
generic_decl,
);
}

Some(())
}

Expand Down Expand Up @@ -187,7 +203,7 @@ fn add_type_decl(
range: TextRange,
kind: LuaDeclTypeKind,
flag: FlagSet<LuaTypeFlag>,
) {
) -> LuaTypeDeclId {
let file_id = analyzer.get_file_id();
let workspace_id = analyzer
.db
Expand All @@ -212,6 +228,15 @@ fn add_type_decl(
let simple_name = id.get_simple_name();
type_index.add_type_decl(
file_id,
LuaTypeDecl::new(file_id, range, simple_name.to_string(), kind, flag, id),
LuaTypeDecl::new(
file_id,
range,
simple_name.to_string(),
kind,
flag,
id.clone(),
),
);

id
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ pub fn analyze_tag_attribute_use(

let attribute_uses = infer_attribute_uses(analyzer, tag_use)?;
for attribute_use in attribute_uses {
analyzer.db.get_property_index_mut().add_attribute_use(
analyzer.file_id,
owner_id.clone(),
attribute_use,
);
analyzer
.type_context
.db
.get_property_index_mut()
.add_attribute_use(analyzer.file_id, owner_id.clone(), attribute_use);
}
Some(())
}
Expand All @@ -59,13 +59,17 @@ pub fn infer_attribute_uses(
let attribute_uses = tag_use.get_attribute_uses();
let mut result = Vec::new();
for attribute_use in attribute_uses {
let attribute_type = infer_type(analyzer, LuaDocType::Name(attribute_use.get_type()?));
let attribute_type = infer_type(
&mut analyzer.type_context,
LuaDocType::Name(attribute_use.get_type()?),
);
if let LuaType::Ref(type_id) = attribute_type {
let arg_types: Vec<LuaType> = attribute_use
.get_arg_list()
.map(|arg_list| arg_list.get_args().map(infer_attribute_arg_type).collect())
.unwrap_or_default();
let param_names = analyzer
.type_context
.db
.get_type_index()
.get_type_decl(&type_id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ fn analyze_diagnostic_disable(
let owner_block = comment.ancestors::<LuaBlock>().next()?;
let owner_block_range = owner_block.get_range();
let is_file_disable = owner_block.get_parent::<LuaChunk>().is_some();
let file_id = analyzer.file_id;

let diagnostic_index = analyzer.db.get_diagnostic_index_mut();
let diagnostic_index = analyzer.get_db().get_diagnostic_index_mut();
if let Some(diagnostic_code_list) = diagnostic.get_code_list() {
for code in diagnostic_code_list.get_codes() {
let name = code.get_name_text();
Expand All @@ -47,10 +48,10 @@ fn analyze_diagnostic_disable(
};

if is_file_disable {
diagnostic_index.add_file_diagnostic_disabled(analyzer.file_id, diagnostic_code);
diagnostic_index.add_file_diagnostic_disabled(file_id, diagnostic_code);
} else {
diagnostic_index.add_diagnostic_action(
analyzer.file_id,
file_id,
DiagnosticAction::new(
owner_block_range,
DiagnosticActionKind::Disable(diagnostic_code),
Expand All @@ -60,7 +61,7 @@ fn analyze_diagnostic_disable(
}
} else {
diagnostic_index.add_diagnostic_action(
analyzer.file_id,
file_id,
DiagnosticAction::new(owner_block_range, DiagnosticActionKind::DisableAll),
);
}
Expand All @@ -74,12 +75,13 @@ fn analyze_diagnostic_disable_next_line(
) -> Option<()> {
let comment = analyzer.comment.clone();
let comment_range = comment.get_range();
let document = analyzer.db.get_vfs().get_document(&analyzer.file_id)?;
let file_id = analyzer.file_id;
let document = analyzer.get_db().get_vfs().get_document(&file_id)?;
let comment_end_line = document.get_line(comment_range.end())?;
let line_range = document.get_line_range(comment_end_line + 1)?;
let valid_range = TextRange::new(comment_range.start(), line_range.end());

let diagnostic_index = analyzer.db.get_diagnostic_index_mut();
let diagnostic_index = analyzer.get_db().get_diagnostic_index_mut();
if let Some(diagnostic_code_list) = diagnostic.get_code_list() {
for code in diagnostic_code_list.get_codes() {
let name = code.get_name_text();
Expand All @@ -90,13 +92,13 @@ fn analyze_diagnostic_disable_next_line(
};

diagnostic_index.add_diagnostic_action(
analyzer.file_id,
file_id,
DiagnosticAction::new(valid_range, DiagnosticActionKind::Disable(diagnostic_code)),
);
}
} else {
diagnostic_index.add_diagnostic_action(
analyzer.file_id,
file_id,
DiagnosticAction::new(valid_range, DiagnosticActionKind::DisableAll),
);
}
Expand All @@ -110,11 +112,12 @@ fn analyze_diagnostic_disable_line(
) -> Option<()> {
let comment = analyzer.comment.clone();
let comment_range = comment.get_range();
let document = analyzer.db.get_vfs().get_document(&analyzer.file_id)?;
let file_id = analyzer.file_id;
let document = analyzer.get_db().get_vfs().get_document(&file_id)?;
let comment_end_line = document.get_line(comment_range.end())?;
let valid_range = document.get_line_range(comment_end_line)?;

let diagnostic_index = analyzer.db.get_diagnostic_index_mut();
let diagnostic_index = analyzer.get_db().get_diagnostic_index_mut();
if let Some(diagnostic_code_list) = diagnostic.get_code_list() {
for code in diagnostic_code_list.get_codes() {
let name = code.get_name_text();
Expand All @@ -125,13 +128,13 @@ fn analyze_diagnostic_disable_line(
};

diagnostic_index.add_diagnostic_action(
analyzer.file_id,
file_id,
DiagnosticAction::new(valid_range, DiagnosticActionKind::Disable(diagnostic_code)),
);
}
} else {
diagnostic_index.add_diagnostic_action(
analyzer.file_id,
file_id,
DiagnosticAction::new(valid_range, DiagnosticActionKind::DisableAll),
);
}
Expand All @@ -143,7 +146,8 @@ fn analyze_diagnostic_enable(
analyzer: &mut DocAnalyzer,
diagnostic: LuaDocTagDiagnostic,
) -> Option<()> {
let diagnostic_index = analyzer.db.get_diagnostic_index_mut();
let file_id = analyzer.file_id;
let diagnostic_index = analyzer.get_db().get_diagnostic_index_mut();
let diagnostic_code_list = diagnostic.get_code_list()?;
for code in diagnostic_code_list.get_codes() {
let name = code.get_name_text();
Expand All @@ -153,7 +157,7 @@ fn analyze_diagnostic_enable(
continue;
};

diagnostic_index.add_file_diagnostic_enabled(analyzer.file_id, diagnostic_code);
diagnostic_index.add_file_diagnostic_enabled(file_id, diagnostic_code);
}

Some(())
Expand Down
Loading
Loading