Skip to content
Open

update #1113

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
9dcb5be
refactor(attribute): switch to a solution similar to C#.
xuhuanzy Jun 8, 2026
25e0c7a
perf: Improve subtype checking performance
xuhuanzy Jun 8, 2026
ffb172b
perf: hover
xuhuanzy Jun 9, 2026
6901ada
perf: find members
xuhuanzy Jun 10, 2026
35be13b
update generic: support for capturing generic parameters of table
xuhuanzy Jun 10, 2026
68296d6
update infer_call_generic
xuhuanzy Jun 10, 2026
3fd1b50
refactor(hover): optimize functions overload
xuhuanzy Jun 11, 2026
a5c2496
refactor(hover): optimize `table field` type is a signature
xuhuanzy Jun 12, 2026
1405446
perf: hover
xuhuanzy Jun 12, 2026
4621da4
fix(hover): call function
xuhuanzy Jun 13, 2026
313da4f
fix(hover): generic function call
xuhuanzy Jun 13, 2026
d3a1563
refactor(hover): no longer special rendering for `@return_overload`
xuhuanzy Jun 13, 2026
91bc734
refactor(diagnostic): param type check for all overloads
xuhuanzy Jun 14, 2026
238246a
refactor(diagnostic): optimize param check
xuhuanzy Jun 14, 2026
b0d6666
clean code
xuhuanzy Jun 14, 2026
b0a0f00
fix(diagnostic): param type check
xuhuanzy Jun 14, 2026
098fb12
perf: filter callable overloads
xuhuanzy Jun 15, 2026
1b588b7
perf: call completion
xuhuanzy Jun 15, 2026
bd04a39
fix: instantiate StrTplRef
xuhuanzy Jun 16, 2026
0c60b9a
perf(diagnostic): GenericConstraintMismatch
xuhuanzy Jun 18, 2026
4f14925
Runs workspace tests with all features
xuhuanzy Jun 18, 2026
2d88675
fix #1110
xuhuanzy Jun 18, 2026
57c6731
fix: prefer main signature for tied overload matches
xuhuanzy Jun 18, 2026
3ffa8be
update hover
xuhuanzy Jun 18, 2026
cebcc37
test: move slow test to `slow-tests` feature
xuhuanzy Jun 18, 2026
4f52723
fix: preserve pcall return narrowing through unresolved casts
xuhuanzy Jun 18, 2026
56f833c
i18n: update
xuhuanzy Jun 18, 2026
6593c66
fix: handle deprecated annotation targets
xuhuanzy Jun 18, 2026
c5df9e7
fix: preserve alias descriptions across deprecated tags
xuhuanzy Jun 19, 2026
a47848f
feat(check): add diagnostic severity filter
xuhuanzy Jun 19, 2026
bd401f0
fix(hover): show bound class docs for variable hovers
xuhuanzy Jun 19, 2026
dce37db
fix #960
xuhuanzy Jun 19, 2026
b65fc3e
fix #930
xuhuanzy Jun 19, 2026
c8c3132
feat: support goto label definition and references
xuhuanzy Jun 19, 2026
fb278c3
fix(generic): infer inline lambda return for callback generics
xuhuanzy Jun 19, 2026
8cbd11d
fix(generic): infer class generic args for self overload returns
xuhuanzy Jun 19, 2026
7ccd2a3
feat(completion): add ArrayAppendProvider
xuhuanzy Jun 19, 2026
e18c277
fix(flow): narrow numeric for len operand in loop body
xuhuanzy Jun 19, 2026
6e864c5
fix(flow): remove fully matched type guards on false branch
xuhuanzy Jun 19, 2026
4d9eb09
fix: preserve integer enum type after bitwise assignment
xuhuanzy Jun 19, 2026
bc65578
fix(flow): ignore unresolved condition replay during narrowing
xuhuanzy Jun 19, 2026
3a92e9e
fix(flow): preserve elseif false branch for chained narrowing
xuhuanzy Jun 19, 2026
42dfc8b
fix(flow): preserve condition narrowing through elseif and not logica…
xuhuanzy Jun 19, 2026
4ef3e95
fix(flow): use pessimistic loop post-flow merging
xuhuanzy Jun 19, 2026
892952f
feat: narrow compatible table literal OR assignments
xuhuanzy Jun 20, 2026
8e8dbfd
fix: hover type member key
xuhuanzy Jun 20, 2026
6a52c65
fix: suppress nil check for asserted assignment prefix
xuhuanzy Jun 20, 2026
d03af37
fix(analysis): handle multiline union optional fields
xuhuanzy Jun 21, 2026
9619628
fix: add `antigravity` to vscode id
xuhuanzy Jun 21, 2026
f16589e
fix(references): include constructor attribute class calls
xuhuanzy Jun 21, 2026
a8bb7df
fix(code-analysis): keep table slot type for empty fallback assignment
xuhuanzy Jun 22, 2026
0091127
fix: prefer precise overloads for literal and vararg calls
xuhuanzy Jun 22, 2026
72f247c
fix(completion): show literal params in overload details
xuhuanzy Jun 22, 2026
7daa188
fix(hover): hide nil doc field keys in type display
xuhuanzy Jun 22, 2026
17c8cb9
fix: honor module map when resolving require paths
xuhuanzy Jun 22, 2026
439953a
feat: add file-local type modifier
xuhuanzy Jun 23, 2026
8daff9e
fix(hover): display constrained generics for parameter hover
xuhuanzy Jun 24, 2026
5234559
fix(diagnostic): honor constrained generics in checks
xuhuanzy Jun 24, 2026
08c540e
refactor(type_check): centralize generic alias expansion
xuhuanzy Jun 24, 2026
97fdc30
perf(diagnostic): cache table field checks
xuhuanzy Jun 24, 2026
96439c0
rename table field optimization attribute
xuhuanzy Jun 24, 2026
504473f
update CHANGELOG.md
xuhuanzy Jun 24, 2026
827aa4c
refactor(diagnostic): param check
xuhuanzy Jun 25, 2026
32a0221
fix(diagnostic): preserve generic param requiredness after instantiation
xuhuanzy Jun 25, 2026
c2a1074
fix(generic): infer implicit self
xuhuanzy Jun 25, 2026
63fe29e
Merge remote-tracking branch 'EmmyLuaLs/main' into update
xuhuanzy Jun 26, 2026
0a01b57
fix clippy
xuhuanzy Jun 26, 2026
7184825
fix(diagnostic): resolve alias types before assign mismatch checks
xuhuanzy Jun 26, 2026
24637d9
fix #1136
xuhuanzy Jun 29, 2026
71926f0
fix(diagnostic): continue checking generic constraints after unconstr…
xuhuanzy Jun 29, 2026
95ba21b
refactor(generic ): header resolution and defer indexed alias calls
xuhuanzy Jun 29, 2026
a3806a7
fix(checker): GenericConstraintMismatch
xuhuanzy Jun 29, 2026
675eef4
refactor(generic): centralize literal widening policy
xuhuanzy Jun 29, 2026
8e3901f
fix(semantic-token): highlight mapped alias type parameters
xuhuanzy Jun 30, 2026
72c5c6f
Merge remote-tracking branch 'EmmyLuaLs/main' into update
xuhuanzy Jun 30, 2026
10960e4
fix: render alias call and generic declaration syntax in hovers
xuhuanzy Jun 30, 2026
2357628
fix(generic): treat keyof instantiation as union
xuhuanzy Jun 30, 2026
300add7
fix(type-check): resolve indexed access through keyof aliases
xuhuanzy Jun 30, 2026
6684148
fix(generic): preserve tuple shape only for homomorphic mapped types
xuhuanzy Jun 30, 2026
696d998
fix(parser): support keyof in conditional generic extends
xuhuanzy Jun 30, 2026
c6db443
fix linux build
xuhuanzy Jun 30, 2026
923e80b
fix(completion): support member completion after lone colon trigger
xuhuanzy Jun 30, 2026
2efa6ad
fix(parser): require branches for doc conditional extends types
xuhuanzy Jun 30, 2026
99e79e2
feat(hover): resolve concrete type expressions in hover
xuhuanzy Jun 30, 2026
05990bc
fix(parser): recover incomplete colon member access before boundaries
xuhuanzy Jul 1, 2026
d7de3f5
fix: Initialization success output should use `info!`
xuhuanzy Jul 1, 2026
01b021f
Merge remote-tracking branch 'EmmyLuaLs/main' into update
xuhuanzy Jul 2, 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 --workspace --features emmylua_ls/full-test
run: cargo test --workspace --all-features

