Skip to content

Commit 644cc2f

Browse files
authored
Merge pull request #604 from xuhuanzy/merge
update merge
2 parents cca6a90 + b890da1 commit 644cc2f

File tree

108 files changed

+3863
-826
lines changed

Some content is hidden

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

108 files changed

+3863
-826
lines changed

crates/emmylua_code_analysis/locales/lint.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,8 @@ Cannot use `...` outside a vararg function.:
260260
"type recursion":
261261
en: "type recursion"
262262
zh_CN: "类型递归"
263-
zh_HK: "類型遞歸"
263+
zh_HK: "類型遞歸"
264+
"Module '%{module}' is not visible. It has @export restrictions.":
265+
en: "Module '%{module}' is not visible. It has @export restrictions."
266+
zh_CN: "模块 '%{module}' 不可见。它有 @export 限制。"
267+
zh_HK: "模組 '%{module}' 不可見。它有 @export 限制。"

crates/emmylua_code_analysis/resources/schema.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@
4646
"severity": {}
4747
}
4848
},
49+
"doc": {
50+
"$ref": "#/$defs/EmmyrcDoc",
51+
"default": {
52+
"privateName": []
53+
}
54+
},
4955
"documentColor": {
5056
"$ref": "#/$defs/EmmyrcDocumentColor",
5157
"default": {
@@ -384,6 +390,11 @@
384390
"description": "cast-type-mismatch",
385391
"type": "string",
386392
"const": "cast-type-mismatch"
393+
},
394+
{
395+
"description": "require-module-not-visible",
396+
"type": "string",
397+
"const": "require-module-not-visible"
387398
}
388399
]
389400
},
@@ -537,6 +548,19 @@
537548
}
538549
}
539550
},
551+
"EmmyrcDoc": {
552+
"type": "object",
553+
"properties": {
554+
"privateName": {
555+
"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.",
556+
"type": "array",
557+
"default": [],
558+
"items": {
559+
"type": "string"
560+
}
561+
}
562+
}
563+
},
540564
"EmmyrcDocumentColor": {
541565
"type": "object",
542566
"properties": {

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ fn infer_generic_type(analyzer: &mut DocAnalyzer, generic_type: &LuaDocGenericTy
215215
{
216216
name_type_decl.get_id()
217217
} else {
218+
analyzer.db.get_diagnostic_index_mut().add_diagnostic(
219+
analyzer.file_id,
220+
AnalyzeError::new(
221+
DiagnosticCode::TypeNotFound,
222+
&t!("Type '%{name}' not found", name = name),
223+
generic_type.get_range(),
224+
),
225+
);
218226
return LuaType::Unknown;
219227
};
220228

@@ -228,6 +236,13 @@ fn infer_generic_type(analyzer: &mut DocAnalyzer, generic_type: &LuaDocGenericTy
228236
generic_params.push(param_type);
229237
}
230238
}
239+
if let Some(name_type) = generic_type.get_name_type() {
240+
analyzer.db.get_reference_index_mut().add_type_reference(
241+
analyzer.file_id,
242+
id.clone(),
243+
name_type.get_range(),
244+
);
245+
}
231246

232247
return LuaType::Generic(LuaGenericType::new(id, generic_params).into());
233248
}

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

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
use crate::{LuaNoDiscard, LuaSignatureId};
1+
use crate::{
2+
LuaDeclId, LuaExport, LuaExportScope, LuaNoDiscard, LuaSemanticDeclId, LuaSignatureId,
3+
};
24

35
use super::{
46
tags::{find_owner_closure, get_owner_id},
57
DocAnalyzer,
68
};
79
use emmylua_parser::{
8-
LuaDocDescriptionOwner, LuaDocTagDeprecated, LuaDocTagNodiscard, LuaDocTagSource,
9-
LuaDocTagVersion, LuaDocTagVisibility,
10+
LuaAst, LuaAstNode, LuaDocDescriptionOwner, LuaDocTagDeprecated, LuaDocTagExport,
11+
LuaDocTagNodiscard, LuaDocTagSource, LuaDocTagVersion, LuaDocTagVisibility, LuaTableExpr,
1012
};
1113

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

111113
Some(())
112114
}
115+
116+
pub fn analyze_export(analyzer: &mut DocAnalyzer, tag: LuaDocTagExport) -> Option<()> {
117+
let owner = analyzer.comment.get_owner()?;
118+
let owner_id = match owner {
119+
LuaAst::LuaReturnStat(return_stat) => {
120+
let return_table_expr = return_stat.child::<LuaTableExpr>()?;
121+
LuaSemanticDeclId::LuaDecl(LuaDeclId::new(
122+
analyzer.file_id,
123+
return_table_expr.get_position(),
124+
))
125+
}
126+
_ => get_owner_id(analyzer)?,
127+
};
128+
129+
let export_scope = if let Some(scope_text) = tag.get_export_scope() {
130+
match scope_text.as_str() {
131+
"namespace" => LuaExportScope::Namespace,
132+
"global" => LuaExportScope::Global,
133+
_ => LuaExportScope::Global, // 默认为 global
134+
}
135+
} else {
136+
LuaExportScope::Global // 没有参数时默认为 global
137+
};
138+
139+
let export = LuaExport {
140+
scope: export_scope,
141+
};
142+
143+
analyzer
144+
.db
145+
.get_property_index_mut()
146+
.add_export(analyzer.file_id, owner_id, export);
147+
148+
Some(())
149+
}

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use super::{
1111
diagnostic_tags::analyze_diagnostic,
1212
field_or_operator_def_tags::{analyze_field, analyze_operator},
1313
property_tags::{
14-
analyze_async, analyze_deprecated, analyze_nodiscard, analyze_source, analyze_version,
15-
analyze_visibility,
14+
analyze_async, analyze_deprecated, analyze_export, analyze_nodiscard, analyze_source,
15+
analyze_version, analyze_visibility,
1616
},
1717
type_def_tags::{analyze_alias, analyze_class, analyze_enum, analyze_func_generic},
1818
type_ref_tags::{
@@ -104,6 +104,9 @@ pub fn analyze_tag(analyzer: &mut DocAnalyzer, tag: LuaDocTag) -> Option<()> {
104104
LuaDocTag::Other(other) => {
105105
analyze_other(analyzer, other)?;
106106
}
107+
LuaDocTag::Export(export) => {
108+
analyze_export(analyzer, export)?;
109+
}
107110
_ => {}
108111
}
109112

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ use super::{
2323
};
2424

2525
pub fn analyze_type(analyzer: &mut DocAnalyzer, tag: LuaDocTagType) -> Option<()> {
26+
let description = if let Some(des) = tag.get_description() {
27+
Some(preprocess_description(&des.get_description_text(), None))
28+
} else {
29+
None
30+
};
31+
2632
let mut type_list = Vec::new();
2733
for lua_doc_type in tag.get_type_list() {
2834
let type_ref = infer_type(analyzer, lua_doc_type);
@@ -48,6 +54,17 @@ pub fn analyze_type(analyzer: &mut DocAnalyzer, tag: LuaDocTagType) -> Option<()
4854
.db
4955
.get_type_index_mut()
5056
.bind_type(decl_id.into(), LuaTypeCache::DocType(type_ref.clone()));
57+
58+
// bind description
59+
if let Some(ref desc) = description {
60+
if !desc.is_empty() {
61+
analyzer.db.get_property_index_mut().add_description(
62+
analyzer.file_id,
63+
LuaSemanticDeclId::LuaDecl(decl_id),
64+
desc.clone(),
65+
);
66+
}
67+
}
5168
}
5269
LuaVarExpr::IndexExpr(index_expr) => {
5370
let member_id =
@@ -56,6 +73,17 @@ pub fn analyze_type(analyzer: &mut DocAnalyzer, tag: LuaDocTagType) -> Option<()
5673
.db
5774
.get_type_index_mut()
5875
.bind_type(member_id.into(), LuaTypeCache::DocType(type_ref.clone()));
76+
77+
// bind description
78+
if let Some(ref desc) = description {
79+
if !desc.is_empty() {
80+
analyzer.db.get_property_index_mut().add_description(
81+
analyzer.file_id,
82+
LuaSemanticDeclId::Member(member_id),
83+
desc.clone(),
84+
);
85+
}
86+
}
5987
}
6088
}
6189
}
@@ -75,6 +103,17 @@ pub fn analyze_type(analyzer: &mut DocAnalyzer, tag: LuaDocTagType) -> Option<()
75103
.db
76104
.get_type_index_mut()
77105
.bind_type(decl_id.into(), LuaTypeCache::DocType(type_ref.clone()));
106+
107+
// bind description
108+
if let Some(ref desc) = description {
109+
if !desc.is_empty() {
110+
analyzer.db.get_property_index_mut().add_description(
111+
analyzer.file_id,
112+
LuaSemanticDeclId::LuaDecl(decl_id),
113+
desc.clone(),
114+
);
115+
}
116+
}
78117
}
79118
}
80119
LuaAst::LuaTableField(table_field) => {
@@ -85,6 +124,17 @@ pub fn analyze_type(analyzer: &mut DocAnalyzer, tag: LuaDocTagType) -> Option<()
85124
.db
86125
.get_type_index_mut()
87126
.bind_type(member_id.into(), LuaTypeCache::DocType(first_type.clone()));
127+
128+
// bind description
129+
if let Some(ref desc) = description {
130+
if !desc.is_empty() {
131+
analyzer.db.get_property_index_mut().add_description(
132+
analyzer.file_id,
133+
LuaSemanticDeclId::Member(member_id),
134+
desc.clone(),
135+
);
136+
}
137+
}
88138
}
89139
}
90140
_ => {}

