Skip to content

Commit 8adfe8b

Browse files
committed
[IMP] server: detect "delegate=True" for inherits in models
1 parent 9958287 commit 8adfe8b

File tree

7 files changed

+104
-8
lines changed

7 files changed

+104
-8
lines changed

server/src/core/evaluation.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,39 @@ impl Evaluation {
612612
(None, value.diagnostics)
613613
}
614614

615+
/* Given an Expr, try to return the represented Boolean. None if it can't be achieved */
616+
pub fn expr_to_bool(session: &mut SessionInfo, ast: &Expr, parent: Rc<RefCell<Symbol>>, max_infer: &TextSize, diagnostics: &mut Vec<Diagnostic>) -> (Option<bool>, Vec<Diagnostic>) {
617+
let from_module;
618+
if let Some(module) = parent.borrow().find_module() {
619+
from_module = ContextValue::MODULE(Rc::downgrade(&module));
620+
} else {
621+
from_module = ContextValue::BOOLEAN(false);
622+
}
623+
let mut context: Option<Context> = Some(HashMap::from([
624+
(S!("module"), from_module),
625+
(S!("range"), ContextValue::RANGE(ast.range()))
626+
]));
627+
let value = Evaluation::analyze_ast(session, &ExprOrIdent::Expr(ast), parent, max_infer, &mut context, &mut vec![]);
628+
if value.evaluations.len() == 1 { //only handle strict evaluations
629+
let eval = &value.evaluations[0];
630+
let v = eval.follow_ref_and_get_value(session, &mut None, diagnostics);
631+
if let Some(v) = v {
632+
match v {
633+
EvaluationValue::CONSTANT(v) => {
634+
match v {
635+
Expr::BooleanLiteral(s) => {
636+
return (Some(s.value), value.diagnostics);
637+
},
638+
_ => {}
639+
}
640+
},
641+
_ => {}
642+
}
643+
}
644+
}
645+
(None, value.diagnostics)
646+
}
647+
615648

