Skip to content

Commit ea31e61

Browse files
committed
support cast analyze
1 parent 71a935a commit ea31e61

File tree

12 files changed

+191
-14
lines changed

12 files changed

+191
-14
lines changed

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ use super::{
1414
},
1515
type_def_tags::{analyze_alias, analyze_class, analyze_enum, analyze_func_generic},
1616
type_ref_tags::{
17-
analyze_as, analyze_module, analyze_overload, analyze_param, analyze_return, analyze_type
17+
analyze_as, analyze_cast, analyze_module, analyze_overload, analyze_param, analyze_return,
18+
analyze_type,
1819
},
1920
DocAnalyzer,
2021
};
@@ -84,12 +85,14 @@ pub fn analyze_tag(analyzer: &mut DocAnalyzer, tag: LuaDocTag) -> Option<()> {
8485
LuaDocTag::Diagnostic(diagnostic) => {
8586
analyze_diagnostic(analyzer, diagnostic)?;
8687
}
87-
88-
// cast type
89-
// LuaDocTag::Cast(lua_doc_tag_cast) => todo!(),
88+
// as type
9089
LuaDocTag::As(lua_doc_tag_as) => {
9190
analyze_as(analyzer, lua_doc_tag_as)?;
92-
},
91+
}
92+
// cast type
93+
LuaDocTag::Cast(lua_doc_tag_cast) => {
94+
analyze_cast(analyzer, lua_doc_tag_cast)?;
95+
}
9396
_ => {}
9497
}
9598

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

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use emmylua_parser::{
2-
LuaAst, LuaAstNode, LuaAstToken, LuaDocDescriptionOwner, LuaDocTagAs, LuaDocTagModule,
3-
LuaDocTagOverload, LuaDocTagParam, LuaDocTagReturn, LuaDocTagType, LuaExpr, LuaLocalName,
4-
LuaVarExpr,
2+
BinaryOperator, LuaAst, LuaAstNode, LuaAstToken, LuaBlock, LuaDocDescriptionOwner, LuaDocTagAs,
3+
LuaDocTagCast, LuaDocTagModule, LuaDocTagOverload, LuaDocTagParam, LuaDocTagReturn,
4+
LuaDocTagType, LuaExpr, LuaLocalName, LuaNameToken, LuaVarExpr,
55
};
66

77
use crate::{
88
db_index::{
99
LuaDeclId, LuaDocParamInfo, LuaDocReturnInfo, LuaMemberId, LuaOperator, LuaPropertyOwnerId,
1010
LuaSignatureId, LuaType,
1111
},
12-
InFiled,
12+
InFiled, TypeAssertion,
1313
};
1414

1515
use super::{
@@ -238,3 +238,82 @@ pub fn analyze_as(analyzer: &mut DocAnalyzer, tag: LuaDocTagAs) -> Option<()> {
238238

239239
Some(())
240240
}
241+
242+
pub fn analyze_cast(analyzer: &mut DocAnalyzer, tag: LuaDocTagCast) -> Option<()> {
243+
let name_token = tag.get_name_token();
244+
if let Some(name_token) = name_token {
245+
analyze_cast_with_name_token(analyzer, name_token, tag);
246+
}
247+
248+
Some(())
249+
}
250+
251+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
252+
enum CastAction {
253+
Force,
254+
Add,
255+
Remove,
256+
}
257+
258+
fn analyze_cast_with_name_token(
259+
analyzer: &mut DocAnalyzer,
260+
name_token: LuaNameToken,
261+
tag: LuaDocTagCast,
262+
) -> Option<()> {
263+
let name = name_token.get_name_text();
264+
let decl_index = analyzer.db.get_decl_index();
265+
let decl_tree = decl_index.get_decl_tree(&analyzer.file_id)?;
266+
let decl = decl_tree.find_local_decl(name, tag.get_position())?;
267+
let decl_id = decl.get_id();
268+
269+
let effect_range = tag.ancestors::<LuaBlock>().next()?.get_range();
270+
271+
for cast_op_type in tag.get_op_types() {
272+
let action = match cast_op_type.get_op() {
273+
Some(op) => {
274+
if op.get_op() == BinaryOperator::OpAdd {
275+
CastAction::Add
276+
} else {
277+
CastAction::Remove
278+
}
279+
}
280+
None => CastAction::Force,
281+
};
282+
283+
if cast_op_type.is_nullable() {
284+
let flow_chain = analyzer
285+
.db
286+
.get_flow_index_mut()
287+
.get_or_create_flow_chain(analyzer.file_id, decl_id);
288+
match action {
289+
CastAction::Add => {
290+
flow_chain.add_type_assert(TypeAssertion::Add(LuaType::Nil), effect_range);
291+
}
292+
CastAction::Remove => {
293+
flow_chain.add_type_assert(TypeAssertion::Remove(LuaType::Nil), effect_range);
294+
}
295+
_ => {}
296+
}
297+
} else if let Some(typ) = cast_op_type.get_type() {
298+
let typ = infer_type(analyzer, typ);
299+
let flow_chain = analyzer
300+
.db
301+
.get_flow_index_mut()
302+
.get_or_create_flow_chain(analyzer.file_id, decl_id);
303+
304+
match action {
305+
CastAction::Add => {
306+
flow_chain.add_type_assert(TypeAssertion::Add(typ), effect_range);
307+
}
308+
CastAction::Remove => {
309+
flow_chain.add_type_assert(TypeAssertion::Remove(typ), effect_range);
310+
}
311+
CastAction::Force => {
312+
flow_chain.add_type_assert(TypeAssertion::Force(typ), effect_range);
313+
}
314+
}
315+
}
316+
}
317+
318+
Some(())
319+
}

crates/code_analysis/src/db_index/flow/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ impl LuaFlowIndex {
3434
.get(&file_id)
3535
.and_then(|map| map.get(&decl_id))
3636
}
37+
38+
pub fn get_or_create_flow_chain(&mut self, file_id: FileId, decl_id: LuaDeclId) -> &mut LuaFlowChain {
39+
self.chains_map
40+
.entry(file_id)
41+
.or_insert_with(HashMap::new)
42+
.entry(decl_id)
43+
.or_insert_with(|| LuaFlowChain::new(decl_id))
44+
}
3745
}
3846

