Skip to content

update #554

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 51 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
4b31005
feature: add tag `---@export`
xuhuanzy Jun 27, 2025
f7511bb
add `---@export` diagnostic & semantic_token
xuhuanzy Jun 27, 2025
d84281f
update ---@export
xuhuanzy Jun 27, 2025
ac41c08
update @export diagnostic
xuhuanzy Jun 27, 2025
15db173
update @export: 对标记了`@export`的导出变量实施自动导入控制
xuhuanzy Jun 27, 2025
1ebdda1
add diagnostic: RequireModuleNotVisible
xuhuanzy Jun 28, 2025
4e3ce74
update @export
xuhuanzy Jun 28, 2025
f8343ab
update `@export`. 支持`return {}`
xuhuanzy Jun 28, 2025
68c6ada
fix #558
xuhuanzy Jun 28, 2025
ed5c5df
completion: optimize class_attr_completion
xuhuanzy Jun 28, 2025
3b1fff7
diagnostic: 增强参数与返回值的表检查, 当表字段不匹配时反向抑制参数与返回值检查
xuhuanzy Jun 28, 2025
5bab994
fix: `@type`现在会绑定右侧的注释
xuhuanzy Jun 28, 2025
2b61c16
diagnostic: AssignTypeMismatch 移除 table 过滤
xuhuanzy Jun 29, 2025
dbaa3fe
[New] 重命名支持索引访问
xuhuanzy Jun 29, 2025
3bdf1b8
fix spell check
xuhuanzy Jun 29, 2025
04d3135
optimize rename
xuhuanzy Jun 29, 2025
76735c1
feature: 索引成员允许定义一个别名, 补全时将使用该别名作为显示
xuhuanzy Jun 29, 2025
57507d9
fix #559
xuhuanzy Jun 29, 2025
f8d2f41
update: 增强索引跳转
xuhuanzy Jun 29, 2025
1842419
fix diagnostic DuplicateDocField
xuhuanzy Jun 29, 2025
42d287a
feature: 索引访问现在会在 hint 显示别名
xuhuanzy Jun 29, 2025
c345562
优化member_info搜索
xuhuanzy Jun 29, 2025
f007436
hint 索引别名前缀字符更新
xuhuanzy Jun 29, 2025
1358812
update
xuhuanzy Jun 29, 2025
86aec7d
fix enum field assign int
xuhuanzy Jun 30, 2025
a63312d
fix DuplicateSetField
xuhuanzy Jun 30, 2025
10007ea
fix ParamTypeNotMatch: self
xuhuanzy Jun 30, 2025
47216bd
fix @export UndefinedField
xuhuanzy Jun 30, 2025
17e286c
#region 不再高亮
xuhuanzy Jun 30, 2025
d6a8ef8
fix did_rename_files
xuhuanzy Jul 1, 2025
2422716
optimize goto_def_definition function
xuhuanzy Jul 1, 2025
8da287e
update references: 本地函数现在能够搜索导出的引用
xuhuanzy Jul 1, 2025
b4977b1
optimize semantic_tokens
xuhuanzy Jul 1, 2025
e671005
optimize auto-require
xuhuanzy Jul 1, 2025
ea9d237
fix #565
xuhuanzy Jul 1, 2025
d5b7b1f
fix #567
xuhuanzy Jul 1, 2025
06651c4
Some adjustments to the experiential details
xuhuanzy Jul 3, 2025
930b63e
fix typecheck: def/ref match Generic
xuhuanzy Jul 3, 2025
a2c722d
fix #572
xuhuanzy Jul 4, 2025
5312a09
fix: find_member_origin_owner 禁止追溯到参数
xuhuanzy Jul 4, 2025
b337baa
update diagnostic: `GenericConstraintMismatch` support check union
xuhuanzy Jul 4, 2025
2faff7f
change: 函数泛型返回值会将 `def` 转为 `ref`
xuhuanzy Jul 4, 2025
8fe6a1b
add config: `doc.privateName`
xuhuanzy Jul 4, 2025
089da9f
fix diagnostic: generic_type TypeNotFound
xuhuanzy Jul 6, 2025
e138c07
fix diagnostic: typecheck now knows how to handle generics
xuhuanzy Jul 6, 2025
bc72d51
optimize definition: support generic type
xuhuanzy Jul 6, 2025
c13c34b
fix generic type rename
xuhuanzy Jul 6, 2025
250b34f
optimize completion table field value: do not actively add global va…
xuhuanzy Jul 6, 2025
f55faa2
Support for generic matching table
xuhuanzy Jul 6, 2025
1351438
fix #573
xuhuanzy Jul 7, 2025
f1984c2
fix #574
xuhuanzy Jul 7, 2025
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
6 changes: 5 additions & 1 deletion crates/emmylua_code_analysis/locales/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -260,4 +260,8 @@ Cannot use `...` outside a vararg function.:
"type recursion":
en: "type recursion"
zh_CN: "类型递归"
zh_HK: "類型遞歸"
zh_HK: "類型遞歸"
"Module '%{module}' is not visible. It has @export restrictions.":
en: "Module '%{module}' is not visible. It has @export restrictions."
zh_CN: "模块 '%{module}' 不可见。它有 @export 限制。"
zh_HK: "模組 '%{module}' 不可見。它有 @export 限制。"
24 changes: 24 additions & 0 deletions crates/emmylua_code_analysis/resources/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
"severity": {}
}
},
"doc": {
"$ref": "#/$defs/EmmyrcDoc",
"default": {
"privateName": []
}
},
"documentColor": {
"$ref": "#/$defs/EmmyrcDocumentColor",
"default": {
Expand Down Expand Up @@ -384,6 +390,11 @@
"description": "cast-type-mismatch",
"type": "string",
"const": "cast-type-mismatch"
},
{
"description": "require-module-not-visible",
"type": "string",
"const": "require-module-not-visible"
}
]
},
Expand Down Expand Up @@ -537,6 +548,19 @@
}
}
},
"EmmyrcDoc": {
"type": "object",
"properties": {
"privateName": {
"description": "Treat specific field names as private, e.g. `m_*` means `XXX.m_id` and `XXX.m_type` are private, witch can only be accessed in the class where the definition is located.",
"type": "array",
"default": [],
"items": {
"type": "string"
}
}
}
},
"EmmyrcDocumentColor": {
"type": "object",
"properties": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@ fn infer_generic_type(analyzer: &mut DocAnalyzer, generic_type: &LuaDocGenericTy
{
name_type_decl.get_id()
} else {
analyzer.db.get_diagnostic_index_mut().add_diagnostic(
analyzer.file_id,
AnalyzeError::new(
DiagnosticCode::TypeNotFound,
&t!("Type '%{name}' not found", name = name),
generic_type.get_range(),
),
);
return LuaType::Unknown;
};

Expand All @@ -228,6 +236,13 @@ fn infer_generic_type(analyzer: &mut DocAnalyzer, generic_type: &LuaDocGenericTy
generic_params.push(param_type);
}
}
if let Some(name_type) = generic_type.get_name_type() {
analyzer.db.get_reference_index_mut().add_type_reference(
analyzer.file_id,
id.clone(),
name_type.get_range(),
);
}

return LuaType::Generic(LuaGenericType::new(id, generic_params).into());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use crate::{LuaNoDiscard, LuaSignatureId};
use crate::{
LuaDeclId, LuaExport, LuaExportScope, LuaNoDiscard, LuaSemanticDeclId, LuaSignatureId,
};

use super::{
tags::{find_owner_closure, get_owner_id},
DocAnalyzer,
};
use emmylua_parser::{
LuaDocDescriptionOwner, LuaDocTagDeprecated, LuaDocTagNodiscard, LuaDocTagSource,
LuaDocTagVersion, LuaDocTagVisibility,
LuaAst, LuaAstNode, LuaDocDescriptionOwner, LuaDocTagDeprecated, LuaDocTagExport,
LuaDocTagNodiscard, LuaDocTagSource, LuaDocTagVersion, LuaDocTagVisibility, LuaTableExpr,
};

pub fn analyze_visibility(
Expand Down Expand Up @@ -110,3 +112,38 @@ pub fn analyze_async(analyzer: &mut DocAnalyzer) -> Option<()> {

Some(())
}

pub fn analyze_export(analyzer: &mut DocAnalyzer, tag: LuaDocTagExport) -> Option<()> {
let owner = analyzer.comment.get_owner()?;
let owner_id = match owner {
LuaAst::LuaReturnStat(return_stat) => {
let return_table_expr = return_stat.child::<LuaTableExpr>()?;
LuaSemanticDeclId::LuaDecl(LuaDeclId::new(
analyzer.file_id,
return_table_expr.get_position(),
))
}
_ => get_owner_id(analyzer)?,
};

let export_scope = if let Some(scope_text) = tag.get_export_scope() {
match scope_text.as_str() {
"namespace" => LuaExportScope::Namespace,
"global" => LuaExportScope::Global,
_ => LuaExportScope::Global, // 默认为 global
}
} else {
LuaExportScope::Global // 没有参数时默认为 global
};

let export = LuaExport {
scope: export_scope,
};

analyzer
.db
.get_property_index_mut()
.add_export(analyzer.file_id, owner_id, export);

Some(())
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use super::{
diagnostic_tags::analyze_diagnostic,
field_or_operator_def_tags::{analyze_field, analyze_operator},
property_tags::{
analyze_async, analyze_deprecated, analyze_nodiscard, analyze_source, analyze_version,
analyze_visibility,
analyze_async, analyze_deprecated, analyze_export, analyze_nodiscard, analyze_source,
analyze_version, analyze_visibility,
},
type_def_tags::{analyze_alias, analyze_class, analyze_enum, analyze_func_generic},
type_ref_tags::{
Expand Down Expand Up @@ -104,6 +104,9 @@ pub fn analyze_tag(analyzer: &mut DocAnalyzer, tag: LuaDocTag) -> Option<()> {
LuaDocTag::Other(other) => {
analyze_other(analyzer, other)?;
}
LuaDocTag::Export(export) => {
analyze_export(analyzer, export)?;
}
_ => {}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ use super::{
};

pub fn analyze_type(analyzer: &mut DocAnalyzer, tag: LuaDocTagType) -> Option<()> {
let description = if let Some(des) = tag.get_description() {
Some(preprocess_description(&des.get_description_text(), None))
} else {
None
};

let mut type_list = Vec::new();
for lua_doc_type in tag.get_type_list() {
let type_ref = infer_type(analyzer, lua_doc_type);
Expand All @@ -50,6 +56,17 @@ pub fn analyze_type(analyzer: &mut DocAnalyzer, tag: LuaDocTagType) -> Option<()
.db
.get_type_index_mut()
.bind_type(decl_id.into(), LuaTypeCache::DocType(type_ref.clone()));

// bind description
if let Some(ref desc) = description {
if !desc.is_empty() {
analyzer.db.get_property_index_mut().add_description(
analyzer.file_id,
LuaSemanticDeclId::LuaDecl(decl_id),
desc.clone(),
);
}
}
}
LuaVarExpr::IndexExpr(index_expr) => {
let member_id =
Expand All @@ -58,6 +75,17 @@ pub fn analyze_type(analyzer: &mut DocAnalyzer, tag: LuaDocTagType) -> Option<()
.db
.get_type_index_mut()
.bind_type(member_id.into(), LuaTypeCache::DocType(type_ref.clone()));

// bind description
if let Some(ref desc) = description {
if !desc.is_empty() {
analyzer.db.get_property_index_mut().add_description(
analyzer.file_id,
LuaSemanticDeclId::Member(member_id),
desc.clone(),
);
}
}
}
}
}
Expand All @@ -77,6 +105,17 @@ pub fn analyze_type(analyzer: &mut DocAnalyzer, tag: LuaDocTagType) -> Option<()
.db
.get_type_index_mut()
.bind_type(decl_id.into(), LuaTypeCache::DocType(type_ref.clone()));

// bind description
if let Some(ref desc) = description {
if !desc.is_empty() {
analyzer.db.get_property_index_mut().add_description(
analyzer.file_id,
LuaSemanticDeclId::LuaDecl(decl_id),
desc.clone(),
);
}
}
}
}
LuaAst::LuaTableField(table_field) => {
Expand All @@ -87,6 +126,17 @@ pub fn analyze_type(analyzer: &mut DocAnalyzer, tag: LuaDocTagType) -> Option<()
.db
.get_type_index_mut()
.bind_type(member_id.into(), LuaTypeCache::DocType(first_type.clone()));

// bind description
if let Some(ref desc) = description {
if !desc.is_empty() {
analyzer.db.get_property_index_mut().add_description(
analyzer.file_id,
LuaSemanticDeclId::Member(member_id),
desc.clone(),
);
}
}
}
}
_ => {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use emmylua_parser::{LuaAstNode, LuaChunk, LuaExpr};

use crate::{
compilation::analyzer::unresolve::UnResolveModule, db_index::LuaType, InferFailReason,
LuaSemanticDeclId, LuaSignatureId,
LuaDeclId, LuaSemanticDeclId, LuaSignatureId,
};

use super::{func_body::analyze_func_body_returns, LuaAnalyzer, LuaReturnPoint};
Expand Down Expand Up @@ -67,6 +67,11 @@ fn get_property_owner_id(analyzer: &LuaAnalyzer, expr: LuaExpr) -> Option<LuaSem
LuaExpr::ClosureExpr(closure) => Some(LuaSemanticDeclId::Signature(
LuaSignatureId::from_closure(analyzer.file_id, &closure),
)),
// `return {}`
LuaExpr::TableExpr(table_expr) => Some(LuaSemanticDeclId::LuaDecl(LuaDeclId::new(
analyzer.file_id,
table_expr.get_position(),
))),
_ => None,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,16 @@ mod test {
let expected = ws.ty("string");
assert_eq!(ty, expected);
}

#[test]
fn test_generic_type_inference() {
let mut ws = VirtualWorkspace::new();

assert!(!ws.check_code_for(
DiagnosticCode::TypeNotFound,
r#"
---@class AnonymousObserver<T>: Observer<T>
"#,
));
}
}
26 changes: 26 additions & 0 deletions crates/emmylua_code_analysis/src/compilation/test/export_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#[cfg(test)]
mod test {
use crate::VirtualWorkspace;

#[test]
fn test_1() {
let mut ws = VirtualWorkspace::new();
ws.def_file(
"A.lua",
r#"

---@export
return {
newField = 1
}
"#,
);

ws.def(
r#"
local A = require("A")
A.newField = 2
"#,
);
}
}
1 change: 1 addition & 0 deletions crates/emmylua_code_analysis/src/compilation/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod closure_param_infer_test;
mod closure_return_test;
mod decl_test;
mod diagnostic_disable_test;
mod export_test;
mod flow;
mod for_range_var_infer_test;
mod infer_str_tpl_test;
Expand Down
18 changes: 18 additions & 0 deletions crates/emmylua_code_analysis/src/config/configs/doc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
#[serde(rename_all = "camelCase")]
pub struct EmmyrcDoc {
#[serde(default)]
/// Treat specific field names as private, e.g. `m_*` means `XXX.m_id` and `XXX.m_type` are private, witch can only be accessed in the class where the definition is located.
pub private_name: Vec<String>,
}

impl Default for EmmyrcDoc {
fn default() -> Self {
Self {
private_name: Default::default(),
}
}
}
2 changes: 2 additions & 0 deletions crates/emmylua_code_analysis/src/config/configs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod code_action;
mod codelen;
mod completion;
mod diagnostics;
mod doc;
mod document_color;
mod hover;
mod inlayhint;
Expand All @@ -18,6 +19,7 @@ pub use code_action::EmmyrcCodeAction;
pub use codelen::EmmyrcCodeLen;
pub use completion::{EmmyrcCompletion, EmmyrcFilenameConvention};
pub use diagnostics::EmmyrcDiagnostic;
pub use doc::EmmyrcDoc;
pub use document_color::EmmyrcDocumentColor;
pub use hover::EmmyrcHover;
pub use inlayhint::EmmyrcInlayHint;
Expand Down
4 changes: 3 additions & 1 deletion crates/emmylua_code_analysis/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub use configs::EmmyrcFilenameConvention;
pub use configs::EmmyrcLuaVersion;
use configs::{EmmyrcCodeAction, EmmyrcDocumentColor};
use configs::{
EmmyrcCodeLen, EmmyrcCompletion, EmmyrcDiagnostic, EmmyrcHover, EmmyrcInlayHint,
EmmyrcCodeLen, EmmyrcCompletion, EmmyrcDiagnostic, EmmyrcDoc, EmmyrcHover, EmmyrcInlayHint,
EmmyrcInlineValues, EmmyrcReference, EmmyrcResource, EmmyrcRuntime, EmmyrcSemanticToken,
EmmyrcSignature, EmmyrcStrict, EmmyrcWorkspace,
};
Expand Down Expand Up @@ -58,6 +58,8 @@ pub struct Emmyrc {
pub code_action: EmmyrcCodeAction,
#[serde(default)]
pub inline_values: EmmyrcInlineValues,
#[serde(default)]
pub doc: EmmyrcDoc,
}

impl Emmyrc {
Expand Down
Loading