616649
/**
617650
analyze_ast will extract all known information about an ast:

server/src/core/model.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ impl Model {
208208
} else {
209209
symbols.push((s.clone(), None));
210210
}
211-
if with_inheritance {
211+
if with_inheritance { //TODO wrong, should be recursive
212212
let inherited_models = s.borrow().as_class_sym()._model.as_ref().unwrap().inherit.clone();
213213
for inherited_model in inherited_models.iter() {
214214
if !seen_inherited_models.contains(inherited_model) {

server/src/core/python_arch_eval_hooks.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::cmp::Ordering;
22
use std::collections::HashMap;
3+
use std::ops::Index;
34
use std::rc::Rc;
45
use std::rc::Weak;
56
use std::cell::RefCell;
@@ -866,6 +867,7 @@ impl PythonArchEvalHooks {
866867
"comodel_name",
867868
"related",
868869
"compute",
870+
"delegate",
869871
];
870872
contexts_to_add.extend(
871873
context_arguments.into_iter()
@@ -880,6 +882,11 @@ impl PythonArchEvalHooks {
880882
if let Some(related_string) = maybe_related_string {
881883
context.insert(S!(arg_name), ContextValue::STRING(related_string.to_string()));
882884
context.insert(format!("{arg_name}_arg_range"), ContextValue::RANGE(arg_range.clone()));
885+
} else {
886+
let maybe_boolean = Evaluation::expr_to_bool(session, field_name_expr, parent.clone(), &parameters.range.start(), &mut vec![]).0;
887+
if let Some(boolean) = maybe_boolean {
888+
context.insert(S!(arg_name), ContextValue::BOOLEAN(boolean));
889+
}
883890
}
884891
}
885892

server/src/core/python_odoo_builder.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::cmp::Ordering;
2-
use std::collections::HashSet;
2+
use std::collections::{HashMap, HashSet};
33
use std::rc::Rc;
44
use std::cell::RefCell;
55
use ruff_python_ast::Expr;
@@ -191,6 +191,33 @@ impl PythonOdooBuilder {
191191
}
192192
}
193193
}
194+
drop(_inherits);
195+
drop(symbol);
196+
//Add inherits from delegate=True from fields
197+
let mut all_fields = HashMap::new();
198+
Symbol::all_members(&self.symbol, session, &mut all_fields, false, true, false, None, &mut None, false);
199+
for (field_name, symbols) in all_fields.iter() {
200+
for (symbol, _deps) in symbols.iter() {
201+
if let Some(evals) = symbol.borrow().evaluations() {
202+
for eval in evals.iter() {
203+
let symbol_weak = eval.symbol.get_symbol_as_weak(session, &mut None, diagnostics, self.symbol.borrow().get_file().unwrap().upgrade());
204+
if let Some(eval_symbol) = symbol_weak.weak.upgrade() {
205+
if eval_symbol.borrow().name() == &Sy!("Many2one") {
206+
let context = &symbol_weak.context;
207+
if let Some(delegate) = context.get("delegate") {
208+
if delegate.as_bool() == true {
209+
if let Some(comodel) = context.get("comodel_name") {
210+
let comodel_name = oyarn!("{}", comodel.as_string());
211+
self.symbol.borrow_mut().as_class_sym_mut()._model.as_mut().unwrap().inherits.push((comodel_name, field_name.clone()));
212+
}
213+
}
214+
}
215+
}
216+
}
217+
}
218+
}
219+
}
220+
}
194221
}
195222

196223
fn _get_attribute(session: &mut SessionInfo, loc_sym: &mut Symbol, attr: &String, diagnostics: &mut Vec<Diagnostic>) -> Option<EvaluationValue> {

server/src/core/python_validator.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ use tracing::{trace, warn};
55
use std::rc::Rc;
66
use std::cell::RefCell;
77
use std::path::PathBuf;
8-
use lsp_types::{Diagnostic, Position, Range};
8+
use lsp_types::{Diagnostic, DiagnosticSeverity, NumberOrString, Position, Range};
99
use crate::core::diagnostics::{create_diagnostic, DiagnosticCode};
10+
use crate::core::evaluation::ContextValue;
1011
use crate::{constants::*, oyarn, Sy};
1112
use crate::core::symbols::symbol::Symbol;
1213
use crate::core::odoo::SyncOdoo;
@@ -389,7 +390,7 @@ impl PythonValidator {
389390
if !symbol.borrow().is_field_class(session){
390391
continue;
391392
}
392-
if let Some(related_field_name) = eval_weak.as_weak().context.get(&S!("related")).map(|ctx_val| ctx_val.as_string()) {
393+
if let Some(related_field_name) = eval_weak.as_weak().context.get(&S!("related")).filter(|val| matches!(val, ContextValue::STRING(s))).map(|ctx_val| ctx_val.as_string()) {
393394
let Some(special_arg_range) = eval_weak.as_weak().context.get(&S!("related_arg_range")).map(|ctx_val| ctx_val.as_text_range()) else {
394395
continue;
395396
};

server/src/core/symbols/symbol.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2259,7 +2259,7 @@ impl Symbol {
22592259
iter.into_iter()
22602260
}
22612261

2262-
//store in result all available members for self: sub symbols, base class elements and models symbols
2262+
//store in result all available members for symbol: sub symbols, base class elements and models symbols
22632263
//TODO is order right of Vec in HashMap? if we take first or last in it, do we have the last effective value?
22642264
pub fn all_members(symbol: &Rc<RefCell<Symbol>>, session: &mut SessionInfo, result: &mut HashMap<OYarn, Vec<(Rc<RefCell<Symbol>>, Option<OYarn>)>>, with_co_models: bool, only_fields: bool, only_methods: bool, from_module: Option<Rc<RefCell<Symbol>>>, acc: &mut Option<HashSet<Tree>>, is_super: bool) {
22652265
if acc.is_none() {
@@ -2279,7 +2279,7 @@ impl Symbol {
22792279
if only_fields && !symbol.borrow().is_field(session){
22802280
continue;
22812281
}
2282-
if only_methods && symbol.borrow().typ() != SymType::FUNCTION{
2282+
if only_methods && symbol.borrow().typ() != SymType::FUNCTION {
22832283
continue;
22842284
}
22852285
let name = symbol.borrow().name().clone();
@@ -2311,6 +2311,25 @@ impl Symbol {
23112311
result.insert(name.clone(), vec![(s, Some(model_sym.borrow().name().clone()))]);
23122312
}
23132313
}
2314+
//add fields from _inherits
2315+
if let Some(model_data) = model_sym.borrow().as_class_sym()._model.as_ref() {
2316+
for (inherits_model, inherits_field) in model_data.inherits.iter() {
2317+
let inherits_model_sym = session.sync_odoo.models.get(inherits_model).cloned();
2318+
if let Some(inherits_model_sym) = inherits_model_sym {
2319+
for (model_symbol, deps) in inherits_model_sym.borrow().all_symbols(session, from_module.clone(), true).iter().filter(|(x, deps)| deps.is_none()) {
2320+
for (field_name, field_symbols) in Symbol::all_fields(&model_symbol, session, from_module.clone()) {
2321+
for (s, deps) in field_symbols.iter().filter(|(x, deps)| deps.is_none()) {
2322+
if let Some(vec) = result.get_mut(&field_name) {
2323+
vec.push((s.clone(), Some(model_sym.borrow().name().clone())));
2324+
} else {
2325+
result.insert(field_name.clone(), vec![(s.clone(), Some(model_sym.borrow().name().clone()))]);
2326+
}
2327+
}
2328+
}
2329+
}
2330+
}
2331+
}
2332+
}
23142333
}
23152334
}
23162335
}
@@ -2319,6 +2338,7 @@ impl Symbol {
23192338
let bases = symbol.borrow().as_class_sym().bases.clone();
23202339
for base in bases.iter() {
23212340
//no comodel as we will search for co-model from original class (what about overrided _name?)
2341+
//TODO what about base of co-models classes?
23222342
if let Some(base) = base.upgrade() {
23232343
Symbol::all_members(&base, session, result, false, only_fields, only_methods, from_module.clone(), acc, false);
23242344
}
@@ -2339,6 +2359,9 @@ impl Symbol {
23392359
}
23402360
}
23412361
}
2362+
2363+
2364+
23422365
/* return the Symbol (class, function or file) the closest to the given offset */
23432366
pub fn get_scope_symbol(file_symbol: Rc<RefCell<Symbol>>, offset: u32, is_param: bool) -> Rc<RefCell<Symbol>> {
23442367
let mut result = file_symbol.clone();
@@ -2610,6 +2633,12 @@ impl Symbol {
26102633
false
26112634
}
26122635

2636+
pub fn all_fields(symbol: &Rc<RefCell<Symbol>>, session: &mut SessionInfo, from_module: Option<Rc<RefCell<Symbol>>>) -> HashMap<OYarn, Vec<(Rc<RefCell<Symbol>>, Option<OYarn>)>> {
2637+
let mut all_fields = HashMap::new();
2638+
Symbol::all_members(symbol, session, &mut all_fields, true, true, false, from_module.clone(), &mut None, false);
2639+
all_fields
2640+
}
2641+
26132642
/* similar to get_symbol: will return the symbol that is under this one with the specified name.
26142643
However, if the symbol is a class or a model, it will search in the base class or in comodel classes
26152644
if not all, it will return the first found. If all, the all found symbols are returned, but the first one

server/src/core/xml_validation.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ impl XmlValidator {
8888
for main_sym in main_symbols.iter() {
8989
dependencies.push(main_sym.borrow().get_file().unwrap().upgrade().unwrap());
9090
}
91-
let mut all_fields = HashMap::new();
92-
Symbol::all_members(&main_symbols[0], session, &mut all_fields, true, true, false, Some(module.clone()), &mut None, false);
91+
let all_fields = Symbol::all_fields(&main_symbols[0], session, Some(module.clone()));
9392
for field in &xml_data_record.fields {
9493
let declared_field = all_fields.get(&field.name);
9594
if let Some(declared_field) = declared_field {

0 commit comments

Comments
 (0)