diff --git a/server/src/core/evaluation.rs b/server/src/core/evaluation.rs index bf9c1e6..25887fe 100644 --- a/server/src/core/evaluation.rs +++ b/server/src/core/evaluation.rs @@ -136,7 +136,7 @@ pub type Context = HashMap; * diagnostics: a vec the hook can fill to add diagnostics * file_symbol: if provided, can be used to add dependencies */ -type GetSymbolHook = fn (session: &mut SessionInfo, eval: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, file_symbol: Option>>) -> EvaluationSymbolWeak; +type GetSymbolHook = fn (session: &mut SessionInfo, eval: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, scope: Option>>) -> EvaluationSymbolWeak; #[derive(Debug, Clone)] @@ -316,7 +316,7 @@ impl Evaluation { match self.symbol.sym { EvaluationSymbolPtr::WEAK(_) => { //take the weak by get_symbol instead of the match - let symbol_eval_weak = self.symbol.get_symbol(session, &mut None, &mut vec![], None); + let symbol_eval_weak = self.symbol.get_symbol(session, &mut None, &mut vec![], Some(function.clone())); let out_of_scope = Symbol::follow_ref(&symbol_eval_weak, session, &mut None, true, false, Some(function.clone()), &mut vec![]); for weak_sym in out_of_scope { if !weak_sym.weak.is_expired() { @@ -614,7 +614,7 @@ impl Evaluation { } let mut context = Some(base_eval[0].symbol.context.clone()); //TODO context should give params - let base_sym_weak_eval= base_eval[0].symbol.get_symbol(session, &mut context, &mut diagnostics, None); + let base_sym_weak_eval= base_eval[0].symbol.get_symbol(session, &mut context, &mut diagnostics, None); //TODO is parent right? if there is multiple chained evaluation, we should not give it? let base_sym = base_sym_weak_eval.weak.upgrade(); if let Some(base_sym) = base_sym { if base_sym.borrow().typ() == SymType::CLASS { @@ -629,7 +629,7 @@ impl Evaluation { if class_eval.len() != 1 { return AnalyzeAstResult::from_only_diagnostics(diagnostics); } - let class_sym_weak_eval= class_eval[0].symbol.get_symbol(session, &mut context, &mut diagnostics, None); + let class_sym_weak_eval= class_eval[0].symbol.get_symbol(session, &mut context, &mut diagnostics, Some(parent.clone())); //TODO is parent right? if there is multiple chained evaluation, we should not give it? class_sym_weak_eval.weak.upgrade().and_then(|class_sym|{ let class_sym_weak_eval = &Symbol::follow_ref(&EvaluationSymbolWeak::new( Rc::downgrade(&class_sym), None, false @@ -660,7 +660,7 @@ impl Evaluation { } let object_or_type_weak_eval = &Symbol::follow_ref( &object_or_type_eval[0].symbol.get_symbol( - session, &mut context, &mut diagnostics, None), + session, &mut context, &mut diagnostics, Some(parent)), session, &mut None, false, false, None, &mut diagnostics)[0]; is_instance = object_or_type_weak_eval.instance; } @@ -758,7 +758,6 @@ impl Evaluation { &base_sym.borrow().as_func(), expr, context.as_ref().unwrap().get_key_value(&S!("parent")).unwrap_or((&S!(""), &ContextValue::SYMBOL(Weak::new()))).1.as_symbol(), - from_module, on_instance)); } @@ -779,7 +778,7 @@ impl Evaluation { if base_evals.len() == 0 || (base_evals.len() > 0 && base_evals[0].symbol.get_symbol(session, &mut None, &mut diagnostics, None).weak.is_expired()) { return AnalyzeAstResult::from_only_diagnostics(diagnostics); } - let base_ref = base_evals[0].symbol.get_symbol(session, &mut None, &mut diagnostics, Some(parent.borrow().get_file().unwrap().upgrade().unwrap().clone())); + let base_ref = base_evals[0].symbol.get_symbol(session, &mut None, &mut diagnostics, Some(parent.clone())); let bases = Symbol::follow_ref(&base_ref, session, &mut None, false, false, None, &mut diagnostics); for ibase in bases.iter() { let base_loc = ibase.weak.upgrade(); @@ -834,7 +833,7 @@ impl Evaluation { if eval_left.len() == 0 || (eval_left.len() > 0 && eval_left[0].symbol.get_symbol(session, &mut None, &mut diagnostics, None).weak.is_expired()) { //TODO set context? return AnalyzeAstResult::from_only_diagnostics(diagnostics); } - let base = &eval_left[0].symbol.get_symbol(session, &mut None, &mut diagnostics, None); //TODO set context? + let base = &eval_left[0].symbol.get_symbol(session, &mut None, &mut diagnostics, Some(parent.clone())); //TODO set context? let bases = Symbol::follow_ref(&base, session, &mut None, false, false, None, &mut diagnostics); if bases.len() != 1 { return AnalyzeAstResult::from_only_diagnostics(diagnostics); @@ -854,7 +853,7 @@ impl Evaluation { context.as_mut().unwrap().insert(S!("args"), ContextValue::STRING(value)); let old_range = context.as_mut().unwrap().remove(&S!("range")); context.as_mut().unwrap().insert(S!("range"), ContextValue::RANGE(sub.slice.range())); - let hook_result = hook(session, &get_item_eval.symbol, context, &mut diagnostics, Some(parent.borrow().get_file().unwrap().upgrade().unwrap().clone())); + let hook_result = hook(session, &get_item_eval.symbol, context, &mut diagnostics, Some(parent.clone())); if !hook_result.weak.is_expired() { evals.push(Evaluation::eval_from_symbol(&hook_result.weak, hook_result.instance)); } @@ -1209,7 +1208,7 @@ impl EvaluationSymbol { } } - pub fn get_symbol(&self, session: &mut SessionInfo, context: &mut Option, diagnostics: &mut Vec, file_symbol: Option>>) -> EvaluationSymbolWeak { + pub fn get_symbol(&self, session: &mut SessionInfo, context: &mut Option, diagnostics: &mut Vec, scope: Option>>) -> EvaluationSymbolWeak { let mut full_context = self.context.clone(); //extend with local elements if let Some(context) = context { @@ -1217,7 +1216,7 @@ impl EvaluationSymbol { } if self.get_symbol_hook.is_some() { let hook = self.get_symbol_hook.unwrap(); - return hook(session, self, &mut Some(full_context), diagnostics, file_symbol); + return hook(session, self, &mut Some(full_context), diagnostics, scope); } match &self.sym { EvaluationSymbolPtr::WEAK(w) => { diff --git a/server/src/core/model.rs b/server/src/core/model.rs index 282ac5e..d7d4b79 100644 --- a/server/src/core/model.rs +++ b/server/src/core/model.rs @@ -5,6 +5,9 @@ use lsp_types::MessageType; use weak_table::PtrWeakHashSet; use std::collections::HashSet; +use crate::constants::BuildStatus; +use crate::constants::BuildSteps; +use crate::constants::SymType; use crate::threads::SessionInfo; use super::symbols::module_symbol::ModuleSymbol; @@ -79,13 +82,14 @@ impl Model { } pub fn add_symbol(&mut self, session: &mut SessionInfo, symbol: Rc>) { - self.symbols.insert(symbol); - self.add_dependents_to_validation(session); + self.symbols.insert(symbol.clone()); + let from_module = symbol.borrow().find_module(); + self.add_dependents_to_validation(session, from_module); } - pub fn remove_symbol(&mut self, session: &mut SessionInfo, symbol: &Rc>) { + pub fn remove_symbol(&mut self, session: &mut SessionInfo, symbol: &Rc>, from_module: Option>>) { self.symbols.remove(symbol); - self.add_dependents_to_validation(session); + self.add_dependents_to_validation(session, from_module); } pub fn get_symbols(&self, session: &mut SessionInfo, from_module: Rc>) -> impl Iterator>> { @@ -149,10 +153,23 @@ impl Model { self.dependents.insert(symbol.clone()); } - pub fn add_dependents_to_validation(&self, session: &mut SessionInfo) { + pub fn add_dependents_to_validation(&self, session: &mut SessionInfo, module_change: Option>>) { for dep in self.dependents.iter() { dep.borrow_mut().invalidate_sub_functions(session); - session.sync_odoo.add_to_validations(dep.clone()); + let module = dep.borrow().find_module(); + if module_change.is_none() || module.is_none() || ModuleSymbol::is_in_deps(session, &module.as_ref().unwrap(), &module_change.as_ref().unwrap().borrow().as_module_package().dir_name, &mut None) { + let typ = dep.borrow().typ().clone(); + match typ { + SymType::FUNCTION => { + dep.borrow_mut().set_build_status(BuildSteps::ARCH_EVAL, BuildStatus::PENDING); + dep.borrow_mut().set_build_status(BuildSteps::ODOO, BuildStatus::PENDING); + session.sync_odoo.add_to_validations(dep.clone()); + }, + _ => { + session.sync_odoo.add_to_validations(dep.clone()); + } + } + } } } } diff --git a/server/src/core/python_arch_eval.rs b/server/src/core/python_arch_eval.rs index f529d1a..9e5027a 100644 --- a/server/src/core/python_arch_eval.rs +++ b/server/src/core/python_arch_eval.rs @@ -690,7 +690,7 @@ impl PythonArchEval { let (eval, diags) = Evaluation::eval_from_ast(session, &item.context_expr, parent, &with_stmt.range.start()); let mut evals = vec![]; for eval in eval.iter() { - let symbol = eval.symbol.get_symbol(session, &mut None, &mut self.diagnostics, Some(self.file.clone())); + let symbol = eval.symbol.get_symbol(session, &mut None, &mut self.diagnostics, Some(variable_rc.borrow().parent_file_or_function().unwrap().upgrade().unwrap().clone())); if let Some(symbol) = symbol.weak.upgrade() { let _enter_ = symbol.borrow().get_symbol(&(vec![], vec![S!("__enter__")]), u32::MAX); if let Some(_enter_) = _enter_.last() { diff --git a/server/src/core/python_arch_eval_hooks.rs b/server/src/core/python_arch_eval_hooks.rs index b03fce5..24e7792 100644 --- a/server/src/core/python_arch_eval_hooks.rs +++ b/server/src/core/python_arch_eval_hooks.rs @@ -411,7 +411,7 @@ impl PythonArchEvalHooks { } } - pub fn eval_env_get_item(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, file_symbol: Option>>) -> EvaluationSymbolWeak + pub fn eval_env_get_item(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, scope: Option>>) -> EvaluationSymbolWeak { if let Some(context) = context { let arg = context.get(&S!("args")); @@ -431,8 +431,8 @@ impl PythonArchEvalHooks { } else { from_module = None; } - if let Some(file_symbol) = file_symbol { - let mut f = file_symbol.borrow_mut(); + if let Some(scope) = scope { + let mut f = scope.borrow_mut(); f.add_model_dependencies(model); } let model = model.clone(); @@ -508,14 +508,14 @@ impl PythonArchEvalHooks { EvaluationSymbolWeak::new(Weak::new(), Some(true), false) } - pub fn eval_registry_get_item(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, file_symbol: Option>>) -> EvaluationSymbolWeak + pub fn eval_registry_get_item(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, scope: Option>>) -> EvaluationSymbolWeak { - let mut result = PythonArchEvalHooks::eval_env_get_item(session, evaluation_sym, context, diagnostics, file_symbol); + let mut result = PythonArchEvalHooks::eval_env_get_item(session, evaluation_sym, context, diagnostics, scope); result.instance = Some(false); result } - fn eval_test_cursor(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, file_symbol: Option>>) -> EvaluationSymbolWeak + fn eval_test_cursor(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, scope: Option>>) -> EvaluationSymbolWeak { if context.is_some() && context.as_ref().unwrap().get(&S!("test_mode")).unwrap_or(&ContextValue::BOOLEAN(false)).as_bool() { let test_cursor_sym = session.sync_odoo.get_symbol(&(vec![S!("odoo"), S!("sql_db")], vec![S!("TestCursor")]), u32::MAX); @@ -528,7 +528,7 @@ impl PythonArchEvalHooks { evaluation_sym.get_weak().clone() } - fn eval_get(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, file_symbol: Option>>) -> EvaluationSymbolWeak + fn eval_get(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, scope: Option>>) -> EvaluationSymbolWeak { if context.is_some() { let parent_instance = context.as_ref().unwrap().get(&S!("parent_instance")); @@ -571,7 +571,7 @@ impl PythonArchEvalHooks { }]); } - fn eval_relational(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, file_symbol: Option>>) -> EvaluationSymbolWeak + fn eval_relational(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option, diagnostics: &mut Vec, scope: Option>>) -> EvaluationSymbolWeak { if context.is_none() { return evaluation_sym.get_symbol(session, &mut None, diagnostics, None); diff --git a/server/src/core/symbols/function_symbol.rs b/server/src/core/symbols/function_symbol.rs index 9f4abf5..2c9a3c1 100644 --- a/server/src/core/symbols/function_symbol.rs +++ b/server/src/core/symbols/function_symbol.rs @@ -2,8 +2,9 @@ use std::{cell::RefCell, collections::HashMap, rc::{Rc, Weak}}; use lsp_types::Diagnostic; use ruff_text_size::{TextRange, TextSize}; +use weak_table::PtrWeakHashSet; -use crate::{constants::{BuildStatus, BuildSteps, SymType}, core::evaluation::{Context, Evaluation}, threads::SessionInfo}; +use crate::{constants::{BuildStatus, BuildSteps, SymType}, core::{evaluation::{Context, Evaluation}, model::Model}, threads::SessionInfo}; use super::{symbol::Symbol, symbol_mgr::{SectionRange, SymbolMgr}}; @@ -34,6 +35,7 @@ pub struct FunctionSymbol { pub ast_indexes: Vec, //list of index to reach the corresponding ast node from file ast pub diagnostics: HashMap>, //only temporary used for CLASS and FUNCTION to be collected like others are stored on FileInfo pub evaluations: Vec, //Vec, because sometimes a single allocation can be ambiguous, like ''' a = "5" if X else 5 ''' + pub model_dependencies: PtrWeakHashSet>>, pub weak_self: Option>>, pub parent: Option>>, pub arch_status: BuildStatus, @@ -75,6 +77,7 @@ impl FunctionSymbol { arch_eval_status: BuildStatus::PENDING, odoo_status: BuildStatus::PENDING, validation_status: BuildStatus::PENDING, + model_dependencies: PtrWeakHashSet::new(), sections: vec![], symbols: HashMap::new(), ext_symbols: HashMap::new(), diff --git a/server/src/core/symbols/symbol.rs b/server/src/core/symbols/symbol.rs index 1165730..f488c47 100644 --- a/server/src/core/symbols/symbol.rs +++ b/server/src/core/symbols/symbol.rs @@ -1176,6 +1176,10 @@ impl Symbol { f.model_dependencies.insert(model.clone()); model.borrow_mut().add_dependent(&self.weak_self().unwrap().upgrade().unwrap()); }, + Symbol::Function(f) => { + f.model_dependencies.insert(model.clone()); + model.borrow_mut().add_dependent(&self.weak_self().unwrap().upgrade().unwrap()); + } _ => {} } } @@ -1238,7 +1242,8 @@ impl Symbol { if let Some(model_data) = &class.borrow().as_class_sym()._model { let model = session.sync_odoo.models.get(&model_data.name).cloned(); if let Some(model) = model { - model.borrow().add_dependents_to_validation(session); + let from_module = class.borrow().find_module(); + model.borrow().add_dependents_to_validation(session, from_module); } } } @@ -1281,6 +1286,7 @@ impl Symbol { if DEBUG_MEMORY && (mut_symbol.typ() == SymType::FILE || matches!(mut_symbol.typ(), SymType::PACKAGE(_))) { info!("Unloading symbol {:?} at {:?}", mut_symbol.name(), mut_symbol.paths()); } + let module = mut_symbol.find_module(); //unload symbol let parent = mut_symbol.parent().as_ref().unwrap().upgrade().unwrap().clone(); let mut parent_bw = parent.borrow_mut(); @@ -1310,7 +1316,7 @@ impl Symbol { if let Some(model_data) = c._model.as_ref() { let model = session.sync_odoo.models.get(&model_data.name).cloned(); if let Some(model) = model { - model.borrow_mut().remove_symbol(session, &ref_to_unload); + model.borrow_mut().remove_symbol(session, &ref_to_unload, module); } } }, diff --git a/server/src/features/completion.rs b/server/src/features/completion.rs index c13ff0d..8c2f85d 100644 --- a/server/src/features/completion.rs +++ b/server/src/features/completion.rs @@ -541,10 +541,10 @@ fn complete_attribut(session: &mut SessionInfo, file: &Rc>, attr if offset > attr.value.range().start().to_usize() && offset <= attr.value.range().end().to_usize() { return complete_expr( &attr.value, session, file, offset, is_param, expected_type); } else { - let parent = Evaluation::eval_from_ast(session, &attr.value, scope, &attr.range().start()).0; + let parent = Evaluation::eval_from_ast(session, &attr.value, scope.clone(), &attr.range().start()).0; for parent_eval in parent.iter() { - let parent_sym_eval_weak = parent_eval.symbol.get_symbol(session, &mut None, &mut vec![], Some(file.clone())); + let parent_sym_eval_weak = parent_eval.symbol.get_symbol(session, &mut None, &mut vec![], Some(scope.clone())); if !parent_sym_eval_weak.weak.is_expired() { let parent_sym_types = Symbol::follow_ref(&parent_sym_eval_weak, session, &mut None, true, false, None, &mut vec![]); for parent_sym_type in parent_sym_types.iter() { @@ -573,9 +573,9 @@ fn complete_attribut(session: &mut SessionInfo, file: &Rc>, attr fn complete_subscript(session: &mut SessionInfo, file: &Rc>, expr_subscript: &ExprSubscript, offset: usize, is_param: bool, expected_type: &Vec) -> Option { let scope = Symbol::get_scope_symbol(file.clone(), offset as u32, is_param); - let subscripted = Evaluation::eval_from_ast(session, &expr_subscript.value, scope, &expr_subscript.value.range().start()).0; + let subscripted = Evaluation::eval_from_ast(session, &expr_subscript.value, scope.clone(), &expr_subscript.value.range().start()).0; for eval in subscripted.iter() { - let eval_symbol = eval.symbol.get_symbol(session, &mut None, &mut vec![], Some(file.clone())); + let eval_symbol = eval.symbol.get_symbol(session, &mut None, &mut vec![], Some(scope.clone())); if !eval_symbol.weak.is_expired() { let symbol_types = Symbol::follow_ref(&eval_symbol, session, &mut None, true, false, None, &mut vec![]); for symbol_type in symbol_types.iter() {