Skip to content

Commit 1c12fa2

Browse files
mmahroussfda-odoo
authored andcommitted
[IMP] validate inverse_name reverse model name
1 parent 7be614d commit 1c12fa2

File tree

6 files changed

+76
-14
lines changed

6 files changed

+76
-14
lines changed

server/src/core/diagnostic_codes_list.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ OLS03021, DiagnosticSetting::Error, "Inverse field {0} does not exist on comodel
163163
* On a One2many field, the inverse_name should be a field on the comodel that is a Many2one to the current model.
164164
*/
165165
OLS03022, DiagnosticSetting::Error, "Inverse field is not a Many2one field",
166+
/**
167+
* On a One2many field, the inverse_name should be a field on the comodel that is a Many2one to the current model.
168+
*/
169+
OLS03023, DiagnosticSetting::Error, "Inverse field {0} is not pointing to the current model {1}, but rather to {2}",
166170
/**
167171
* A __manifest__.py file should be evaluated with a literal_eval to a single dictionary.
168172
* Do not store any other information in it.

server/src/core/python_validator.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ impl PythonValidator {
429429
}
430430
let Some(field_type) = symbol
431431
.borrow()
432-
.get_member_symbol(session, &S!("type"), None, false, false, false, false)
432+
.get_member_symbol(session, &S!("type"), None, false, false, false, false, false)
433433
.0.first()
434434
.and_then(|field_type_var| field_type_var.borrow().evaluations().cloned())
435435
.and_then(|evals| evals.first().cloned())
@@ -452,7 +452,7 @@ impl PythonValidator {
452452
};
453453
let found = related_field_class_sym
454454
.borrow()
455-
.get_member_symbol(session, &S!("type"), None, false, false, false, false)
455+
.get_member_symbol(session, &S!("type"), None, false, false, false, false, false)
456456
.0.first()
457457
.and_then(|field_type_var| field_type_var.borrow().evaluations().cloned())
458458
.and_then(|evals| evals.first().cloned())
@@ -574,7 +574,42 @@ impl PythonValidator {
574574
..diagnostic_base.clone()
575575
});
576576
}
577-
577+
} else {
578+
// Check if we have a many2one field pointing to the comodel with another name than the current model
579+
let mut comodel_eval_weaks = Vec::new();
580+
for sym in symbols.iter() {
581+
let sym_ref = sym.borrow();
582+
let evals = sym_ref.evaluations().as_ref().unwrap().iter();
583+
for eval in evals {
584+
let followed = Symbol::follow_ref(
585+
&eval.symbol.get_symbol(session, &mut None, &mut vec![], None),
586+
session,
587+
&mut None,
588+
true,
589+
false,
590+
None,
591+
);
592+
comodel_eval_weaks.extend(followed);
593+
}
594+
}
595+
for comodel_eval_weak in comodel_eval_weaks {
596+
let Some(model_name) = comodel_eval_weak.as_weak().context.get(&S!("comodel_name")).map(|ctx_val| ctx_val.as_string()) else {
597+
continue;
598+
};
599+
if model_name == model_data.name.to_string() { // valid
600+
continue;
601+
}
602+
let Some(arg_range) = eval_weak.as_weak().context.get(&format!("inverse_name_arg_range")).map(|ctx_val| ctx_val.as_text_range()) else {
603+
continue;
604+
};
605+
if let Some(diagnostic_base) = create_diagnostic(&session, DiagnosticCode::OLS03023, &[&inverse_name, &model_data.name, &model_name]) {
606+
self.diagnostics.push(Diagnostic {
607+
range: Range::new(Position::new(arg_range.start().to_u32(), 0), Position::new(arg_range.end().to_u32(), 0)),
608+
..diagnostic_base.clone()
609+
});
610+
break;
611+
}
612+
}
578613
}
579614
}
580615
}

server/src/core/symbols/symbol.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2619,6 +2619,29 @@ impl Symbol {
26192619
}
26202620
}
26212621

2622+
pub fn is_method(&self, session: &mut SessionInfo) -> bool {
2623+
match self.typ() {
2624+
SymType::FUNCTION => true,
2625+
SymType::VARIABLE => {
2626+
if let Some(evals) = self.evaluations().as_ref() {
2627+
for eval in evals.iter() {
2628+
let symbol = eval.symbol.get_symbol(session, &mut None, &mut vec![], None);
2629+
let eval_weaks = Symbol::follow_ref(&symbol, session, &mut None, true, false, None);
2630+
for eval_weak in eval_weaks.iter() {
2631+
if let Some(symbol) = eval_weak.upgrade_weak() {
2632+
if symbol.borrow().typ() == SymType::FUNCTION {
2633+
return true;
2634+
}
2635+
}
2636+
}
2637+
}
2638+
}
2639+
false
2640+
},
2641+
_ => false,
2642+
}
2643+
}
2644+
26222645
pub fn is_inheriting_from_field(&self, session: &mut SessionInfo) -> bool {
26232646
// if not class return false
26242647
if !matches!(self.typ(), SymType::CLASS) {
@@ -2812,7 +2835,7 @@ impl Symbol {
28122835
content_syms = content_syms.iter().filter(|x| x.borrow().is_field(session)).cloned().collect();
28132836
}
28142837
if only_methods {
2815-
content_syms = content_syms.iter().filter(|x| x.borrow().typ() == SymType::FUNCTION).cloned().collect();
2838+
content_syms = content_syms.iter().filter(|x| x.borrow().is_method(session)).cloned().collect();
28162839
}
28172840
if !content_syms.is_empty() {
28182841
if all {

server/src/features/completion.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ fn complete_string_literal(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>
790790
};
791791
let main_syms = model.borrow().get_main_symbols(session, current_module.clone());
792792
main_syms.iter().for_each(|model_sym| {
793-
add_model_attributes(session, &mut items, current_module.clone(), model_sym.clone(), false, true, false, expr_string_literal.value.to_str(), &Some(S!("Many2one")))
793+
add_model_attributes(session, &mut items, current_module.clone(), model_sym.clone(), false, true, false, expr_string_literal.value.to_str(), &Some(Sy!("Many2one")))
794794
});
795795
},
796796
ExpectedType::CLASS(_) => {},

server/src/features/definition.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,10 @@ impl DefinitionFeature {
158158
return false;
159159
};
160160
let Some(call_expr) = call_expr else { return false };
161-
let compute_symbols = FeaturesUtils::find_field_symbols(
161+
let method_symbols = FeaturesUtils::find_kwarg_methods_symbols(
162162
session, Symbol::get_scope_symbol(file_symbol.clone(), offset as u32, false), file_symbol.borrow().find_module(), &value, call_expr, &offset
163163
);
164-
compute_symbols.iter().for_each(|field|{
164+
method_symbols.iter().for_each(|field|{
165165
if let Some(file_sym) = field.borrow().get_file().and_then(|file_sym_weak| file_sym_weak.upgrade()){
166166
let path = file_sym.borrow().paths()[0].clone();
167167
let range = session.sync_odoo.get_file_mgr().borrow().text_range_to_range(session, &path, &field.borrow().range());
@@ -173,7 +173,7 @@ impl DefinitionFeature {
173173
});
174174
}
175175
});
176-
compute_symbols.len() > 0
176+
method_symbols.len() > 0
177177
}
178178

179179
pub fn add_display_name_compute_methods(session: &mut SessionInfo, links: &mut Vec<LocationLink>, expr: &ExprOrIdent, file_symbol: &Rc<RefCell<Symbol>>, offset: usize) {
@@ -191,7 +191,7 @@ impl DefinitionFeature {
191191
let Some(symbol) = eval_ptr.upgrade_weak() else {
192192
return vec![];
193193
};
194-
symbol.borrow().get_member_symbol(session, &S!("_compute_display_name"), maybe_module.clone(), false, false, true, false).0
194+
symbol.borrow().get_member_symbol(session, &S!("_compute_display_name"), maybe_module.clone(), false, false, true, true, false).0
195195
}).collect::<Vec<_>>();
196196
for symbol in symbols {
197197
if let Some(file) = symbol.borrow().get_file() {

server/src/features/features_utils.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ struct InferredType {
4545
pub struct FeaturesUtils {}
4646

4747
impl FeaturesUtils {
48-
pub fn find_field_symbols(
48+
pub fn find_kwarg_methods_symbols(
4949
session: &mut SessionInfo,
5050
scope: Rc<RefCell<Symbol>>,
5151
from_module: Option<Rc<RefCell<Symbol>>>,
@@ -147,7 +147,7 @@ impl FeaturesUtils {
147147
let range_end = range_start + TextSize::new((name.len() + 1) as u32);
148148
let cursor_section = TextRange::new(range_start, range_end).contains(TextSize::new(*offset as u32));
149149
if cursor_section {
150-
let fields = parent_object.clone().unwrap().borrow().get_member_symbol(session, &name, from_module.clone(), false, true, false,true, false).0;
150+
let fields = parent_object.clone().unwrap().borrow().get_member_symbol(session, &name, from_module.clone(), false, true, false, true, false).0;
151151
return fields.into_iter().map(|f| (f, TextRange::new(range_start, range_end - TextSize::new(1)))).collect();
152152
} else {
153153
let (symbols, _diagnostics) = parent_object.clone().unwrap().borrow().get_member_symbol(session,
@@ -342,9 +342,9 @@ impl FeaturesUtils {
342342
if string_domain_fields_syms.len() >= 1 {
343343
return string_domain_fields_syms.into_iter().map(|(sym, _)| sym).collect();
344344
}
345-
let compute_kwarg_syms = FeaturesUtils::find_field_symbols(session, scope.clone(), from_module.clone(), string_val, call_expr, &offset);
346-
if compute_kwarg_syms.len() >= 1{
347-
return compute_kwarg_syms;
345+
let kwarg_syms = FeaturesUtils::find_kwarg_methods_symbols(session, scope.clone(), from_module.clone(), string_val, call_expr, &offset);
346+
if kwarg_syms.len() >= 1{
347+
return kwarg_syms;
348348
}
349349
vec![]
350350
}

0 commit comments

Comments
 (0)