diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/bind_type/mod.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/common/bind_type.rs similarity index 82% rename from crates/emmylua_code_analysis/src/compilation/analyzer/bind_type/mod.rs rename to crates/emmylua_code_analysis/src/compilation/analyzer/common/bind_type.rs index 9c5c13a29..db2d4e43b 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/bind_type/mod.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/common/bind_type.rs @@ -1,9 +1,8 @@ -mod migrate_global_member; -use migrate_global_member::migrate_global_members_when_type_resolve; use rowan::TextRange; use crate::{ InFiled, LuaMemberId, LuaTypeCache, LuaTypeOwner, + compilation::analyzer::common::migrate_global_member::migrate_global_members_when_type_resolve, db_index::{DbIndex, LuaMemberOwner, LuaType, LuaTypeDeclId}, }; @@ -43,9 +42,12 @@ pub fn bind_type( } } - db.get_type_index_mut() - .bind_type(type_owner.clone(), type_cache); - migrate_global_members_when_type_resolve(db, type_owner); + if db + .get_type_index_mut() + .bind_type(type_owner.clone(), type_cache) + { + migrate_global_members_when_type_resolve(db, type_owner); + } } else { let decl_type = decl_type_cache?.as_type(); merge_def_type(db, decl_type.clone(), type_cache.as_type().clone(), 0); @@ -95,6 +97,13 @@ fn merge_def_type_with_table( } pub fn add_member(db: &mut DbIndex, owner: LuaMemberOwner, member_id: LuaMemberId) -> Option<()> { + let old_member_owner = db.get_member_index().get_current_owner(&member_id); + if let Some(old_owner) = old_member_owner { + if old_owner == &owner { + return None; // Already exists + } + } + db.get_member_index_mut() .set_member_owner(owner.clone(), member_id.file_id, member_id); db.get_member_index_mut() @@ -102,13 +111,3 @@ pub fn add_member(db: &mut DbIndex, owner: LuaMemberOwner, member_id: LuaMemberI Some(()) } - -fn get_owner_id(db: &DbIndex, type_owner: &LuaTypeOwner) -> Option { - let type_cache = db.get_type_index().get_type_cache(&type_owner)?; - match type_cache.as_type() { - LuaType::Ref(type_id) => Some(LuaMemberOwner::Type(type_id.clone())), - LuaType::TableConst(id) => Some(LuaMemberOwner::Element(id.clone())), - LuaType::Instance(inst) => Some(LuaMemberOwner::Element(inst.get_range().clone())), - _ => None, - } -} diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/common/member.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/common/member.rs new file mode 100644 index 000000000..1f5bad940 --- /dev/null +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/common/member.rs @@ -0,0 +1,132 @@ +use std::vec; + +use emmylua_parser::{LuaAstNode, LuaExpr, LuaIndexExpr, LuaIndexKey, LuaNameExpr}; + +use crate::{DbIndex, FileId, GlobalId, LuaDeclId, LuaMemberOwner, LuaType}; + +// todo + +pub fn get_name_expr_member_owner( + db: &DbIndex, + file_id: FileId, + name_expr: &LuaNameExpr, +) -> Option { + let decl_id = LuaDeclId::new(file_id, name_expr.get_position()); + if let Some(owner) = get_decl_member_owner(&db, &decl_id) { + return Some(owner); + } + + let decl_tree = db.get_decl_index().get_decl_tree(&file_id)?; + let name = name_expr.get_name_text()?; + let prev_decl = decl_tree.find_local_decl(&name, name_expr.get_position())?; + + if !prev_decl.is_implicit_self() { + return get_decl_member_owner(db, &prev_decl.get_id()) + } + + let root = name_expr.get_root(); + let syntax_id = prev_decl.get_syntax_id(); + let token = syntax_id.to_token_from_root(&root)?; + let index_expr = LuaIndexExpr::cast(token.parent()?)?; + let LuaExpr::NameExpr(prefix_name_expr) = index_expr.get_prefix_expr()? else { + return None; + }; + + get_name_expr_member_owner(db, file_id, &prefix_name_expr) +} + +pub fn get_decl_member_owner(db: &DbIndex, decl_id: &LuaDeclId) -> Option { + if let Some(type_cache) = db.get_type_index().get_type_cache(&decl_id.clone().into()) { + let decl_type = type_cache.as_type(); + match decl_type { + LuaType::Def(type_id) => { + return Some(LuaMemberOwner::Type(type_id.clone())); + } + LuaType::GlobalTable(global_id) => { + return Some(LuaMemberOwner::GlobalId(GlobalId(global_id.clone()))); + } + LuaType::TableConst(table_const) => { + return Some(LuaMemberOwner::Element(table_const.clone())); + } + LuaType::Instance(inst) => { + return Some(LuaMemberOwner::Element(inst.get_range().clone())) + } + _ => return None, + } + } + + let decl = db.get_decl_index().get_decl(decl_id)?; + + if decl.is_global() { + return Some(LuaMemberOwner::GlobalId(GlobalId::new(decl.get_name()))); + } + + None + // Some(LuaMemberOwner::LocalDeclId(decl_id.clone())) +} + +pub fn get_global_path( + db: &DbIndex, + file_id: FileId, + index_expr: &LuaIndexExpr, +) -> Option { + let mut prefix_expr = index_expr.get_prefix_expr()?; + let mut paths = vec![index_expr.clone()]; + loop { + match &prefix_expr { + LuaExpr::NameExpr(name_expr) => { + let owner_id = get_name_expr_member_owner(db, file_id, &name_expr)?; + match owner_id { + LuaMemberOwner::GlobalId(global_id) => { + let base_name = global_id.get_name(); + match paths.len() { + 0 => return Some(GlobalId::new(base_name)), + 1 => { + if let Some(name) = to_path_name(&paths[0]) { + return Some(GlobalId::new(&format!("{}.{}", base_name, name))); + } else { + return None; + } + } + _ => { + let mut path = base_name.to_string(); + for path_expr in paths.iter().rev() { + if let Some(name) = to_path_name(path_expr) { + // general this path is not too long + path.push_str(&format!(".{}", name)); + } + } + return Some(GlobalId::new(&path)); + } + } + } + _ => return None, + }; + } + LuaExpr::IndexExpr(index_expr) => { + paths.push(index_expr.clone()); + prefix_expr = index_expr.get_prefix_expr()?; + } + _ => return None, + } + } +} + +fn to_path_name(index_expr: &LuaIndexExpr) -> Option { + match index_expr.get_index_key()? { + LuaIndexKey::String(s) => { + return Some(s.get_value()); + } + LuaIndexKey::Name(name) => { + return Some(name.get_name_text().to_string()); + } + LuaIndexKey::Integer(i) => { + return Some(i.get_int_value().to_string()); + } + LuaIndexKey::Idx(idx) => { + let text = format!("[{}]", idx); + return Some(text); + } + _ => return None, + } +} diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/bind_type/migrate_global_member.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/common/migrate_global_member.rs similarity index 72% rename from crates/emmylua_code_analysis/src/compilation/analyzer/bind_type/migrate_global_member.rs rename to crates/emmylua_code_analysis/src/compilation/analyzer/common/migrate_global_member.rs index e30b748d2..b483e43d6 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/bind_type/migrate_global_member.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/common/migrate_global_member.rs @@ -1,6 +1,7 @@ -use crate::{DbIndex, GlobalId, LuaDeclId, LuaMemberId, LuaMemberOwner, LuaTypeOwner}; - -use super::get_owner_id; +use crate::{ + DbIndex, GlobalId, LuaDeclId, LuaMemberId, LuaMemberOwner, LuaTypeOwner, + compilation::analyzer::common::{add_member, get_owner_id}, +}; pub fn migrate_global_members_when_type_resolve( db: &mut DbIndex, @@ -30,28 +31,27 @@ fn migrate_global_member_to_decl(db: &mut DbIndex, decl_id: LuaDeclId) -> Option let global_id = GlobalId::new(name.into()); let members = db .get_member_index() - .get_members(&LuaMemberOwner::GlobalPath(global_id))? + .get_members(&LuaMemberOwner::GlobalId(global_id))? .iter() .map(|member| member.get_id()) .collect::>(); - let member_index = db.get_member_index_mut(); for member_id in members { - member_index.set_member_owner(owner_id.clone(), member_id.file_id, member_id); - member_index.add_member_to_owner(owner_id.clone(), member_id); + add_member(db, owner_id.clone(), member_id); } Some(()) } fn migrate_global_member_to_member(db: &mut DbIndex, member_id: LuaMemberId) -> Option<()> { - let member = db.get_member_index().get_member(&member_id)?; - let global_id = member.get_global_id()?; + let global_id = db + .get_member_index() + .get_member_global_id(&member_id)?; let owner_id = get_owner_id(db, &member_id.clone().into())?; let members = db .get_member_index() - .get_members(&LuaMemberOwner::GlobalPath(global_id.clone()))? + .get_members(&LuaMemberOwner::GlobalId(global_id.clone()))? .iter() .map(|member| member.get_id()) .collect::>(); diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/common/mod.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/common/mod.rs new file mode 100644 index 000000000..1aa76f092 --- /dev/null +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/common/mod.rs @@ -0,0 +1,20 @@ +mod bind_type; +mod member; +mod migrate_global_member; + +pub use bind_type::{add_member, bind_type}; +pub use member::*; + +use crate::{DbIndex, GlobalId, LuaMemberOwner, LuaType, LuaTypeOwner}; + + +fn get_owner_id(db: &DbIndex, type_owner: &LuaTypeOwner) -> Option { + let type_cache = db.get_type_index().get_type_cache(&type_owner)?; + match type_cache.as_type() { + LuaType::Ref(type_id) => Some(LuaMemberOwner::Type(type_id.clone())), + LuaType::TableConst(id) => Some(LuaMemberOwner::Element(id.clone())), + LuaType::Instance(inst) => Some(LuaMemberOwner::Element(inst.get_range().clone())), + LuaType::GlobalTable(inst) => Some(LuaMemberOwner::GlobalId(GlobalId(inst.clone()))), + _ => None, + } +} diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/decl/exprs.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/decl/exprs.rs index 4ffea5c11..e6c90ad1e 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/decl/exprs.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/decl/exprs.rs @@ -1,14 +1,11 @@ use emmylua_parser::{ - LuaAst, LuaAstNode, LuaAstToken, LuaCallExpr, LuaClosureExpr, LuaDocTagCast, LuaExpr, - LuaFuncStat, LuaIndexExpr, LuaIndexKey, LuaLiteralExpr, LuaLiteralToken, LuaNameExpr, - LuaTableExpr, LuaVarExpr, + LuaAst, LuaAstNode, LuaAstToken, LuaCallExpr, LuaClosureExpr, LuaExpr, LuaFuncStat, + LuaIndexExpr, LuaIndexKey, LuaLiteralExpr, LuaLiteralToken, LuaNameExpr, LuaVarExpr, }; use crate::{ - FileId, InFiled, InferFailReason, LuaDeclExtra, LuaDeclId, LuaMemberFeature, LuaMemberId, - LuaSignatureId, - compilation::analyzer::unresolve::UnResolveTableField, - db_index::{LuaDecl, LuaMember, LuaMemberKey, LuaMemberOwner}, + FileId, LuaDeclExtra, LuaDeclId, LuaMemberId, LuaSignatureId, + db_index::{LuaDecl, LuaMemberKey}, }; use super::DeclAnalyzer; @@ -51,9 +48,6 @@ pub fn analyze_name_expr(analyzer: &mut DeclAnalyzer, expr: LuaNameExpr) -> Opti } pub fn analyze_index_expr(analyzer: &mut DeclAnalyzer, index_expr: LuaIndexExpr) -> Option<()> { - if index_expr.ancestors::().next().is_some() { - return Some(()); - } let index_key = index_expr.get_index_key()?; let key = match index_key { LuaIndexKey::Name(name) => LuaMemberKey::Name(name.get_name_text().to_string().into()), @@ -214,67 +208,67 @@ fn analyze_closure_params( Some(()) } -pub fn analyze_table_expr(analyzer: &mut DeclAnalyzer, table_expr: LuaTableExpr) -> Option<()> { - if table_expr.is_object() { - let file_id = analyzer.get_file_id(); - let owner_id = LuaMemberOwner::Element(InFiled { - file_id, - value: table_expr.get_range(), - }); - let decl_feature = if analyzer.is_meta { - LuaMemberFeature::MetaDefine - } else { - LuaMemberFeature::FileDefine - }; - - for field in table_expr.get_fields() { - if let Some(field_key) = field.get_field_key() { - let key: LuaMemberKey = match field_key { - LuaIndexKey::Name(name) => LuaMemberKey::Name(name.get_name_text().into()), - LuaIndexKey::String(str) => LuaMemberKey::Name(str.get_value().into()), - LuaIndexKey::Integer(i) => LuaMemberKey::Integer(i.get_int_value()), - LuaIndexKey::Idx(idx) => LuaMemberKey::Integer(idx as i64), - LuaIndexKey::Expr(field_expr) => { - let unresolve_member = UnResolveTableField { - file_id: analyzer.get_file_id(), - table_expr: table_expr.clone(), - field: field.clone(), - decl_feature, - }; - analyzer.context.add_unresolve( - unresolve_member.into(), - InferFailReason::UnResolveExpr(InFiled::new( - analyzer.get_file_id(), - field_expr.clone(), - )), - ); - continue; - } - }; - - analyzer.db.get_reference_index_mut().add_index_reference( - key.clone(), - file_id, - field.get_syntax_id(), - ); - - let member_id = LuaMemberId::new(field.get_syntax_id(), file_id); - let member = match &owner_id { - LuaMemberOwner::GlobalPath(path) => { - LuaMember::new(member_id, key, decl_feature, Some(path.clone())) - } - _ => LuaMember::new(member_id, key, decl_feature, None), - }; - analyzer - .db - .get_member_index_mut() - .add_member(owner_id.clone(), member); - } - } - } - - Some(()) -} +// pub fn analyze_table_expr(analyzer: &mut DeclAnalyzer, table_expr: LuaTableExpr) -> Option<()> { +// if table_expr.is_object() { +// let file_id = analyzer.get_file_id(); +// let owner_id = LuaMemberOwner::Element(InFiled { +// file_id, +// value: table_expr.get_range(), +// }); +// let decl_feature = if analyzer.is_meta { +// LuaMemberFeature::MetaDefine +// } else { +// LuaMemberFeature::FileDefine +// }; + +// for field in table_expr.get_fields() { +// if let Some(field_key) = field.get_field_key() { +// let key: LuaMemberKey = match field_key { +// LuaIndexKey::Name(name) => LuaMemberKey::Name(name.get_name_text().into()), +// LuaIndexKey::String(str) => LuaMemberKey::Name(str.get_value().into()), +// LuaIndexKey::Integer(i) => LuaMemberKey::Integer(i.get_int_value()), +// LuaIndexKey::Idx(idx) => LuaMemberKey::Integer(idx as i64), +// LuaIndexKey::Expr(field_expr) => { +// // let unresolve_member = UnResolveTableField { +// // file_id: analyzer.get_file_id(), +// // table_expr: table_expr.clone(), +// // field: field.clone(), +// // decl_feature, +// // }; +// // analyzer.context.add_unresolve( +// // unresolve_member.into(), +// // InferFailReason::UnResolveExpr(InFiled::new( +// // analyzer.get_file_id(), +// // field_expr.clone(), +// // )), +// // ); +// continue; +// } +// }; + +// analyzer.db.get_reference_index_mut().add_index_reference( +// key.clone(), +// file_id, +// field.get_syntax_id(), +// ); + +// let member_id = LuaMemberId::new(field.get_syntax_id(), file_id); +// let member = match &owner_id { +// LuaMemberOwner::GlobalPath(path) => { +// LuaMember::new(member_id, key, decl_feature, Some(path.clone())) +// } +// _ => LuaMember::new(member_id, key, decl_feature, None), +// }; +// analyzer +// .db +// .get_member_index_mut() +// .add_member(owner_id.clone(), member); +// } +// } +// } + +// Some(()) +// } pub fn analyze_literal_expr(analyzer: &mut DeclAnalyzer, expr: LuaLiteralExpr) -> Option<()> { let literal = expr.get_literal()?; diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/decl/members.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/decl/members.rs deleted file mode 100644 index 22f435013..000000000 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/decl/members.rs +++ /dev/null @@ -1,88 +0,0 @@ -use emmylua_parser::{LuaAstNode, LuaExpr, LuaIndexExpr, PathTrait}; -use smol_str::SmolStr; - -use crate::{GlobalId, LuaMemberOwner}; - -use super::DeclAnalyzer; - -pub fn find_index_owner( - analyzer: &mut DeclAnalyzer, - index_expr: LuaIndexExpr, -) -> (LuaMemberOwner, Option) { - if is_in_global_member(analyzer, &index_expr).unwrap_or(false) { - if let Some(prefix_expr) = index_expr.get_prefix_expr() { - match prefix_expr { - LuaExpr::IndexExpr(parent_index_expr) => { - if let Some(parent_access_path) = parent_index_expr.get_access_path() { - if let Some(access_path) = index_expr.get_access_path() { - return ( - LuaMemberOwner::GlobalPath(GlobalId( - SmolStr::new(parent_access_path).into(), - )), - Some(GlobalId(SmolStr::new(access_path).into())), - ); - } - - return ( - LuaMemberOwner::GlobalPath(GlobalId( - SmolStr::new(parent_access_path).into(), - )), - None, - ); - } - } - LuaExpr::NameExpr(name) => { - if let Some(parent_path) = name.get_name_text() { - if parent_path == "self" { - return (LuaMemberOwner::LocalUnresolve, None); - } - - if let Some(access_path) = index_expr.get_access_path() { - return ( - LuaMemberOwner::GlobalPath(GlobalId( - SmolStr::new(parent_path).into(), - )), - Some(GlobalId(SmolStr::new(access_path).into())), - ); - } - - return ( - LuaMemberOwner::GlobalPath(GlobalId(SmolStr::new(parent_path).into())), - None, - ); - } - } - _ => {} - } - } else { - if let Some(access_path) = index_expr.get_access_path() { - return ( - LuaMemberOwner::LocalUnresolve, - Some(GlobalId(SmolStr::new(access_path).into())), - ); - } - } - } - - (LuaMemberOwner::LocalUnresolve, None) -} - -fn is_in_global_member(analyzer: &DeclAnalyzer, index_expr: &LuaIndexExpr) -> Option { - let prefix = index_expr.get_prefix_expr()?; - match prefix { - LuaExpr::IndexExpr(index_expr) => { - return is_in_global_member(analyzer, &index_expr); - } - LuaExpr::NameExpr(name) => { - let name_text = name.get_name_text()?; - if name_text == "self" { - return Some(false); - } - - let decl = analyzer.find_decl(&name_text, name.get_position()); - return Some(decl.is_none()); - } - _ => {} - } - None -} diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/decl/mod.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/decl/mod.rs index fc86b0afb..5780f32c9 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/decl/mod.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/decl/mod.rs @@ -1,15 +1,15 @@ mod docs; mod exprs; -mod members; mod stats; use crate::{ + compilation::analyzer::AnalysisPipeline, db_index::{DbIndex, LuaScopeKind}, profile::Profile, }; use super::AnalyzeContext; -use emmylua_parser::{LuaAst, LuaAstNode, LuaChunk, LuaFuncStat, LuaSyntaxKind, LuaVarExpr}; +use emmylua_parser::{LuaAst, LuaAstNode, LuaFuncStat, LuaSyntaxKind, LuaVarExpr}; use rowan::{TextRange, TextSize, WalkEvent}; use crate::{ @@ -17,21 +17,25 @@ use crate::{ db_index::{LuaDecl, LuaDeclId, LuaDeclarationTree, LuaScopeId}, }; -pub(crate) fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext) { - let _p = Profile::cond_new("decl analyze", context.tree_list.len() > 1); - let tree_list = context.tree_list.clone(); - for in_filed_tree in tree_list.iter() { - db.get_reference_index_mut() - .create_local_reference(in_filed_tree.file_id); - let mut analyzer = DeclAnalyzer::new( - db, - in_filed_tree.file_id, - in_filed_tree.value.clone(), - context, - ); - analyzer.analyze(); - let decl_tree = analyzer.get_decl_tree(); - db.get_decl_index_mut().add_decl_tree(decl_tree); +pub struct DeclAnalysisPipeline; + +impl AnalysisPipeline for DeclAnalysisPipeline { + fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext) { + let _p = Profile::cond_new("decl analyze", context.tree_list.len() > 1); + let tree_list = context.tree_list.clone(); + for in_filed_tree in tree_list.iter() { + db.get_reference_index_mut() + .create_local_reference(in_filed_tree.file_id); + let mut analyzer = DeclAnalyzer::new(db, in_filed_tree.file_id); + for walk_event in in_filed_tree.value.walk_descendants::() { + match walk_event { + WalkEvent::Enter(node) => walk_node_enter(&mut analyzer, node), + WalkEvent::Leave(node) => walk_node_leave(&mut analyzer, node), + } + } + let decl_tree = analyzer.get_decl_tree(); + db.get_decl_index_mut().add_decl_tree(decl_tree); + } } } @@ -84,9 +88,6 @@ fn walk_node_enter(analyzer: &mut DeclAnalyzer, node: LuaAst) { analyzer.create_scope(expr.get_range(), LuaScopeKind::Normal); exprs::analyze_closure_expr(analyzer, expr); } - LuaAst::LuaTableExpr(expr) => { - exprs::analyze_table_expr(analyzer, expr); - } LuaAst::LuaLiteralExpr(expr) => { exprs::analyze_literal_expr(analyzer, expr); } @@ -140,37 +141,18 @@ fn is_scope_owner(node: &LuaAst) -> bool { #[derive(Debug)] pub struct DeclAnalyzer<'a> { db: &'a mut DbIndex, - root: LuaChunk, decl: LuaDeclarationTree, scopes: Vec, is_meta: bool, - context: &'a mut AnalyzeContext, } impl<'a> DeclAnalyzer<'a> { - pub fn new( - db: &'a mut DbIndex, - file_id: FileId, - root: LuaChunk, - context: &'a mut AnalyzeContext, - ) -> DeclAnalyzer<'a> { + pub fn new(db: &'a mut DbIndex, file_id: FileId) -> DeclAnalyzer<'a> { DeclAnalyzer { db, - root, decl: LuaDeclarationTree::new(file_id), scopes: Vec::new(), is_meta: false, - context, - } - } - - pub fn analyze(&mut self) { - let root = self.root.clone(); - for walk_event in root.walk_descendants::() { - match walk_event { - WalkEvent::Enter(node) => walk_node_enter(self, node), - WalkEvent::Leave(node) => walk_node_leave(self, node), - } } } diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/decl/stats.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/decl/stats.rs index a4f5a2ae1..f8cecccc9 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/decl/stats.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/decl/stats.rs @@ -5,13 +5,12 @@ use emmylua_parser::{ }; use crate::{ - LuaDeclExtra, LuaMemberFeature, LuaMemberId, LuaSemanticDeclId, LuaSignatureId, LuaType, - LuaTypeCache, - compilation::analyzer::bind_type::bind_type, - db_index::{LocalAttribute, LuaDecl, LuaMember, LuaMemberKey}, + LuaDeclExtra, LuaMemberId, LuaSemanticDeclId, LuaSignatureId, LuaType, LuaTypeCache, + compilation::analyzer::common::bind_type, + db_index::{LocalAttribute, LuaDecl}, }; -use super::{DeclAnalyzer, members::find_index_owner}; +use super::DeclAnalyzer; pub fn analyze_local_stat(analyzer: &mut DeclAnalyzer, stat: LuaLocalStat) -> Option<()> { let local_name_list = stat.get_local_name_list().collect::>(); @@ -96,32 +95,31 @@ pub fn analyze_assign_stat(analyzer: &mut DeclAnalyzer, stat: LuaAssignStat) -> } } LuaVarExpr::IndexExpr(index_expr) => { - let index_key = index_expr.get_index_key()?; - let key: LuaMemberKey = match index_key { - LuaIndexKey::Name(name) => LuaMemberKey::Name(name.get_name_text().into()), - LuaIndexKey::String(str) => LuaMemberKey::Name(str.get_value().into()), - LuaIndexKey::Integer(i) => LuaMemberKey::Integer(i.get_int_value()), - LuaIndexKey::Idx(idx) => LuaMemberKey::Integer(idx as i64), - LuaIndexKey::Expr(_) => { - continue; - } - }; - - let file_id = analyzer.get_file_id(); - let member_id = LuaMemberId::new(index_expr.get_syntax_id(), file_id); - let decl_feature = if analyzer.is_meta { - LuaMemberFeature::MetaDefine - } else { - LuaMemberFeature::FileDefine - }; - - let (owner, global_id) = find_index_owner(analyzer, index_expr.clone()); - let member = LuaMember::new(member_id, key.clone(), decl_feature, global_id); - - analyzer.db.get_member_index_mut().add_member(owner, member); - if let LuaMemberKey::Name(name) = &key { - analyze_maybe_global_index_expr(analyzer, index_expr, &name, value_expr_id); - } + // let index_key = index_expr.get_index_key()?; + // let key: LuaMemberKey = match index_key { + // LuaIndexKey::Name(name) => LuaMemberKey::Name(name.get_name_text().into()), + // LuaIndexKey::String(str) => LuaMemberKey::Name(str.get_value().into()), + // LuaIndexKey::Integer(i) => LuaMemberKey::Integer(i.get_int_value()), + // LuaIndexKey::Idx(idx) => LuaMemberKey::Integer(idx as i64), + // LuaIndexKey::Expr(_) => { + // continue; + // } + // }; + + // let file_id = analyzer.get_file_id(); + // let member_id = LuaMemberId::new(index_expr.get_syntax_id(), file_id); + // let decl_feature = if analyzer.is_meta { + // LuaMemberFeature::MetaDefine + // } else { + // LuaMemberFeature::FileDefine + // }; + + // let (owner, global_id) = find_index_owner(analyzer, index_expr.clone()); + // let member = LuaMember::new(member_id, key.clone(), decl_feature, global_id); + + // analyzer.db.get_member_index_mut().add_member(owner, member); + + analyze_maybe_global_index_expr(analyzer, index_expr, value_expr_id); } } } @@ -132,19 +130,25 @@ pub fn analyze_assign_stat(analyzer: &mut DeclAnalyzer, stat: LuaAssignStat) -> fn analyze_maybe_global_index_expr( analyzer: &mut DeclAnalyzer, index_expr: &LuaIndexExpr, - index_name: &str, value_expr_id: Option, ) -> Option<()> { let file_id = analyzer.get_file_id(); let prefix = index_expr.get_prefix_expr()?; if let LuaExpr::NameExpr(name_expr) = prefix { - let name_token = name_expr.get_name_token()?; - let name_token_text = name_token.get_name_text(); - if name_token_text == "_G" || name_token_text == "_ENV" { + let prefix_name_token = name_expr.get_name_token()?; + let prefix_name_token_text = prefix_name_token.get_name_text(); + if prefix_name_token_text == "_G" || prefix_name_token_text == "_ENV" { let position = index_expr.get_position(); - let name = name_token.get_name_text(); + let index_key = index_expr.get_index_key()?; + let index_name = match index_key { + LuaIndexKey::Name(name) => name.get_name_text().to_string(), + LuaIndexKey::String(str) => str.get_value(), + _ => { + return None; + } + }; let range = index_expr.get_range(); - if let Some(decl) = analyzer.find_decl(&name, position) { + if let Some(decl) = analyzer.find_decl(&index_name, position) { let decl_id = decl.get_id(); analyzer .db @@ -152,7 +156,7 @@ fn analyze_maybe_global_index_expr( .add_decl_reference(decl_id, file_id, range, true); } else { let decl = LuaDecl::new( - index_name, + &index_name, file_id, range, LuaDeclExtra::Global { @@ -244,35 +248,32 @@ pub fn analyze_func_stat(analyzer: &mut DeclAnalyzer, stat: LuaFuncStat) -> Opti } } LuaVarExpr::IndexExpr(index_expr) => { - let index_key = index_expr.get_index_key()?; - let key: LuaMemberKey = match index_key { - LuaIndexKey::Name(name) => LuaMemberKey::Name(name.get_name_text().into()), - LuaIndexKey::String(str) => LuaMemberKey::Name(str.get_value().into()), - LuaIndexKey::Integer(i) => LuaMemberKey::Integer(i.get_int_value()), - LuaIndexKey::Idx(idx) => LuaMemberKey::Integer(idx as i64), - LuaIndexKey::Expr(_) => { - return None; - } - }; - + // let index_key = index_expr.get_index_key()?; + // let key: LuaMemberKey = match index_key { + // LuaIndexKey::Name(name) => LuaMemberKey::Name(name.get_name_text().into()), + // LuaIndexKey::String(str) => LuaMemberKey::Name(str.get_value().into()), + // LuaIndexKey::Integer(i) => LuaMemberKey::Integer(i.get_int_value()), + // LuaIndexKey::Idx(idx) => LuaMemberKey::Integer(idx as i64), + // LuaIndexKey::Expr(_) => { + // return None; + // } + // }; + + // let decl_feature = if analyzer.is_meta { + // LuaMemberFeature::MetaMethodDecl + // } else { + // LuaMemberFeature::FileMethodDecl + // }; + + // let (owner_id, global_id) = find_index_owner(analyzer, index_expr.clone()); + // let member = LuaMember::new(member_id, key.clone(), decl_feature, global_id); + // let member_id = analyzer + // .db + // .get_member_index_mut() + // .add_member(owner_id, member); let file_id = analyzer.get_file_id(); let member_id = LuaMemberId::new(index_expr.get_syntax_id(), file_id); - let decl_feature = if analyzer.is_meta { - LuaMemberFeature::MetaMethodDecl - } else { - LuaMemberFeature::FileMethodDecl - }; - - let (owner_id, global_id) = find_index_owner(analyzer, index_expr.clone()); - let member = LuaMember::new(member_id, key.clone(), decl_feature, global_id); - let member_id = analyzer - .db - .get_member_index_mut() - .add_member(owner_id, member); - - if let LuaMemberKey::Name(name) = &key { - analyze_maybe_global_index_expr(analyzer, &index_expr, &name, None); - } + analyze_maybe_global_index_expr(analyzer, &index_expr, None); LuaSemanticDeclId::Member(member_id) } }; @@ -311,11 +312,11 @@ pub fn analyze_local_func_stat(analyzer: &mut DeclAnalyzer, stat: LuaLocalFuncSt let closure = stat.get_closure()?; let closure_owner_id = LuaSemanticDeclId::Signature(LuaSignatureId::from_closure(file_id, &closure)); - let property_decl_id = LuaSemanticDeclId::LuaDecl(decl_id); + let semantic_decl_id = LuaSemanticDeclId::LuaDecl(decl_id); analyzer .db .get_property_index_mut() - .add_owner_map(property_decl_id, closure_owner_id, file_id); + .add_owner_map(semantic_decl_id, closure_owner_id, file_id); Some(()) } diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/doc/field_or_operator_def_tags.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/doc/field_or_operator_def_tags.rs index 14dc035f8..e799e0098 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/doc/field_or_operator_def_tags.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/doc/field_or_operator_def_tags.rs @@ -118,7 +118,7 @@ pub fn analyze_field(analyzer: &mut DocAnalyzer, tag: LuaDocTagField) -> Option< LuaMemberFeature::FileFieldDecl }; - let member = LuaMember::new(member_id, key.clone(), decl_feature, None); + let member = LuaMember::new(member_id, key.clone(), decl_feature); analyzer.db.get_reference_index_mut().add_index_reference( key, analyzer.file_id, diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/doc/mod.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/doc/mod.rs index 98494059d..3cc5b53d5 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/doc/mod.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/doc/mod.rs @@ -10,6 +10,7 @@ mod type_ref_tags; use super::AnalyzeContext; use crate::{ FileId, LuaSemanticDeclId, + compilation::analyzer::AnalysisPipeline, db_index::{DbIndex, LuaTypeDeclId}, profile::Profile, }; @@ -17,22 +18,26 @@ use emmylua_parser::{LuaAstNode, LuaComment, LuaSyntaxNode}; use file_generic_index::FileGenericIndex; use tags::get_owner_id; -pub(crate) fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext) { - let _p = Profile::cond_new("doc analyze", context.tree_list.len() > 1); - let tree_list = context.tree_list.clone(); - for in_filed_tree in tree_list.iter() { - let root = &in_filed_tree.value; - let mut generic_index = FileGenericIndex::new(); - for comment in root.descendants::() { - let mut analyzer = DocAnalyzer::new( - db, - in_filed_tree.file_id, - &mut generic_index, - comment, - root.syntax().clone(), - context, - ); - analyze_comment(&mut analyzer); +pub struct DocAnalysisPipeline; + +impl AnalysisPipeline for DocAnalysisPipeline { + fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext) { + let _p = Profile::cond_new("doc analyze", context.tree_list.len() > 1); + let tree_list = context.tree_list.clone(); + for in_filed_tree in tree_list.iter() { + let root = &in_filed_tree.value; + let mut generic_index = FileGenericIndex::new(); + for comment in root.descendants::() { + let mut analyzer = DocAnalyzer::new( + db, + in_filed_tree.file_id, + &mut generic_index, + comment, + root.syntax().clone(), + context, + ); + analyze_comment(&mut analyzer); + } } } } diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/doc/type_def_tags.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/doc/type_def_tags.rs index fcfada489..3d6645c0e 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/doc/type_def_tags.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/doc/type_def_tags.rs @@ -14,7 +14,7 @@ use super::{ use crate::compilation::analyzer::doc::tags::report_orphan_tag; use crate::{ LuaTypeCache, LuaTypeDeclId, - compilation::analyzer::bind_type::bind_type, + compilation::analyzer::common::bind_type, db_index::{LuaDeclId, LuaMemberId, LuaSemanticDeclId, LuaSignatureId, LuaType}, }; diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/doc/type_ref_tags.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/doc/type_ref_tags.rs index 00e0014cf..6747fcbdc 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/doc/type_ref_tags.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/doc/type_ref_tags.rs @@ -17,7 +17,7 @@ use crate::compilation::analyzer::doc::tags::{ use crate::{ InFiled, InferFailReason, LuaOperatorMetaMethod, LuaTypeCache, LuaTypeOwner, OperatorFunction, SignatureReturnStatus, TypeOps, - compilation::analyzer::{bind_type::bind_type, unresolve::UnResolveModuleRef}, + compilation::analyzer::{common::bind_type, unresolve::UnResolveModuleRef}, db_index::{ LuaDeclId, LuaDocParamInfo, LuaDocReturnInfo, LuaMemberId, LuaOperator, LuaSemanticDeclId, LuaSignatureId, LuaType, @@ -386,7 +386,7 @@ pub fn analyze_cast(analyzer: &mut DocAnalyzer, tag: LuaDocTagCast) -> Option<() } pub fn analyze_see(analyzer: &mut DocAnalyzer, tag: LuaDocTagSee) -> Option<()> { - let owner = get_owner_id_or_report(analyzer, &tag)?; + let owner = get_owner_id(analyzer)?; let content = tag.get_see_content()?; let text = content.get_text(); diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/flow/mod.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/flow/mod.rs index 0453b1d98..2110a1383 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/flow/mod.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/flow/mod.rs @@ -2,9 +2,12 @@ mod bind_analyze; mod binder; use crate::{ - compilation::analyzer::flow::{ - bind_analyze::{bind_analyze, check_goto_label}, - binder::FlowBinder, + compilation::analyzer::{ + AnalysisPipeline, + flow::{ + bind_analyze::{bind_analyze, check_goto_label}, + binder::FlowBinder, + }, }, db_index::DbIndex, profile::Profile, @@ -12,17 +15,21 @@ use crate::{ use super::AnalyzeContext; -pub(crate) fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext) { - let _p = Profile::cond_new("flow analyze", context.tree_list.len() > 1); - let tree_list = context.tree_list.clone(); - // build decl and ref flow chain - for in_filed_tree in &tree_list { - let chunk = in_filed_tree.value.clone(); - let file_id = in_filed_tree.file_id; - let mut binder = FlowBinder::new(db, file_id); - bind_analyze(&mut binder, chunk); - check_goto_label(&mut binder); - let flow_tree = binder.finish(); - db.get_flow_index_mut().add_flow_tree(file_id, flow_tree); +pub struct FlowAnalysisPipeline; + +impl AnalysisPipeline for FlowAnalysisPipeline { + fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext) { + let _p = Profile::cond_new("flow analyze", context.tree_list.len() > 1); + let tree_list = context.tree_list.clone(); + // build decl and ref flow chain + for in_filed_tree in &tree_list { + let chunk = in_filed_tree.value.clone(); + let file_id = in_filed_tree.file_id; + let mut binder = FlowBinder::new(db, file_id); + bind_analyze(&mut binder, chunk); + check_goto_label(&mut binder); + let flow_tree = binder.finish(); + db.get_flow_index_mut().add_flow_tree(file_id, flow_tree); + } } } diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/infer_manager.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/infer_cache_manager.rs similarity index 100% rename from crates/emmylua_code_analysis/src/compilation/analyzer/infer_manager.rs rename to crates/emmylua_code_analysis/src/compilation/analyzer/infer_cache_manager.rs diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/lua/closure.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/lua/closure.rs index 2712e2cae..08a3a82ca 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/lua/closure.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/lua/closure.rs @@ -144,7 +144,7 @@ fn analyze_return( &analyzer.db, &mut analyzer .context - .infer_manager + .infer_caches .get_infer_cache(analyzer.file_id), &return_points, ) { diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/lua/for_range_stat.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/lua/for_range_stat.rs index e5ecf7ab5..cdcbd1449 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/lua/for_range_stat.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/lua/for_range_stat.rs @@ -17,7 +17,7 @@ pub fn analyze_for_range_stat( let iter_exprs = for_range_stat.get_expr_list().collect::>(); let cache = analyzer .context - .infer_manager + .infer_caches .get_infer_cache(analyzer.file_id); let iter_var_types = infer_for_range_iter_expr_func(analyzer.db, cache, &iter_exprs); diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/lua/mod.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/lua/mod.rs index b6349451b..9dfa4a979 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/lua/mod.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/lua/mod.rs @@ -22,6 +22,7 @@ use stats::{ use crate::{ Emmyrc, FileId, InferFailReason, + compilation::analyzer::AnalysisPipeline, db_index::{DbIndex, LuaType}, profile::Profile, semantic::infer_expr, @@ -29,23 +30,27 @@ use crate::{ use super::AnalyzeContext; -pub(crate) fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext) { - let _p = Profile::cond_new("lua analyze", context.tree_list.len() > 1); - let tree_list = context.tree_list.clone(); - let file_ids = tree_list.iter().map(|x| x.file_id).collect::>(); - let tree_map = tree_list - .iter() - .map(|x| (x.file_id, x.value.clone())) - .collect::>(); - let file_dependency = db.get_file_dependencies_index().get_file_dependencies(); - let order = file_dependency.get_best_analysis_order(file_ids.clone()); - for file_id in order { - if let Some(root) = tree_map.get(&file_id) { - let mut analyzer = LuaAnalyzer::new(db, file_id, context); - for node in root.descendants::() { - analyze_node(&mut analyzer, node); +pub struct LuaAnalysisPipeline; + +impl AnalysisPipeline for LuaAnalysisPipeline { + fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext) { + let _p = Profile::cond_new("lua analyze", context.tree_list.len() > 1); + let tree_list = context.tree_list.clone(); + let file_ids = tree_list.iter().map(|x| x.file_id).collect::>(); + let tree_map = tree_list + .iter() + .map(|x| (x.file_id, x.value.clone())) + .collect::>(); + let file_dependency = db.get_file_dependencies_index().get_file_dependencies(); + let order = file_dependency.get_best_analysis_order(file_ids.clone()); + for file_id in order { + if let Some(root) = tree_map.get(&file_id) { + let mut analyzer = LuaAnalyzer::new(db, file_id, context); + for node in root.descendants::() { + analyze_node(&mut analyzer, node); + } + analyze_chunk_return(&mut analyzer, root.clone()); } - analyze_chunk_return(&mut analyzer, root.clone()); } } } @@ -109,7 +114,7 @@ impl LuaAnalyzer<'_> { impl LuaAnalyzer<'_> { pub fn infer_expr(&mut self, expr: &LuaExpr) -> Result { - let cache = self.context.infer_manager.get_infer_cache(self.file_id); + let cache = self.context.infer_caches.get_infer_cache(self.file_id); infer_expr(self.db, cache, expr.clone()) } } diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/lua/stats.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/lua/stats.rs index d7216cf16..48f2905c3 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/lua/stats.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/lua/stats.rs @@ -7,7 +7,7 @@ use crate::{ InFiled, InferFailReason, LuaOperator, LuaOperatorMetaMethod, LuaOperatorOwner, LuaTypeCache, LuaTypeOwner, OperatorFunction, compilation::analyzer::{ - bind_type::{add_member, bind_type}, + common::{add_member, bind_type}, unresolve::{UnResolveDecl, UnResolveMember}, }, db_index::{LuaDeclId, LuaMemberId, LuaMemberOwner, LuaType}, diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/member/members.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/member/members.rs new file mode 100644 index 000000000..b84aaa922 --- /dev/null +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/member/members.rs @@ -0,0 +1,250 @@ +use emmylua_parser::{ + LuaAssignStat, LuaAstNode, LuaExpr, LuaFuncStat, LuaIndexKey, LuaLocalStat, LuaTableExpr, + LuaTableField, LuaVarExpr, +}; + +use crate::{ + InFiled, LuaDeclId, LuaMember, LuaMemberFeature, LuaMemberId, LuaMemberKey, LuaMemberOwner, + LuaType, LuaTypeCache, + compilation::analyzer::{ + common::{bind_type, get_decl_member_owner, get_global_path, get_name_expr_member_owner}, + member::MemberAnalyzer, + }, +}; + +pub fn analyze_local_stat(analyzer: &mut MemberAnalyzer, local_stat: LuaLocalStat) -> Option<()> { + let local_name_list = local_stat.get_local_name_list().collect::>(); + let local_expr_list = local_stat.get_value_exprs().collect::>(); + for i in 0..local_expr_list.len() { + let local_name = local_name_list.get(i)?; + let local_expr = local_expr_list.get(i)?; + if let LuaExpr::TableExpr(table_expr) = local_expr { + let decl_id = LuaDeclId::new(analyzer.file_id, local_name.get_position()); + let owner = match get_decl_member_owner(analyzer.db, &decl_id) { + Some(owner) => owner, + None => { + let table_range = InFiled::new(analyzer.file_id, table_expr.get_range()); + bind_type( + analyzer.db, + decl_id.into(), + LuaTypeCache::InferType(LuaType::TableConst(table_range.clone()).into()), + ); + LuaMemberOwner::Element(table_range) + } + }; + + analyzer.visited_table.insert(table_expr.get_syntax_id()); + + if table_expr.is_object() { + for table_field in table_expr.get_fields() { + if let Some(field_key) = table_field.get_field_key() { + let file_id = analyzer.file_id; + let member_id = LuaMemberId::new(table_field.get_syntax_id(), file_id); + add_field_member(analyzer, owner.clone(), field_key, member_id); + } + } + } + } + } + + Some(()) +} + +pub fn analyze_assign_stat( + analyzer: &mut MemberAnalyzer, + assign_stat: LuaAssignStat, +) -> Option<()> { + let (vars, exprs) = assign_stat.get_var_and_expr_list(); + for i in 0..exprs.len() { + let var = vars.get(i)?; + let expr = exprs.get(i)?; + match (var, expr) { + (LuaVarExpr::IndexExpr(index_expr), _) => { + if let Some(prefix_expr) = index_expr.get_prefix_expr() { + match prefix_expr { + LuaExpr::NameExpr(prefix_name_expr) => { + if let Some(owner) = get_name_expr_member_owner( + &analyzer.db, + analyzer.file_id, + &prefix_name_expr, + ) { + if let Some(field_key) = index_expr.get_index_key() { + let member_id = LuaMemberId::new( + index_expr.get_syntax_id(), + analyzer.file_id, + ); + add_field_member(analyzer, owner.clone(), field_key, member_id); + } + } + } + LuaExpr::IndexExpr(prefix_index_expr) => { + if let Some(global_id) = + get_global_path(&analyzer.db, analyzer.file_id, &prefix_index_expr) + { + if let Some(field_key) = index_expr.get_index_key() { + let member_id = LuaMemberId::new( + index_expr.get_syntax_id(), + analyzer.file_id, + ); + let owner = LuaMemberOwner::GlobalId(global_id); + add_field_member(analyzer, owner, field_key, member_id); + if let Some(current_global_id) = + get_global_path(&analyzer.db, analyzer.file_id, &index_expr) + { + analyzer + .db + .get_member_index_mut() + .add_member_global_id(member_id, current_global_id); + } + } + } + } + _ => {} + } + } + } + (LuaVarExpr::NameExpr(name_expr), LuaExpr::TableExpr(table_expr)) => { + if let Some(owner) = + get_name_expr_member_owner(&analyzer.db, analyzer.file_id, &name_expr) + { + analyzer.visited_table.insert(table_expr.get_syntax_id()); + if table_expr.is_object() { + for table_field in table_expr.get_fields() { + if let Some(field_key) = table_field.get_field_key() { + let file_id = analyzer.file_id; + let member_id = + LuaMemberId::new(table_field.get_syntax_id(), file_id); + add_field_member(analyzer, owner.clone(), field_key, member_id); + } + } + } + } + } + _ => continue, + } + } + + Some(()) +} + +pub fn analyze_func_stat(analyzer: &mut MemberAnalyzer, func_stat: LuaFuncStat) -> Option<()> { + let func_name_expr = func_stat.get_func_name()?; + if let LuaVarExpr::IndexExpr(index_expr) = func_name_expr { + if let Some(LuaExpr::NameExpr(prefix_name_expr)) = index_expr.get_prefix_expr() { + if let Some(owner) = + get_name_expr_member_owner(&analyzer.db, analyzer.file_id, &prefix_name_expr) + { + if let Some(field_key) = index_expr.get_index_key() { + let member_id = LuaMemberId::new(index_expr.get_syntax_id(), analyzer.file_id); + add_field_member(analyzer, owner.clone(), field_key, member_id); + } + } + } + } + + Some(()) +} + +pub fn analyze_table_field( + analyzer: &mut MemberAnalyzer, + table_field: LuaTableField, +) -> Option<()> { + if !table_field.is_assign_field() { + return None; + } + + let value_expr = table_field.get_value_expr()?; + let LuaExpr::TableExpr(table_value) = value_expr else { + return None; + }; + + let member_id = LuaMemberId::new(table_field.get_syntax_id(), analyzer.file_id); + let doc_type = analyzer + .db + .get_type_index() + .get_type_cache(&member_id.into())?; + let owner = match doc_type.as_type() { + LuaType::Def(type_id) => LuaMemberOwner::Type(type_id.clone()), + _ => return None, + }; + + analyzer.visited_table.insert(table_value.get_syntax_id()); + + for field in table_value.get_fields() { + if let Some(field_key) = field.get_field_key() { + add_field_member(analyzer, owner.clone(), field_key, member_id); + } + } + + Some(()) +} + +fn add_field_member( + analyzer: &mut MemberAnalyzer, + member_owner: LuaMemberOwner, + field_key: LuaIndexKey, + member_id: LuaMemberId, +) -> Option<()> { + let decl_feature = if analyzer.is_meta { + LuaMemberFeature::MetaDefine + } else { + LuaMemberFeature::FileDefine + }; + + let key: LuaMemberKey = match field_key { + LuaIndexKey::Name(name) => LuaMemberKey::Name(name.get_name_text().into()), + LuaIndexKey::String(str) => LuaMemberKey::Name(str.get_value().into()), + LuaIndexKey::Integer(i) => LuaMemberKey::Integer(i.get_int_value()), + LuaIndexKey::Idx(idx) => LuaMemberKey::Integer(idx as i64), + LuaIndexKey::Expr(_) => { + // let unresolve_member = UnResolveTableField { + // file_id: analyzer.file_id, + // table_expr: table_expr.clone(), + // field: field.clone(), + // decl_feature, + // }; + // analyzer.context.add_unresolve( + // unresolve_member.into(), + // InferFailReason::UnResolveExpr(InFiled::new( + // analyzer.get_file_id(), + // field_expr.clone(), + // )), + // ); + return None; + } + }; + + let member = LuaMember::new(member_id, key.clone(), decl_feature); + analyzer + .db + .get_member_index_mut() + .add_member(member_owner, member); + + analyzer.db.get_reference_index_mut().add_index_reference( + key, + member_id.file_id, + *member_id.get_syntax_id(), + ); + + Some(()) +} + +pub fn analyze_table_expr(analyzer: &mut MemberAnalyzer, table_expr: LuaTableExpr) -> Option<()> { + if analyzer.visited_table.contains(&table_expr.get_syntax_id()) { + return None; + } + + let in_filed = InFiled::new(analyzer.file_id, table_expr.get_range().clone()); + let owner_id = LuaMemberOwner::Element(in_filed); + + if table_expr.is_object() { + for field in table_expr.get_fields() { + if let Some(field_key) = field.get_field_key() { + let member_id = LuaMemberId::new(field.get_syntax_id(), analyzer.file_id); + add_field_member(analyzer, owner_id.clone(), field_key, member_id); + } + } + } + + Some(()) +} diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/member/mod.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/member/mod.rs new file mode 100644 index 000000000..7e71bd75d --- /dev/null +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/member/mod.rs @@ -0,0 +1,77 @@ +mod members; + +use std::collections::HashSet; + +use emmylua_parser::{LuaAst, LuaAstNode, LuaSyntaxId}; + +use crate::{ + DbIndex, FileId, Profile, + compilation::analyzer::{ + AnalysisPipeline, AnalyzeContext, + member::members::{ + analyze_assign_stat, analyze_func_stat, analyze_local_stat, analyze_table_expr, + analyze_table_field, + }, + }, +}; + +/// Due to the widespread use of global variables in Lua and the various ways to define members, +/// it is impossible to fully analyze them without knowing their types. +/// Therefore, this only tries to identify as many members as possible in advance. +pub struct MemberAnalysisPipeline; + +impl AnalysisPipeline for MemberAnalysisPipeline { + fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext) { + let _p = Profile::cond_new("member analyze", context.tree_list.len() > 1); + let tree_list = context.tree_list.clone(); + for in_filed_tree in tree_list { + let root = &in_filed_tree.value; + let mut analyzer = MemberAnalyzer::new(db, in_filed_tree.file_id, context); + for node in root.descendants::() { + match node { + LuaAst::LuaLocalStat(local_stat) => { + analyze_local_stat(&mut analyzer, local_stat); + } + LuaAst::LuaAssignStat(assign_stat) => { + analyze_assign_stat(&mut analyzer, assign_stat); + } + LuaAst::LuaFuncStat(func_stat) => { + analyze_func_stat(&mut analyzer, func_stat); + } + LuaAst::LuaTableField(table_field) => { + analyze_table_field(&mut analyzer, table_field); + } + LuaAst::LuaTableExpr(table_expr) => { + analyze_table_expr(&mut analyzer, table_expr); + } + _ => {} + } + } + } + } +} + +struct MemberAnalyzer<'a> { + db: &'a mut DbIndex, + file_id: FileId, + #[allow(unused)] + context: &'a mut AnalyzeContext, + is_meta: bool, + visited_table: HashSet, +} + +impl<'a> MemberAnalyzer<'a> { + fn new(db: &'a mut DbIndex, file_id: FileId, context: &'a mut AnalyzeContext) -> Self { + let is_meta = db + .get_module_index() + .get_module(file_id) + .map_or(false, |module| module.is_meta); + Self { + db, + file_id, + context, + is_meta, + visited_table: HashSet::new(), + } + } +} diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/mod.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/mod.rs index f13da3d01..1f1895c47 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/mod.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/mod.rs @@ -1,16 +1,26 @@ -mod bind_type; +mod common; mod decl; mod doc; mod flow; -mod infer_manager; +mod infer_cache_manager; mod lua; +mod member; mod unresolve; use std::{collections::HashMap, sync::Arc}; -use crate::{Emmyrc, InFiled, InferFailReason, WorkspaceId, db_index::DbIndex, profile::Profile}; +use crate::{ + Emmyrc, InFiled, InferFailReason, LuaDeclId, WorkspaceId, + compilation::analyzer::{ + decl::DeclAnalysisPipeline, doc::DocAnalysisPipeline, flow::FlowAnalysisPipeline, + lua::LuaAnalysisPipeline, member::MemberAnalysisPipeline, + unresolve::ResolveAnalysisPipeline, + }, + db_index::DbIndex, + profile::Profile, +}; use emmylua_parser::LuaChunk; -use infer_manager::InferCacheManager; +use infer_cache_manager::InferCacheManager; use unresolve::UnResolve; pub fn analyze(db: &mut DbIndex, need_analyzed_files: Vec>, config: Arc) { @@ -18,20 +28,29 @@ pub fn analyze(db: &mut DbIndex, need_analyzed_files: Vec>, co return; } - let contexts = module_analyze(db, need_analyzed_files, config); + let contexts = analyze_modules(db, need_analyzed_files, config); for (workspace_id, mut context) in contexts { let profile_log = format!("analyze workspace {}", workspace_id); let _p = Profile::cond_new(&profile_log, context.tree_list.len() > 1); - decl::analyze(db, &mut context); - doc::analyze(db, &mut context); - flow::analyze(db, &mut context); - lua::analyze(db, &mut context); - unresolve::analyze(db, &mut context); + run_analysis::(db, &mut context); + run_analysis::(db, &mut context); + run_analysis::(db, &mut context); + run_analysis::(db, &mut context); + run_analysis::(db, &mut context); + run_analysis::(db, &mut context); } } -fn module_analyze( +trait AnalysisPipeline { + fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext); +} + +fn run_analysis(db: &mut DbIndex, context: &mut AnalyzeContext) { + T::analyze(db, context); +} + +fn analyze_modules( db: &mut DbIndex, need_analyzed_files: Vec>, config: Arc, @@ -112,7 +131,9 @@ pub struct AnalyzeContext { #[allow(unused)] config: Arc, unresolves: Vec<(UnResolve, InferFailReason)>, - infer_manager: InferCacheManager, + #[allow(unused)] + unresolve_member_ids: HashMap, + infer_caches: InferCacheManager, } impl AnalyzeContext { @@ -121,7 +142,8 @@ impl AnalyzeContext { tree_list: Vec::new(), config: emmyrc, unresolves: Vec::new(), - infer_manager: InferCacheManager::new(), + unresolve_member_ids: HashMap::new(), + infer_caches: InferCacheManager::new(), } } diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/check_reason.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/check_reason.rs index 76bea4dfe..9b74485af 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/check_reason.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/check_reason.rs @@ -4,8 +4,8 @@ use emmylua_parser::LuaAstNode; use crate::{ DbIndex, InFiled, InferFailReason, LuaDocReturnInfo, LuaSemanticDeclId, LuaType, LuaTypeCache, - SignatureReturnStatus, compilation::analyzer::infer_manager::InferCacheManager, infer_expr, - infer_param, + SignatureReturnStatus, compilation::analyzer::infer_cache_manager::InferCacheManager, + infer_expr, infer_param, }; use super::UnResolve; diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/mod.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/mod.rs index 7f43d1c6c..393ca33d3 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/mod.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/mod.rs @@ -7,6 +7,7 @@ use std::collections::HashMap; use crate::{ FileId, InferFailReason, LuaMemberFeature, LuaSemanticDeclId, + compilation::analyzer::AnalysisPipeline, db_index::{DbIndex, LuaDeclId, LuaMemberId, LuaSignatureId}, profile::Profile, }; @@ -22,40 +23,44 @@ use resolve_closure::{ try_resolve_call_closure_params, try_resolve_closure_parent_params, try_resolve_closure_return, }; -use super::{AnalyzeContext, infer_manager::InferCacheManager, lua::LuaReturnPoint}; +use super::{AnalyzeContext, infer_cache_manager::InferCacheManager, lua::LuaReturnPoint}; type ResolveResult = Result<(), InferFailReason>; -pub fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext) { - let _p = Profile::cond_new("resolve analyze", context.tree_list.len() > 1); - let mut infer_manager = std::mem::take(&mut context.infer_manager); - infer_manager.clear(); - let mut reason_resolve: HashMap> = HashMap::new(); - for (unresolve, reason) in context.unresolves.drain(..) { - reason_resolve - .entry(reason.clone()) - .or_insert_with(Vec::new) - .push(unresolve); - } - - let mut loop_count = 0; - while !reason_resolve.is_empty() { - try_resolve(db, &mut infer_manager, &mut reason_resolve); +pub struct ResolveAnalysisPipeline; - if reason_resolve.is_empty() { - break; +impl AnalysisPipeline for ResolveAnalysisPipeline { + fn analyze(db: &mut DbIndex, context: &mut AnalyzeContext) { + let _p = Profile::cond_new("resolve analyze", context.tree_list.len() > 1); + let mut infer_manager = std::mem::take(&mut context.infer_caches); + infer_manager.clear(); + let mut reason_resolve: HashMap> = HashMap::new(); + for (unresolve, reason) in context.unresolves.drain(..) { + reason_resolve + .entry(reason.clone()) + .or_insert_with(Vec::new) + .push(unresolve); } - if loop_count == 0 { - infer_manager.set_force(); - } + let mut loop_count = 0; + while !reason_resolve.is_empty() { + try_resolve(db, &mut infer_manager, &mut reason_resolve); - resolve_all_reason(db, &mut reason_resolve, loop_count); + if reason_resolve.is_empty() { + break; + } - if loop_count >= 5 { - break; + if loop_count == 0 { + infer_manager.set_force(); + } + + resolve_all_reason(db, &mut reason_resolve, loop_count); + + if loop_count >= 5 { + break; + } + loop_count += 1; } - loop_count += 1; } } diff --git a/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/resolve.rs b/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/resolve.rs index 134efe9d8..984c6b22e 100644 --- a/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/resolve.rs +++ b/crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/resolve.rs @@ -6,7 +6,7 @@ use crate::{ InFiled, InferFailReason, LuaDeclId, LuaMember, LuaMemberId, LuaMemberKey, LuaSemanticDeclId, LuaTypeCache, SignatureReturnStatus, TypeOps, compilation::analyzer::{ - bind_type::{add_member, bind_type}, + common::{add_member, bind_type}, lua::{analyze_return_point, infer_for_range_iter_expr_func}, }, db_index::{DbIndex, LuaMemberOwner, LuaType}, @@ -125,12 +125,7 @@ pub fn try_resolve_table_field( }; let member_id = LuaMemberId::new(field.get_syntax_id(), file_id); - let member = LuaMember::new( - member_id, - member_key, - unresolve_table_field.decl_feature, - None, - ); + let member = LuaMember::new(member_id, member_key, unresolve_table_field.decl_feature); db.get_member_index_mut().add_member(owner_id, member); db.get_type_index_mut().bind_type( member_id.clone().into(), diff --git a/crates/emmylua_code_analysis/src/db_index/member/lua_member.rs b/crates/emmylua_code_analysis/src/db_index/member/lua_member.rs index 6fcfae406..fdc51171b 100644 --- a/crates/emmylua_code_analysis/src/db_index/member/lua_member.rs +++ b/crates/emmylua_code_analysis/src/db_index/member/lua_member.rs @@ -6,28 +6,21 @@ use serde::{Deserialize, Serialize}; use smol_str::SmolStr; use super::lua_member_feature::LuaMemberFeature; -use crate::{DbIndex, FileId, GlobalId, InferFailReason, LuaInferCache, LuaType, infer_expr}; +use crate::{DbIndex, FileId, InferFailReason, LuaInferCache, LuaType, infer_expr}; #[derive(Debug)] pub struct LuaMember { member_id: LuaMemberId, key: LuaMemberKey, feature: LuaMemberFeature, - global_id: Option, } impl LuaMember { - pub fn new( - member_id: LuaMemberId, - key: LuaMemberKey, - decl_feature: LuaMemberFeature, - global_path: Option, - ) -> Self { + pub fn new(member_id: LuaMemberId, key: LuaMemberKey, decl_feature: LuaMemberFeature) -> Self { Self { member_id, key, feature: decl_feature, - global_id: global_path, } } @@ -64,10 +57,6 @@ impl LuaMember { pub fn get_feature(&self) -> LuaMemberFeature { self.feature } - - pub fn get_global_id(&self) -> Option<&GlobalId> { - self.global_id.as_ref() - } } #[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, Serialize, Deserialize)] diff --git a/crates/emmylua_code_analysis/src/db_index/member/lua_member_owner.rs b/crates/emmylua_code_analysis/src/db_index/member/lua_member_owner.rs index 3888ca1d9..a52cac41a 100644 --- a/crates/emmylua_code_analysis/src/db_index/member/lua_member_owner.rs +++ b/crates/emmylua_code_analysis/src/db_index/member/lua_member_owner.rs @@ -1,15 +1,12 @@ -use internment::ArcIntern; use rowan::TextRange; -use smol_str::SmolStr; use crate::{GlobalId, InFiled, LuaTypeDeclId}; #[derive(Debug, Hash, PartialEq, Eq, Clone)] pub enum LuaMemberOwner { - LocalUnresolve, Type(LuaTypeDeclId), Element(InFiled), - GlobalPath(GlobalId), + GlobalId(GlobalId), } impl From for LuaMemberOwner { @@ -24,24 +21,6 @@ impl From> for LuaMemberOwner { } } -impl From for LuaMemberOwner { - fn from(path: SmolStr) -> Self { - Self::GlobalPath(GlobalId::new(&path)) - } -} - -impl From> for LuaMemberOwner { - fn from(path: ArcIntern) -> Self { - Self::GlobalPath(GlobalId(path.clone())) - } -} - -impl From for LuaMemberOwner { - fn from(global_id: GlobalId) -> Self { - Self::GlobalPath(global_id) - } -} - impl LuaMemberOwner { pub fn get_type_id(&self) -> Option<&LuaTypeDeclId> { match self { @@ -57,14 +36,10 @@ impl LuaMemberOwner { } } - pub fn get_path(&self) -> Option<&GlobalId> { + pub fn get_global_id(&self) -> Option<&GlobalId> { match self { - LuaMemberOwner::GlobalPath(path) => Some(path), + LuaMemberOwner::GlobalId(id) => Some(id), _ => None, } } - - pub fn is_unknown(&self) -> bool { - matches!(self, LuaMemberOwner::LocalUnresolve) - } } diff --git a/crates/emmylua_code_analysis/src/db_index/member/mod.rs b/crates/emmylua_code_analysis/src/db_index/member/mod.rs index c5b5f590b..285fd2302 100644 --- a/crates/emmylua_code_analysis/src/db_index/member/mod.rs +++ b/crates/emmylua_code_analysis/src/db_index/member/mod.rs @@ -7,7 +7,7 @@ mod lua_owner_members; use std::collections::{HashMap, HashSet}; use super::traits::LuaIndex; -use crate::{FileId, db_index::member::lua_owner_members::LuaOwnerMembers}; +use crate::{FileId, GlobalId, db_index::member::lua_owner_members::LuaOwnerMembers}; pub use lua_member::{LuaMember, LuaMemberId, LuaMemberKey}; pub use lua_member_feature::LuaMemberFeature; pub use lua_member_item::LuaMemberIndexItem; @@ -19,6 +19,7 @@ pub struct LuaMemberIndex { in_filed: HashMap>, owner_members: HashMap, member_current_owner: HashMap, + member_global_id: HashMap, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -34,6 +35,7 @@ impl LuaMemberIndex { in_filed: HashMap::new(), owner_members: HashMap::new(), member_current_owner: HashMap::new(), + member_global_id: HashMap::new(), } } @@ -42,11 +44,11 @@ impl LuaMemberIndex { let file_id = member.get_file_id(); self.members.insert(id, member); self.add_in_file_object(file_id, MemberOrOwner::Member(id)); - if !owner.is_unknown() { - self.member_current_owner.insert(id, owner.clone()); - self.add_in_file_object(file_id, MemberOrOwner::Owner(owner.clone())); - self.add_member_to_owner(owner.clone(), id); - } + + self.member_current_owner.insert(id, owner.clone()); + self.add_in_file_object(file_id, MemberOrOwner::Owner(owner.clone())); + self.add_member_to_owner(owner.clone(), id); + id } @@ -120,6 +122,19 @@ impl LuaMemberIndex { Some(()) } + pub fn add_member_global_id( + &mut self, + member_id: LuaMemberId, + global_id: GlobalId, + ) -> Option<()> { + self.member_global_id.insert(member_id, global_id); + Some(()) + } + + pub fn get_member_global_id(&self, member_id: &LuaMemberId) -> Option<&GlobalId> { + self.member_global_id.get(member_id) + } + fn is_item_only_meta(&self, item: &LuaMemberIndexItem) -> bool { match item { LuaMemberIndexItem::One(id) => { @@ -233,6 +248,7 @@ impl LuaIndex for LuaMemberIndex { MemberOrOwner::Member(member_id) => { self.members.remove(&member_id); self.member_current_owner.remove(&member_id); + self.member_global_id.remove(&member_id); } MemberOrOwner::Owner(owner) => { owners.insert(owner); @@ -240,6 +256,7 @@ impl LuaIndex for LuaMemberIndex { } } + let mut need_removed_owner = Vec::new(); for owner in owners { if let Some(member_items) = self.owner_members.get_mut(&owner) { @@ -280,5 +297,7 @@ impl LuaIndex for LuaMemberIndex { self.members.clear(); self.in_filed.clear(); self.owner_members.clear(); + self.member_current_owner.clear(); + self.member_global_id.clear(); } } diff --git a/crates/emmylua_code_analysis/src/db_index/semantic_decl.rs b/crates/emmylua_code_analysis/src/db_index/semantic_decl.rs index 497abe397..29a0ca426 100644 --- a/crates/emmylua_code_analysis/src/db_index/semantic_decl.rs +++ b/crates/emmylua_code_analysis/src/db_index/semantic_decl.rs @@ -8,7 +8,6 @@ pub enum LuaSemanticDeclId { Member(LuaMemberId), LuaDecl(LuaDeclId), Signature(LuaSignatureId), - // Multi(Box>), } impl From for LuaSemanticDeclId { diff --git a/crates/emmylua_code_analysis/src/db_index/type/mod.rs b/crates/emmylua_code_analysis/src/db_index/type/mod.rs index 94dfb9015..0cf8e1a84 100644 --- a/crates/emmylua_code_analysis/src/db_index/type/mod.rs +++ b/crates/emmylua_code_analysis/src/db_index/type/mod.rs @@ -221,15 +221,16 @@ impl LuaTypeIndex { self.full_name_type_map.get_mut(decl_id) } - pub fn bind_type(&mut self, owner: LuaTypeOwner, cache: LuaTypeCache) { + pub fn bind_type(&mut self, owner: LuaTypeOwner, cache: LuaTypeCache) -> bool { if self.types.contains_key(&owner) { - return; + return false; } self.types.insert(owner.clone(), cache); self.in_filed_type_owner .entry(owner.get_file_id()) .or_insert_with(HashSet::new) .insert(owner); + true } pub fn get_type_cache(&self, owner: &LuaTypeOwner) -> Option<&LuaTypeCache> { diff --git a/crates/emmylua_code_analysis/src/db_index/type/types.rs b/crates/emmylua_code_analysis/src/db_index/type/types.rs index aa169499a..c6301d452 100644 --- a/crates/emmylua_code_analysis/src/db_index/type/types.rs +++ b/crates/emmylua_code_analysis/src/db_index/type/types.rs @@ -61,6 +61,7 @@ pub enum LuaType { MultiLineUnion(Arc), TypeGuard(Arc), ConstTplRef(Arc), + GlobalTable(ArcIntern), } impl PartialEq for LuaType { @@ -109,6 +110,7 @@ impl PartialEq for LuaType { (LuaType::TypeGuard(a), LuaType::TypeGuard(b)) => a == b, (LuaType::Never, LuaType::Never) => true, (LuaType::ConstTplRef(a), LuaType::ConstTplRef(b)) => a == b, + (LuaType::GlobalTable(a), LuaType::GlobalTable(b)) => a == b, _ => false, // 不同变体之间不相等 } } @@ -142,50 +144,51 @@ impl Hash for LuaType { LuaType::Def(a) => (20, a).hash(state), LuaType::Array(a) => (22, a).hash(state), LuaType::Call(a) => (23, a).hash(state), - LuaType::Tuple(a) => (25, a).hash(state), - LuaType::DocFunction(a) => (26, a).hash(state), + LuaType::Tuple(a) => (24, a).hash(state), + LuaType::DocFunction(a) => (25, a).hash(state), LuaType::Object(a) => { let ptr = Arc::as_ptr(a); - (27, ptr).hash(state) + (26, ptr).hash(state) } LuaType::Union(a) => { let ptr = Arc::as_ptr(a); - (28, ptr).hash(state) + (27, ptr).hash(state) } LuaType::Intersection(a) => { let ptr = Arc::as_ptr(a); - (29, ptr).hash(state) + (28, ptr).hash(state) } LuaType::Generic(a) => { let ptr = Arc::as_ptr(a); - (30, ptr).hash(state) + (29, ptr).hash(state) } LuaType::TableGeneric(a) => { let ptr = Arc::as_ptr(a); - (31, ptr).hash(state) + (30, ptr).hash(state) } - LuaType::TplRef(a) => (32, a).hash(state), - LuaType::StrTplRef(a) => (33, a).hash(state), + LuaType::TplRef(a) => (31, a).hash(state), + LuaType::StrTplRef(a) => (32, a).hash(state), LuaType::Variadic(a) => { let ptr = Arc::as_ptr(a); - (34, ptr).hash(state) + (33, ptr).hash(state) } - LuaType::DocBooleanConst(a) => (35, a).hash(state), - LuaType::Signature(a) => (36, a).hash(state), - LuaType::Instance(a) => (37, a).hash(state), - LuaType::DocStringConst(a) => (38, a).hash(state), - LuaType::DocIntegerConst(a) => (39, a).hash(state), - LuaType::Namespace(a) => (40, a).hash(state), + LuaType::DocBooleanConst(a) => (34, a).hash(state), + LuaType::Signature(a) => (35, a).hash(state), + LuaType::Instance(a) => (36, a).hash(state), + LuaType::DocStringConst(a) => (37, a).hash(state), + LuaType::DocIntegerConst(a) => (38, a).hash(state), + LuaType::Namespace(a) => (39, a).hash(state), LuaType::MultiLineUnion(a) => { let ptr = Arc::as_ptr(a); - (43, ptr).hash(state) + (40, ptr).hash(state) } LuaType::TypeGuard(a) => { let ptr = Arc::as_ptr(a); - (44, ptr).hash(state) + (41, ptr).hash(state) } - LuaType::Never => 45.hash(state), - LuaType::ConstTplRef(a) => (46, a).hash(state), + LuaType::Never => 42.hash(state), + LuaType::ConstTplRef(a) => (43, a).hash(state), + LuaType::GlobalTable(a) => (44, a).hash(state), } } } diff --git a/crates/emmylua_code_analysis/src/semantic/infer/infer_index.rs b/crates/emmylua_code_analysis/src/semantic/infer/infer_index.rs index 73b680148..a607f74b8 100644 --- a/crates/emmylua_code_analysis/src/semantic/infer/infer_index.rs +++ b/crates/emmylua_code_analysis/src/semantic/infer/infer_index.rs @@ -9,8 +9,8 @@ use rowan::TextRange; use smol_str::SmolStr; use crate::{ - CacheEntry, GenericTpl, InFiled, LuaArrayLen, LuaArrayType, LuaDeclOrMemberId, LuaInferCache, - LuaInstanceType, LuaMemberOwner, LuaOperatorOwner, TypeOps, + CacheEntry, GenericTpl, GlobalId, InFiled, LuaArrayLen, LuaArrayType, LuaDeclOrMemberId, + LuaInferCache, LuaInstanceType, LuaMemberOwner, LuaOperatorOwner, TypeOps, db_index::{ DbIndex, LuaGenericType, LuaIntersectionType, LuaMemberKey, LuaObjectType, LuaOperatorMetaMethod, LuaTupleType, LuaType, LuaTypeDeclId, LuaUnionType, @@ -149,7 +149,10 @@ pub fn infer_member_by_member_key( ) -> InferResult { match &prefix_type { LuaType::Table | LuaType::Any | LuaType::Unknown => Ok(LuaType::Any), - LuaType::TableConst(id) => infer_table_member(db, cache, id.clone(), index_expr), + LuaType::TableConst(id) => { + let owner = LuaMemberOwner::Element(id.clone()); + infer_member_owner_member(db, cache, owner, index_expr) + } LuaType::String | LuaType::Io | LuaType::StringConst(_) | LuaType::DocStringConst(_) => { let decl_id = get_buildin_type_map_type_id(&prefix_type).ok_or(InferFailReason::None)?; @@ -174,6 +177,10 @@ pub fn infer_member_by_member_key( LuaType::Namespace(ns) => infer_namespace_member(db, cache, ns, index_expr), LuaType::Array(array_type) => infer_array_member(db, cache, array_type, index_expr), LuaType::TplRef(tpl) => infer_tpl_ref_member(db, cache, tpl, index_expr, infer_guard), + LuaType::GlobalTable(global_table_name) => { + let owner = LuaMemberOwner::GlobalId(GlobalId(global_table_name.clone())); + infer_member_owner_member(db, cache, owner, index_expr) + } _ => Err(InferFailReason::FieldNotFound), } } @@ -328,13 +335,12 @@ fn check_iter_var_range( Some(len_expr_var_ref_id == prefix_expr_var_ref_id) } -fn infer_table_member( +fn infer_member_owner_member( db: &DbIndex, cache: &mut LuaInferCache, - inst: InFiled, + owner: LuaMemberOwner, index_expr: LuaIndexMemberExpr, ) -> InferResult { - let owner = LuaMemberOwner::Element(inst); let index_key = index_expr.get_index_key().ok_or(InferFailReason::None)?; let key = LuaMemberKey::from_index_key(db, cache, &index_key)?; let member_item = match db.get_member_index().get_member_item(&owner, &key) { @@ -776,7 +782,8 @@ fn infer_instance_member( Err(err) => return Err(err), } - infer_table_member(db, cache, range.clone(), index_expr.clone()) + let owner = LuaMemberOwner::Element(range.clone()); + infer_member_owner_member(db, cache, owner, index_expr.clone()) } pub fn infer_member_by_operator( diff --git a/crates/emmylua_code_analysis/src/semantic/member/find_members.rs b/crates/emmylua_code_analysis/src/semantic/member/find_members.rs index 076003258..a70d5fb31 100644 --- a/crates/emmylua_code_analysis/src/semantic/member/find_members.rs +++ b/crates/emmylua_code_analysis/src/semantic/member/find_members.rs @@ -3,7 +3,7 @@ use std::collections::HashSet; use smol_str::SmolStr; use crate::{ - DbIndex, FileId, LuaGenericType, LuaInstanceType, LuaIntersectionType, LuaMemberKey, + DbIndex, FileId, GlobalId, LuaGenericType, LuaInstanceType, LuaIntersectionType, LuaMemberKey, LuaMemberOwner, LuaObjectType, LuaSemanticDeclId, LuaTupleType, LuaType, LuaTypeDeclId, LuaUnionType, semantic::{ @@ -64,6 +64,10 @@ fn find_members_guard( let member_owner = LuaMemberOwner::Element(id.clone()); find_normal_members(db, member_owner, filter) } + LuaType::GlobalTable(global_id) => { + let member_owner = LuaMemberOwner::GlobalId(GlobalId(global_id.clone())); + find_normal_members(db, member_owner, filter) + } LuaType::TableGeneric(table_type) => find_table_generic_members(table_type, filter), LuaType::String | LuaType::Io | LuaType::StringConst(_) => { let type_decl_id = get_buildin_type_map_type_id(&prefix_type)?;