crates/emmylua_code_analysis/src/compilation/analyzer/lua/module.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use emmylua_parser::{LuaAstNode, LuaChunk, LuaExpr};
22

33
use crate::{
44
compilation::analyzer::unresolve::UnResolveModule, db_index::LuaType, InferFailReason,
5-
LuaSemanticDeclId, LuaSignatureId,
5+
LuaDeclId, LuaSemanticDeclId, LuaSignatureId,
66
};
77

88
use super::{func_body::analyze_func_body_returns, LuaAnalyzer, LuaReturnPoint};
@@ -67,6 +67,11 @@ fn get_property_owner_id(analyzer: &LuaAnalyzer, expr: LuaExpr) -> Option<LuaSem
6767
LuaExpr::ClosureExpr(closure) => Some(LuaSemanticDeclId::Signature(
6868
LuaSignatureId::from_closure(analyzer.file_id, &closure),
6969
)),
70+
// `return {}`
71+
LuaExpr::TableExpr(table_expr) => Some(LuaSemanticDeclId::LuaDecl(LuaDeclId::new(
72+
analyzer.file_id,
73+
table_expr.get_position(),
74+
))),
7075
_ => None,
7176
}
7277
}

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,16 @@ mod test {
112112
let expected = ws.ty("string");
113113
assert_eq!(ty, expected);
114114
}
115+
116+
#[test]
117+
fn test_generic_type_inference() {
118+
let mut ws = VirtualWorkspace::new();
119+
120+
assert!(!ws.check_code_for(
121+
DiagnosticCode::TypeNotFound,
122+
r#"
123+
---@class AnonymousObserver<T>: Observer<T>
124+
"#,
125+
));
126+
}
115127
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#[cfg(test)]
2+
mod test {
3+
use crate::VirtualWorkspace;
4+
5+
#[test]
6+
fn test_1() {
7+
let mut ws = VirtualWorkspace::new();
8+
ws.def_file(
9+
"A.lua",
10+
r#"
11+
12+
---@export
13+
return {
14+
newField = 1
15+
}
16+
"#,
17+
);
18+
19+
ws.def(
20+
r#"
21+
local A = require("A")
22+
A.newField = 2
23+
"#,
24+
);
25+
}
26+
}

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

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,4 +945,60 @@ end
945945
let a_expected = ws.ty("string");
946946
assert_eq!(a, a_expected);
947947
}
948+
949+
#[test]
950+
fn test_issue_598() {
951+
let mut ws = VirtualWorkspace::new_with_init_std_lib();
952+
ws.def(
953+
r#"
954+
---@class A<T>
955+
A = {}
956+
---@class IDisposable
957+
---@class B<T>: IDisposable
958+
959+
---@class AnonymousObserver<T>: IDisposable
960+
961+
---@generic T
962+
---@return AnonymousObserver<T>
963+
function createAnonymousObserver()
964+
end
965+
"#,
966+
);
967+
assert!(ws.check_code_for(
968+
DiagnosticCode::ReturnTypeMismatch,
969+
r#"
970+
---@param observer fun(value: T) | B<T>
971+
---@return IDisposable
972+
function A:subscribe(observer)
973+
local typ = type(observer)
974+
if typ == 'function' then
975+
---@cast observer fun(value: T)
976+
observer = createAnonymousObserver()
977+
elseif typ == 'table' then
978+
---@cast observer -function
979+
observer = createAnonymousObserver()
980+
end
981+
982+
return observer
983+
end
984+
"#,
985+
));
986+
987+
assert!(!ws.check_code_for(
988+
DiagnosticCode::ReturnTypeMismatch,
989+
r#"
990+
---@param observer fun(value: T) | B<T>
991+
---@return IDisposable
992+
function A:test2(observer)
993+
local typ = type(observer)
994+
if typ == 'table' then
995+
---@cast observer -function
996+
observer = createAnonymousObserver()
997+
end
998+
999+
return observer
1000+
end
1001+
"#,
1002+
));
1003+
}
9481004
}

0 commit comments

Comments
 (0)