3947
impl LuaIndex for LuaFlowIndex {

crates/code_analysis/src/db_index/type/type_assert.rs

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,23 @@ pub enum TypeAssertion {
99
Exist,
1010
IsNativeLuaType(LuaType),
1111
FieldExist(Arc<LuaMemberKey>),
12+
Add(LuaType),
13+
Remove(LuaType),
14+
Force(LuaType),
1215
}
1316

1417
#[allow(unused)]
1518
impl TypeAssertion {
1619
pub fn tighten_type(&self, source: LuaType) -> LuaType {
1720
match self {
1821
TypeAssertion::Exist => remove_nil_and_not_false(source),
19-
TypeAssertion::IsNativeLuaType(t) => force_type(t.clone(), source),
22+
TypeAssertion::IsNativeLuaType(t) => force_type(source, t.clone()),
2023
TypeAssertion::FieldExist(key) => {
2124
LuaType::ExistField(LuaExistFieldType::new((**key).clone(), source).into())
2225
}
26+
TypeAssertion::Add(lua_type) => add_type(source, lua_type.clone()),
27+
TypeAssertion::Remove(lua_type) => remove_type(source, lua_type.clone()),
28+
TypeAssertion::Force(lua_type) => force_type(source, lua_type.clone()),
2329
}
2430
}
2531
}
@@ -46,7 +52,7 @@ fn remove_nil_and_not_false(t: LuaType) -> LuaType {
4652
}
4753
}
4854