check-schema:
name: Check schema generation
Expand Down
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@

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

## [0.23.3] - Unreleased

### ✨ Added

- **Support const generic parameters**: Added the `const T` syntax for generics, for example `---@generic const T`.
- **emmylua_check severity filter**: Added the `--severity` option to filter diagnostic output by minimum severity.

### ⚠️ Deprecated

- **std.ConstTpl**: Marked `std.ConstTpl` as deprecated. Use the new `const T` generic syntax instead.

### 🔧 Changed

- **Rename table field optimization**: `lsp_optimization("skip_table_fields_check")` is now the documented name for skipping table field diagnostics. The old `check_table_field` name remains supported as a compatibility alias.
- **Refactor hover signature**: Refactored signature rendering in hover.

### 🗑️ Removed

- **`---@attribute` tag**: Removed the `---@attribute` tag. Attribute definitions now use C#-like class definitions:
```lua
---@class NewAttribute: Attribute
---@overload fun(args)
```

## [0.23.2] - 2026-6-3

- **Fix some stuck loading issue**: Fixed some issue that cause the language server stuck at loading workspace, and improve the loading performance of large workspace
Expand Down
10 changes: 9 additions & 1 deletion crates/emmylua_check/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ Output diagnostics in JSON format to a file for further processing:
emmylua_check . -f json --output ./diag.json
```

#### Filter by Severity

Only output warnings and errors:
```shell
emmylua_check . --severity warn
```

---

## ⚙️ Configuration
Expand Down Expand Up @@ -130,9 +137,10 @@ Arguments:
Options:
-c, --config <CONFIG> Path to configuration file. If not provided, ".emmyrc.json" and ".luarc.json" will be searched in the workspace directory
-i, --ignore <IGNORE> Comma-separated list of ignore patterns. Patterns must follow glob syntax
-f, --output-format <OUTPUT_FORMAT> Specify output format [default: text] [possible values: json, text]
-f, --output-format <OUTPUT_FORMAT> Specify output format [default: text] [possible values: json, text, sarif]
--output <OUTPUT> Specify output target (stdout or file path, only used when output_format is json) [default: stdout]
--warnings-as-errors Treat warnings as errors
--severity <SEVERITY> Only output diagnostics at this severity or above [possible values: error, warn, info, hint]
--verbose Verbose output
-h, --help Print help information
-V, --version Print version information
Expand Down
34 changes: 34 additions & 0 deletions crates/emmylua_check/src/cmd_args.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[cfg(feature = "cli")]
use clap::{Parser, ValueEnum};

use lsp_types::DiagnosticSeverity;
use std::path::PathBuf;

#[allow(unused)]
Expand Down Expand Up @@ -44,6 +45,10 @@ pub struct CmdArgs {
#[cfg_attr(feature = "cli", arg(long))]
pub warnings_as_errors: bool,

/// Only output diagnostics at this severity or above
#[cfg_attr(feature = "cli", arg(long, value_enum, ignore_case = true))]
pub severity: Option<DiagnosticSeverityFilter>,

/// Verbose output
#[cfg_attr(feature = "cli", arg(long))]
pub verbose: bool,
Expand All @@ -57,6 +62,35 @@ pub enum OutputFormat {
Sarif,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "cli", derive(ValueEnum))]
pub enum DiagnosticSeverityFilter {
Error,
Warn,
Info,
Hint,
}

impl DiagnosticSeverityFilter {
pub fn allows(self, severity: Option<DiagnosticSeverity>) -> bool {
match severity {
Some(severity) => severity <= self.into(),
None => false,
}
}
}

impl From<DiagnosticSeverityFilter> for DiagnosticSeverity {
fn from(value: DiagnosticSeverityFilter) -> Self {
match value {
DiagnosticSeverityFilter::Error => DiagnosticSeverity::ERROR,
DiagnosticSeverityFilter::Warn => DiagnosticSeverity::WARNING,
DiagnosticSeverityFilter::Info => DiagnosticSeverity::INFORMATION,
DiagnosticSeverityFilter::Hint => DiagnosticSeverity::HINT,
}
}
}

#[allow(unused)]
#[derive(Debug, Clone)]
pub enum OutputDestination {
Expand Down
1 change: 1 addition & 0 deletions crates/emmylua_check/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ pub async fn run_check(cmd_args: CmdArgs) -> Result<(), Box<dyn Error + Sync + S
cmd_args.output_format,
cmd_args.output,
cmd_args.warnings_as_errors,
cmd_args.severity,
)
.await;

Expand Down
9 changes: 7 additions & 2 deletions crates/emmylua_check/src/output/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use emmylua_code_analysis::{DbIndex, FileId};
use lsp_types::Diagnostic;
use tokio::sync::mpsc::Receiver;

use crate::cmd_args::{OutputDestination, OutputFormat};
use crate::cmd_args::{DiagnosticSeverityFilter, OutputDestination, OutputFormat};

use crate::terminal_display::TerminalDisplay;

Expand All @@ -23,6 +23,7 @@ pub async fn output_result(
output_format: OutputFormat,
output: OutputDestination,
warnings_as_errors: bool,
severity_filter: Option<DiagnosticSeverityFilter>,
) -> i32 {
let mut writer: Box<dyn OutputWriter> = match output_format {
OutputFormat::Json => Box::new(json_output_writer::JsonOutputWriter::new(output)),
Expand All @@ -42,7 +43,11 @@ pub async fn output_result(

while let Some((file_id, diagnostics)) = receiver.recv().await {
count += 1;
if let Some(diagnostics) = diagnostics {
if let Some(mut diagnostics) = diagnostics {
if let Some(severity_filter) = severity_filter {
diagnostics.retain(|diagnostic| severity_filter.allows(diagnostic.severity));
}

for diagnostic in &diagnostics {
match diagnostic.severity {
Some(lsp_types::DiagnosticSeverity::ERROR) => {
Expand Down
1 change: 1 addition & 0 deletions crates/emmylua_code_analysis/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ hashbrown.workspace = true
[features]
default = []
reqwest = ["dep:reqwest"]
slow-tests = []

[package.metadata.i18n]
available-locales = ["en", "zh_CN", "zh_HK"]
Expand Down
22 changes: 14 additions & 8 deletions crates/emmylua_code_analysis/resources/std/builtin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,8 @@
--- built-in type for Rawget
--- @alias std.RawGet<T, K> unknown

--- built-in type for generic template, for match integer const and `true`/`false`
--- @deprecated use `const T` as a replacement, for example `---@generic const T`.
---
--- built-in type for generic template, for match integer const and true/false
--- @alias std.ConstTpl<T> unknown

--- compact luals
Expand Down Expand Up @@ -171,24 +170,29 @@

--- attribute

--- @class Attribute

---
--- Deprecated. Receives an optional message parameter.
--- @attribute deprecated(message: string?)
--- @class deprecated: Attribute
--- @overload fun(message?: string)

---
--- Language Server Optimization Items.
---
--- Parameters:
--- - `check_table_field`: Skip the assign check for table fields. It is recommended to use this option for all large configuration tables.
--- - `skip_table_fields_check`: Skip table field diagnostics. It is recommended to use this option for all large configuration tables.
--- - `delayed_definition`: Indicates that the type of the variable is determined by the first assignment.
--- Only valid for `local` declarations with no initial value.
--- @attribute lsp_optimization(code: "check_table_field"|"delayed_definition")
--- @class lsp_optimization: Attribute
--- @overload fun(code: "skip_table_fields_check"|"delayed_definition")

---
--- Index field alias, will be displayed in `hint` and `completion`.
---
--- Receives a string parameter for the alias name.
--- @attribute index_alias(name: string)
--- @class index_alias: Attribute
--- @overload fun(name: string)

---
--- This attribute must be applied to function parameters, and the function parameter's type must be a string template generic,
Expand All @@ -201,7 +205,8 @@
--- - `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"?)
--- @class constructor: Attribute
--- @overload fun(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 All @@ -211,4 +216,5 @@
--- - `convention`: Naming convention, defaults to `camelCase`. Implicitly adds `get` and `set` prefixes. eg: `_age` -> `getAge`, `setAge`.
--- - `getter`: Getter method name. Takes precedence over `convention`.
--- - `setter`: Setter method name. Takes precedence over `convention`.
--- @attribute field_accessor(convention: "camelCase"|"PascalCase"|"snake_case"|nil, getter: string?, setter: string?)
--- @class field_accessor: Attribute
--- @overload fun(convention?: "camelCase"|"PascalCase"|"snake_case", getter?: string, setter?: string)
31 changes: 6 additions & 25 deletions crates/emmylua_code_analysis/src/compilation/analyzer/decl/docs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use emmylua_parser::{
LuaAstNode, LuaAstToken, LuaComment, LuaDocTag, LuaDocTagAlias, LuaDocTagAttribute,
LuaDocTagClass, LuaDocTagEnum, LuaDocTagMeta, LuaDocTagNamespace, LuaDocTagUsing,
LuaDocTypeFlag,
LuaAstNode, LuaAstToken, LuaComment, LuaDocTag, LuaDocTagAlias, LuaDocTagClass, LuaDocTagEnum,
LuaDocTagMeta, LuaDocTagNamespace, LuaDocTagUsing, LuaDocTypeFlag,
};
use flagset::FlagSet;
use rowan::TextRange;
Expand Down Expand Up @@ -62,8 +61,8 @@ fn get_type_flag_value(
"internal" => {
attr |= LuaTypeFlag::Internal;
}
"private" => {
attr |= LuaTypeFlag::Private;
"private" | "file" => {
attr |= LuaTypeFlag::File;
}
_ => {}
}
Expand Down Expand Up @@ -100,24 +99,6 @@ pub fn analyze_doc_tag_alias(analyzer: &mut DeclAnalyzer, alias: LuaDocTagAlias)
Some(())
}

pub fn analyze_doc_tag_attribute(
analyzer: &mut DeclAnalyzer,
attribute: LuaDocTagAttribute,
) -> Option<()> {
let name_token = attribute.get_name_token()?;
let name = name_token.get_name_text().to_string();
let range = name_token.syntax().text_range();

add_type_decl(
analyzer,
&name,
range,
LuaDeclTypeKind::Attribute,
FlagSet::default(),
);
Some(())
}

pub fn analyze_doc_tag_namespace(
analyzer: &mut DeclAnalyzer,
namespace: LuaDocTagNamespace,
Expand Down Expand Up @@ -218,8 +199,8 @@ fn add_type_decl(
let full_name = option_namespace
.map(|ns| format!("{}.{}", ns, basic_name))
.unwrap_or(basic_name.to_string());
let id = if flag.contains(LuaTypeFlag::Private) {
LuaTypeDeclId::local(file_id, &full_name)
let id = if flag.contains(LuaTypeFlag::File) {
LuaTypeDeclId::file(file_id, &full_name)
} else if flag.contains(LuaTypeFlag::Internal) {
LuaTypeDeclId::internal(workspace_id, &full_name)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,6 @@ fn walk_node_enter(analyzer: &mut DeclAnalyzer, node: LuaAst) {
LuaAst::LuaDocTagAlias(doc_tag) => {
docs::analyze_doc_tag_alias(analyzer, doc_tag);
}
LuaAst::LuaDocTagAttribute(doc_tag) => {
docs::analyze_doc_tag_attribute(analyzer, doc_tag);
}
LuaAst::LuaDocTagNamespace(doc_tag) => {
docs::analyze_doc_tag_namespace(analyzer, doc_tag);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{
infer_type::infer_type,
tags::{get_owner_id, report_orphan_tag},
},
get_attribute_constructor_params, is_attribute_class,
};

pub fn analyze_tag_attribute_use(
Expand Down Expand Up @@ -64,27 +65,19 @@ pub fn infer_attribute_uses(
LuaDocType::Name(attribute_use.get_type()?),
);
if let LuaType::Ref(type_id) = attribute_type {
if !is_attribute_class(analyzer.type_context.db, &type_id) {
continue;
}

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)
.and_then(|decl| decl.get_attribute_type())
.and_then(|typ| match typ {
LuaType::DocAttribute(attr_type) => Some(
attr_type
.get_params()
.iter()
.map(|(name, _)| name.clone())
.collect::<Vec<_>>(),
),
_ => None,
})
.unwrap_or_default();
let param_names: Vec<String> =
get_attribute_constructor_params(analyzer.type_context.db, &type_id, &arg_types)
.into_iter()
.map(|(name, _)| name)
.collect();

let mut params = Vec::new();
for (idx, arg_type) in arg_types.into_iter().enumerate() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub fn analyze_field(analyzer: &mut DocAnalyzer, tag: LuaDocTagField) -> Option<
.get_db()
.get_operator_index_mut()
.add_operator(operator);
LuaMemberKey::ExprType(key_type_ref)
LuaMemberKey::TypeKey(key_type_ref)
}
};

Expand Down
Loading
Loading