Skip to content

Commit 98172b0

Browse files
committed
[IMP] server: add not found models
1 parent b9071f0 commit 98172b0

File tree

9 files changed

+306
-213
lines changed

9 files changed

+306
-213
lines changed

server/src/core/entry_point.rs

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ pub struct EntryPoint {
320320
pub addon_to_odoo_tree: Option<Vec<OYarn>>, //contains the odoo tree if this is an addon entry point
321321
pub root: Rc<RefCell<Symbol>>,
322322
pub not_found_symbols: PtrWeakHashSet<Weak<RefCell<Symbol>>>,
323+
pub not_found_symbols_for_models: PtrWeakHashSet<Weak<RefCell<Symbol>>>,
323324
pub to_delete: bool,
324325
pub data_symbols: HashMap<String, Weak<RefCell<Symbol>>>, //key is path, weak to Rc that is hold by the module symbol
325326
}
@@ -333,6 +334,7 @@ impl EntryPoint {
333334
addon_to_odoo_path,
334335
addon_to_odoo_tree,
335336
not_found_symbols: PtrWeakHashSet::new(),
337+
not_found_symbols_for_models: PtrWeakHashSet::new(),
336338
root: root.clone(),
337339
to_delete: false,
338340
data_symbols: HashMap::new(),
@@ -376,33 +378,27 @@ impl EntryPoint {
376378

377379
/* Consider the given 'tree' path as updated (or new) and move all symbols that were searching for it
378380
from the not_found_symbols list to the rebuild list. Return True is something should be rebuilt */
379-
pub fn search_symbols_to_rebuild(&mut self, session: &mut SessionInfo, path: &String, tree: &Tree) -> bool {
381+
pub fn search_symbols_to_rebuild(&mut self, session: &mut SessionInfo, path: &String, tree: &Tree) {
380382
let flat_tree = [tree.0.clone(), tree.1.clone()].concat();
381-
let mut found_sym: PtrWeakHashSet<Weak<RefCell<Symbol>>> = PtrWeakHashSet::new();
382-
let mut need_rebuild = false;
383383
let mut to_add = [vec![], vec![], vec![], vec![]]; //list of symbols to add after the loop (borrow issue)
384-
'loop_symbols: for s in self.not_found_symbols.iter() {
384+
for s in self.not_found_symbols.iter() {
385385
if s.borrow().typ() == SymType::PACKAGE(PackageType::MODULE) {
386386
let mut sym = s.borrow_mut();
387387
if let Some(step) = sym.as_module_package().not_found_data.get(path) {
388-
need_rebuild = true;
389388
match step {
390389
BuildSteps::ARCH | BuildSteps::ARCH_EVAL | BuildSteps::VALIDATION => {
391390
to_add[*step as usize].push(s.clone());
392391
}
393392
_ => {}
394393
}
395394
sym.as_module_package_mut().not_found_data.remove(path);
395+
continue; //as if a data has been found, we won't find anything later, so we can continue the loop
396396
}
397397
}
398-
if need_rebuild {
399-
continue 'loop_symbols; //as if a data has been found, we won't find anything later, so we can continue the loop
400-
}
401398
let mut index: i32 = 0; //i32 sa we could go in negative values
402399
while (index as usize) < s.borrow().not_found_paths().len() {
403400
let (step, not_found_tree) = s.borrow().not_found_paths()[index as usize].clone();
404401
if flat_tree[..cmp::min(not_found_tree.len(), flat_tree.len())] == not_found_tree[..cmp::min(not_found_tree.len(), flat_tree.len())] {
405-
need_rebuild = true;
406402
match step {
407403
BuildSteps::ARCH | BuildSteps::ARCH_EVAL | BuildSteps::VALIDATION => {
408404
to_add[step as usize].push(s.clone());
@@ -414,9 +410,6 @@ impl EntryPoint {
414410
}
415411
index += 1;
416412
}
417-
if s.borrow().not_found_paths().len() == 0 {
418-
found_sym.insert(s.clone());
419-
}
420413
}
421414
for s in to_add[BuildSteps::ARCH as usize].iter() {
422415
session.sync_odoo.add_to_rebuild_arch(s.clone());
@@ -428,11 +421,43 @@ impl EntryPoint {
428421
s.borrow_mut().invalidate_sub_functions(session);
429422
session.sync_odoo.add_to_validations(s.clone());
430423
}
431-
for sym in found_sym.iter() {
432-
if sym.borrow().not_found_paths().is_empty() && (sym.borrow().typ() != SymType::PACKAGE(PackageType::MODULE) || sym.borrow().as_module_package().not_found_data.is_empty()) {
433-
self.not_found_symbols.remove(&sym);
424+
self.not_found_symbols.retain(|sym| {
425+
!sym.borrow().not_found_paths().is_empty() || (sym.borrow().typ() == SymType::PACKAGE(PackageType::MODULE) && !sym.borrow().as_module_package().not_found_data.is_empty())
426+
});
427+
}
428+
429+
pub fn search_rebuild_for_models(&mut self, session: &mut SessionInfo, model_name: OYarn){
430+
let mut to_add: [Vec<Rc<RefCell<Symbol>>>; 4] = [vec![], vec![], vec![], vec![]]; //list of symbols to add after the loop (borrow issue)
431+
for sym_rc in self.not_found_symbols_for_models.iter() {
432+
let mut sym_ref = sym_rc.borrow_mut();
433+
let Some(not_found_models) = sym_ref.not_found_models_mut() else {
434+
continue;
435+
};
436+
let Some(step) = not_found_models.get(&model_name) else {
437+
continue;
438+
};
439+
match step {
440+
BuildSteps::ARCH | BuildSteps::ARCH_EVAL | BuildSteps::VALIDATION => {
441+
to_add[*step as usize].push(sym_rc.clone());
442+
}
443+
_ => {} // unreachable
434444
}
445+
not_found_models.remove(&model_name);
446+
435447
}
436-
need_rebuild
448+
for s in to_add[BuildSteps::ARCH as usize].iter() {
449+
session.sync_odoo.add_to_rebuild_arch(s.clone());
450+
}
451+
for s in to_add[BuildSteps::ARCH_EVAL as usize].iter() {
452+
session.sync_odoo.add_to_rebuild_arch_eval(s.clone());
453+
}
454+
for s in to_add[BuildSteps::VALIDATION as usize].iter() {
455+
s.borrow_mut().invalidate_sub_functions(session);
456+
session.sync_odoo.add_to_validations(s.clone());
457+
}
458+
self.not_found_symbols_for_models.retain(|sym| {
459+
!sym.borrow().not_found_models().map(|models| models.is_empty()).unwrap_or(true)
460+
});
461+
437462
}
438463
}

server/src/core/model.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ impl Model {
8989
}
9090

9191
pub fn add_symbol(&mut self, session: &mut SessionInfo, symbol: Rc<RefCell<Symbol>>) {
92+
if self.symbols.contains(&symbol) {
93+
return;
94+
}
9295
self.symbols.insert(symbol.clone());
9396
let from_module = symbol.borrow().find_module();
9497
self.add_dependents_to_validation(session, from_module);
@@ -184,6 +187,11 @@ impl Model {
184187
res
185188
}
186189

190+
pub fn has_symbols(&mut self) -> bool {
191+
self.symbols.remove_expired();
192+
!self.symbols.is_empty()
193+
}
194+
187195
/* Return all symbols that build this model.
188196
It returns the symbol and an optional string that represents the module name that should be added to dependencies to be used.
189197
if with_inheritance is true, it will also return symbols from inherited models (NOT Base classes).

server/src/core/python_arch_eval_hooks.rs

Lines changed: 72 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
use std::cmp::Ordering;
22
use std::collections::HashMap;
3-
use std::ops::Index;
4-
use std::path::PathBuf;
53
use std::rc::Rc;
64
use std::rc::Weak;
75
use std::cell::RefCell;
86
use lsp_types::Diagnostic;
9-
use lsp_types::DiagnosticSeverity;
10-
use lsp_types::NumberOrString;
117
use once_cell::sync::Lazy;
128
use ruff_python_ast::Arguments;
139
use ruff_python_ast::Expr;
@@ -23,16 +19,13 @@ use crate::constants::*;
2319
use crate::oyarn;
2420
use crate::threads::SessionInfo;
2521
use crate::utils::compare_semver;
26-
use crate::utils::is_file_cs;
27-
use crate::utils::PathSanitizer;
2822
use crate::Sy;
2923
use crate::S;
3024

3125
use super::entry_point::EntryPoint;
3226
use super::evaluation::{ContextValue, Evaluation, EvaluationSymbolPtr, EvaluationSymbol, EvaluationSymbolWeak};
3327
use super::file_mgr::FileMgr;
3428
use super::python_arch_eval::PythonArchEval;
35-
use super::symbols::module_symbol::ModuleSymbol;
3629

3730
type PythonArchEvalHookFile = fn (odoo: &mut SessionInfo, entry: &Rc<RefCell<EntryPoint>>, file_symbol: Rc<RefCell<Symbol>>, symbol: Rc<RefCell<Symbol>>);
3831

@@ -704,100 +697,86 @@ impl PythonArchEvalHooks {
704697
diagnostics
705698
}
706699

707-
pub fn eval_env_get_item(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option<Context>, diagnostics: &mut Vec<Diagnostic>, scope: Option<Rc<RefCell<Symbol>>>) -> Option<EvaluationSymbolPtr>
700+
pub fn eval_env_get_item(session: &mut SessionInfo, _evaluation_sym: &EvaluationSymbol, context: &mut Option<Context>, diagnostics: &mut Vec<Diagnostic>, scope: Option<Rc<RefCell<Symbol>>>) -> Option<EvaluationSymbolPtr>
708701
{
709-
if let Some(context) = context {
710-
let in_validation = context.get(&S!("is_in_validation")).unwrap_or(&ContextValue::BOOLEAN(false)).as_bool();
711-
let arg = context.get(&S!("args"));
712-
if let Some(arg) = arg {
713-
match arg {
714-
ContextValue::STRING(s) => {
715-
let model = session.sync_odoo.models.get(&oyarn!("{}", s));
716-
let mut has_class_in_parents = false;
717-
if let Some(scope) = scope.as_ref() {
718-
has_class_in_parents = scope.borrow().get_in_parents(&vec![SymType::CLASS], true).is_some();
702+
let res = Some(EvaluationSymbolPtr::WEAK(EvaluationSymbolWeak::new(Weak::new(), Some(true), false)));
703+
let Some(context) = context else {
704+
return res
705+
};
706+
let in_validation = context.get(&S!("is_in_validation")).unwrap_or(&ContextValue::BOOLEAN(false)).as_bool();
707+
let Some(ContextValue::STRING(s)) = context.get(&S!("args")) else {
708+
return res
709+
};
710+
let maybe_model = session.sync_odoo.models.get(&oyarn!("{}", s));
711+
let has_class_in_parents = scope.as_ref().map(|scope| scope.borrow().get_in_parents(&vec![SymType::CLASS], true).is_some()).unwrap_or(false);
712+
if maybe_model.map(|m| m.borrow_mut().has_symbols()).unwrap_or(false) {
713+
let Some(model) = maybe_model else {unreachable!()};
714+
let module = context.get(&S!("module"));
715+
let from_module = if let Some(ContextValue::MODULE(m)) = module {
716+
m.upgrade().clone()
717+
} else {
718+
None
719+
};
720+
if let Some(scope) = scope {
721+
let mut f = scope.borrow_mut();
722+
f.add_model_dependencies(model);
723+
}
724+
let model = model.clone();
725+
let model = model.borrow();
726+
let symbols = model.get_main_symbols(session, from_module.clone());
727+
if let Some(first_symbol) = symbols.first() {
728+
return Some(EvaluationSymbolPtr::WEAK(EvaluationSymbolWeak::new(Rc::downgrade(first_symbol), Some(true), false)));
729+
}
730+
if in_validation && has_class_in_parents { //we don't want to show error for functions outside of a model body
731+
if from_module.is_some(){
732+
//retry without from_module to see if model exists elsewhere
733+
let symbols = model.get_main_symbols(session, None);
734+
if symbols.is_empty() {
735+
// Model exists, but has no main symbols
736+
if let Some(diagnostic_base) = create_diagnostic(&session, DiagnosticCode::OLS03005, &[]) { // Is this error code correct?
737+
diagnostics.push(Diagnostic {
738+
range: FileMgr::textRange_to_temporary_Range(&context.get(&S!("range")).unwrap().as_text_range()),
739+
..diagnostic_base.clone()
740+
});
719741
}
720-
if let Some(model) = model {
721-
let module = context.get(&S!("module"));
722-
let from_module;
723-
if let Some(ContextValue::MODULE(m)) = module {
724-
if let Some(m) = m.upgrade() {
725-
from_module = Some(m.clone());
726-
} else {
727-
from_module = None;
728-
}
729-
} else {
730-
from_module = None;
731-
}
732-
if let Some(scope) = scope {
733-
let mut f = scope.borrow_mut();
734-
f.add_model_dependencies(model);
735-
}
736-
let model = model.clone();
737-
let model = model.borrow();
738-
let symbols = model.get_main_symbols(session, from_module.clone());
739-
if !symbols.is_empty() {
740-
for s in symbols.iter() {
741-
if from_module.is_none() || ModuleSymbol::is_in_deps(session, &from_module.as_ref().unwrap(),&s.borrow().find_module().unwrap().borrow().as_module_package().dir_name) {
742-
return Some(EvaluationSymbolPtr::WEAK(EvaluationSymbolWeak::new(Rc::downgrade(s), Some(true), false)));
743-
}
744-
}
745-
} else {
746-
if from_module.is_some() && has_class_in_parents { //we don't want to show error for functions outside of a model body
747-
//retry without from_module to see if model exists elsewhere
748-
let symbols = model.get_main_symbols(session, None);
749-
if symbols.is_empty() {
750-
if in_validation {
751-
if let Some(diagnostic_base) = create_diagnostic(&session, DiagnosticCode::OLS03005, &[]) {
752-
diagnostics.push(Diagnostic {
753-
range: FileMgr::textRange_to_temporary_Range(&context.get(&S!("range")).unwrap().as_text_range()),
754-
..diagnostic_base.clone()
755-
});
756-
}
757-
}
758-
} else {
759-
if in_validation {
760-
let valid_modules: Vec<OYarn> = symbols.iter().map(|s| match s.borrow().find_module() {
761-
Some(sym) => sym.borrow().name().clone(),
762-
None => Sy!("Unknown").clone()
763-
}).collect();
764-
if let Some(diagnostic_base) = create_diagnostic(&session, DiagnosticCode::OLS03001, &[&format!("{:?}", valid_modules)]) {
765-
diagnostics.push(Diagnostic {
766-
range: FileMgr::textRange_to_temporary_Range(&context.get(&S!("range")).unwrap().as_text_range()),
767-
..diagnostic_base.clone()
768-
});
769-
}
770-
}
771-
}
772-
} else if has_class_in_parents {
773-
if in_validation {
774-
if let Some(diagnostic_base) = create_diagnostic(&session, DiagnosticCode::OLS03002, &[]) {
775-
diagnostics.push(Diagnostic {
776-
range: FileMgr::textRange_to_temporary_Range(&context.get(&S!("range")).unwrap().as_text_range()),
777-
..diagnostic_base
778-
});
779-
};
780-
}
781-
}
782-
}
783-
} else if has_class_in_parents {
784-
if in_validation {
785-
if let Some(diagnostic_base) = create_diagnostic(&session, DiagnosticCode::OLS03002, &[]) {
786-
diagnostics.push(Diagnostic {
787-
range: FileMgr::textRange_to_temporary_Range(&context.get(&S!("range")).unwrap().as_text_range()),
788-
..diagnostic_base
789-
});
790-
};
791-
}
742+
} else {
743+
// Model exists but not in dependencies
744+
let valid_modules: Vec<OYarn> = symbols.iter().map(|s| match s.borrow().find_module() {
745+
Some(sym) => sym.borrow().name().clone(),
746+
None => Sy!("Unknown").clone()
747+
}).collect();
748+
if let Some(diagnostic_base) = create_diagnostic(&session, DiagnosticCode::OLS03001, &[&format!("{:?}", valid_modules)]) {
749+
diagnostics.push(Diagnostic {
750+
range: FileMgr::textRange_to_temporary_Range(&context.get(&S!("range")).unwrap().as_text_range()),
751+
..diagnostic_base.clone()
752+
});
792753
}
793754
}
794-
_ => {
795-
//NOT A STRING
755+
} else {
756+
// Model exists, but has no main symbols
757+
if let Some(diagnostic_base) = create_diagnostic(&session, DiagnosticCode::OLS03005, &[]) {
758+
diagnostics.push(Diagnostic {
759+
range: FileMgr::textRange_to_temporary_Range(&context.get(&S!("range")).unwrap().as_text_range()),
760+
..diagnostic_base
761+
});
796762
}
797763
}
798764
}
765+
} else if in_validation && has_class_in_parents {
766+
// Model Unknown
767+
if let Some(diagnostic_base) = create_diagnostic(&session, DiagnosticCode::OLS03002, &[]) {
768+
diagnostics.push(Diagnostic {
769+
range: FileMgr::textRange_to_temporary_Range(&context.get(&S!("range")).unwrap().as_text_range()),
770+
..diagnostic_base
771+
});
772+
}
773+
let Some(file_symbol) = scope.and_then(|scope| scope.borrow().get_file()).and_then(|file| file.upgrade()) else {
774+
return res
775+
};
776+
file_symbol.borrow_mut().as_file_mut().not_found_models.insert(Sy!(s.clone()), BuildSteps::VALIDATION);
777+
session.sync_odoo.get_main_entry().borrow_mut().not_found_symbols_for_models.insert(file_symbol.clone());
799778
}
800-
Some(EvaluationSymbolPtr::WEAK(EvaluationSymbolWeak::new(Weak::new(), Some(true), false)))
779+
res
801780
}
802781

803782
pub fn eval_registry_get_item(session: &mut SessionInfo, evaluation_sym: &EvaluationSymbol, context: &mut Option<Context>, diagnostics: &mut Vec<Diagnostic>, scope: Option<Rc<RefCell<Symbol>>>) -> Option<EvaluationSymbolPtr>

0 commit comments

Comments
 (0)