49-
fn force_type(target: LuaType, source: LuaType) -> LuaType {
55+
fn force_type(source: LuaType, target: LuaType) -> LuaType {
5056
match &source {
5157
LuaType::Union(union) => {
5258
let mut types = union.get_types().to_vec();
@@ -128,3 +134,45 @@ fn force_type(target: LuaType, source: LuaType) -> LuaType {
128134
_ => target,
129135
}
130136
}
137+
138+
fn add_type(source: LuaType, addded_typ: LuaType) -> LuaType {
139+
if addded_typ.is_nil() {
140+
return LuaType::Nullable(source.into());
141+
}
142+
143+
match source {
144+
LuaType::Union(union) => {
145+
let mut types = union.get_types().to_vec();
146+
types.push(addded_typ);
147+
LuaType::Union(LuaUnionType::new(types).into())
148+
}
149+
LuaType::Nullable(inner) => {
150+
let inner = add_type((*inner).clone(), addded_typ);
151+
LuaType::Nullable(inner.into())
152+
}
153+
_ => LuaType::Union(LuaUnionType::new(vec![source, addded_typ]).into()),
154+
}
155+
}
156+
157+
fn remove_type(source: LuaType, removed_type: LuaType) -> LuaType {
158+
if removed_type.is_nil() {
159+
return remove_nil_and_not_false(source);
160+
}
161+
162+
match source {
163+
LuaType::Union(union) => {
164+
let mut types = union.get_types().to_vec();
165+
types.retain(|t| t != &removed_type);
166+
if types.len() == 1 {
167+
types.pop().unwrap()
168+
} else {
169+
LuaType::Union(LuaUnionType::new(types).into())
170+
}
171+
}
172+
LuaType::Nullable(inner) => {
173+
let inner = remove_type((*inner).clone(), removed_type);
174+
LuaType::Nullable(inner.into())
175+
}
176+
_ => source,
177+
}
178+
}

crates/emmylua_ls/src/handlers/completion/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ pub async fn on_completion_handler(
3535
document.get_offset(position.line as usize, position.character as usize)?
3636
};
3737

38+
if position_offset > root.syntax().text_range().end() {
39+
return None;
40+
}
41+
3842
let token = match root.syntax().token_at_offset(position_offset) {
3943
TokenAtOffset::Single(token) => token,
4044
TokenAtOffset::Between(left, _) => left,

crates/emmylua_ls/src/handlers/defination/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ pub async fn on_goto_defination_handler(
2424
document.get_offset(position.line as usize, position.character as usize)?
2525
};
2626

27+
if position_offset > root.syntax().text_range().end() {
28+
return None;
29+
}
30+
2731
let token = match root.syntax().token_at_offset(position_offset) {
2832
TokenAtOffset::Single(token) => token,
2933
TokenAtOffset::Between(left, right) => {

crates/emmylua_ls/src/handlers/document_highlight/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ pub async fn on_document_highlight_handler(
2626
document.get_offset(position.line as usize, position.character as usize)?
2727
};
2828

29+
if position_offset > root.syntax().text_range().end() {
30+
return None;
31+
}
32+
2933
let token = match root.syntax().token_at_offset(position_offset) {
3034
TokenAtOffset::Single(token) => token,
3135
TokenAtOffset::Between(left, right) => {

crates/emmylua_ls/src/handlers/hover/mod.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
mod keyword_hover;
21
mod build_hover;
32
mod hover_humanize;
3+
mod keyword_hover;
44

55
use build_hover::build_semantic_info_hover;
66
use emmylua_parser::LuaAstNode;
77
use keyword_hover::{hover_keyword, is_keyword};
8-
use lsp_types::{ClientCapabilities, Hover, HoverContents, HoverParams, HoverProviderCapability, MarkupContent, ServerCapabilities};
8+
use lsp_types::{
9+
ClientCapabilities, Hover, HoverContents, HoverParams, HoverProviderCapability, MarkupContent,
10+
ServerCapabilities,
11+
};
912
use rowan::TokenAtOffset;
1013
use tokio_util::sync::CancellationToken;
1114

@@ -29,6 +32,10 @@ pub async fn on_hover(
2932
document.get_offset(position.line as usize, position.character as usize)?
3033
};
3134

35+
if position_offset > root.syntax().text_range().end() {
36+
return None;
37+
}
38+
3239
let token = match root.syntax().token_at_offset(position_offset) {
3340
TokenAtOffset::Single(token) => token,
3441
TokenAtOffset::Between(_, right) => right,
@@ -63,4 +70,4 @@ pub fn register_capabilities(
6370
) -> Option<()> {
6471
server_capabilities.hover_provider = Some(HoverProviderCapability::Simple(true));
6572
Some(())
66-
}
73+
}

crates/emmylua_ls/src/handlers/references/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ pub async fn on_references_handler(
2424
document.get_offset(position.line as usize, position.character as usize)?
2525
};
2626

27+
if position_offset > root.syntax().text_range().end() {
28+
return None;
29+
}
30+
2731
let token = match root.syntax().token_at_offset(position_offset) {
2832
TokenAtOffset::Single(token) => token,
2933
TokenAtOffset::Between(left, right) => {

crates/emmylua_ls/src/handlers/rename/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ pub async fn on_rename_handler(
2727
document.get_offset(position.line as usize, position.character as usize)?
2828
};
2929

30+
if position_offset > root.syntax().text_range().end() {
31+
return None;
32+
}
33+
3034
let token = match root.syntax().token_at_offset(position_offset) {
3135
TokenAtOffset::Single(token) => token,
3236
TokenAtOffset::Between(left, right) => {
@@ -65,6 +69,10 @@ pub async fn on_prepare_rename_handler(
6569
document.get_offset(position.line as usize, position.character as usize)?
6670
};
6771

72+
if position_offset > root.syntax().text_range().end() {
73+
return None;
74+
}
75+
6876
let token = match root.syntax().token_at_offset(position_offset) {
6977
TokenAtOffset::Single(token) => token,
7078
TokenAtOffset::Between(left, right) => {

0 commit comments

Comments
 (0)