From 1adcef456a47f387620235513372108e3bf53707 Mon Sep 17 00:00:00 2001 From: M Mahrous Date: Mon, 23 Feb 2026 15:03:57 +0100 Subject: [PATCH] [FIX] follow ref in completion of calls This makes sure we are completing the final callable a class for fields to get the correct result --- server/src/features/completion.rs | 101 +++++++++++++++--------------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/server/src/features/completion.rs b/server/src/features/completion.rs index 3b5312df..364780e9 100644 --- a/server/src/features/completion.rs +++ b/server/src/features/completion.rs @@ -590,67 +590,70 @@ fn complete_call(session: &mut SessionInfo, file: &Rc>, expr_cal let scope = Symbol::get_scope_symbol(file.clone(), offset as u32, is_param); AstUtils::build_scope(session, &scope); let callable_evals = Evaluation::eval_from_ast(session, &expr_call.func, scope, &expr_call.func.range().start(), false, &mut vec![]).0; - for (arg_index, arg) in expr_call.arguments.args.iter().enumerate() { - if offset > arg.range().start().to_usize() && offset <= arg.range().end().to_usize() { - for callable_eval in callable_evals.iter() { - let callable = callable_eval.symbol.get_symbol_as_weak(session, &mut None, &mut vec![], None); - let Some(callable_sym) = callable.weak.upgrade() else {continue}; - match callable_sym.borrow().typ(){ - SymType::FUNCTION => { - let func = callable_sym.borrow(); - let func = func.as_func(); - let func_arg = func.get_indexed_arg_in_call( - expr_call, - arg_index as u32, - callable.context.get(&S!("is_attr_of_instance")).map(|v| v.as_bool())); - if let Some(func_arg) = func_arg { - if let Some(func_arg_sym) = func_arg.symbol.upgrade() { - let mut expected_type = vec![]; - for evaluation in func_arg_sym.borrow().evaluations().unwrap().iter() { - match evaluation.symbol.get_symbol_ptr() { - EvaluationSymbolPtr::WEAK(_weak) => { - //if weak, use get_symbol - let symbol= evaluation.symbol.get_symbol_as_weak(session, &mut None, &mut vec![], None); - if let Some(evaluation) = symbol.weak.upgrade() { - if evaluation.borrow().typ() == SymType::CLASS { - expected_type.push(ExpectedType::CLASS(evaluation.clone())); - } - } - }, - EvaluationSymbolPtr::DOMAIN => { - if let Some(parent) = callable.context.get(&S!("base_attr")) - .and_then(|parent_value| parent_value.as_symbol().upgrade()) { - expected_type.push(ExpectedType::DOMAIN(parent)); + let callable_eval_sym_ptrs = callable_evals.iter().flat_map(|callable_eval| + Symbol::follow_ref(&callable_eval.symbol.get_symbol(session, &mut None, &mut vec![], None), session, &mut None, false, false, None, None) + ).collect::>(); + if let Some((arg_index, arg)) = expr_call.arguments.args.iter().find_position(|arg| + offset > arg.range().start().to_usize() && offset <= arg.range().end().to_usize() + ){ + for callable_eval in callable_evals.iter() { + let callable = callable_eval.symbol.get_symbol_as_weak(session, &mut None, &mut vec![], None); + let Some(callable_sym) = callable.weak.upgrade() else {continue}; + match callable_sym.borrow().typ(){ + SymType::FUNCTION => { + let func = callable_sym.borrow(); + let func = func.as_func(); + let func_arg = func.get_indexed_arg_in_call( + expr_call, + arg_index as u32, + callable.context.get(&S!("is_attr_of_instance")).map(|v| v.as_bool())); + if let Some(func_arg) = func_arg { + if let Some(func_arg_sym) = func_arg.symbol.upgrade() { + let mut expected_type = vec![]; + for evaluation in func_arg_sym.borrow().evaluations().unwrap().iter() { + match evaluation.symbol.get_symbol_ptr() { + EvaluationSymbolPtr::WEAK(_weak) => { + //if weak, use get_symbol + let symbol= evaluation.symbol.get_symbol_as_weak(session, &mut None, &mut vec![], None); + if let Some(evaluation) = symbol.weak.upgrade() { + if evaluation.borrow().typ() == SymType::CLASS { + expected_type.push(ExpectedType::CLASS(evaluation.clone())); } } - _ => {} + }, + EvaluationSymbolPtr::DOMAIN => { + if let Some(parent) = callable.context.get(&S!("base_attr")) + .and_then(|parent_value| parent_value.as_symbol().upgrade()) { + expected_type.push(ExpectedType::DOMAIN(parent)); + } } + _ => {} } - return complete_expr(arg, session, file, offset, is_param, &expected_type); } + return complete_expr(arg, session, file, offset, is_param, &expected_type); } - }, - SymType::CLASS => { - // check for completion of first positional argument for comodel_name - if arg_index != 0 || !callable_sym.borrow().is_specific_field_class(session, &["Many2one", "One2many", "Many2many"]) { - break; - } - return complete_expr(arg, session, file, offset, is_param, &vec![ExpectedType::MODEL_NAME]); - }, - _ => {} - }; - } - //if we didn't find anything, still try to complete - return complete_expr(arg, session, file, offset, is_param, &vec![]); + } + }, + SymType::CLASS => { + // check for completion of first positional argument for comodel_name + if arg_index != 0 || !callable_sym.borrow().is_specific_field_class(session, &["Many2one", "One2many", "Many2many"]) { + break; + } + return complete_expr(arg, session, file, offset, is_param, &vec![ExpectedType::MODEL_NAME]); + }, + _ => {} + }; } + //if we didn't find anything, still try to complete + return complete_expr(arg, session, file, offset, is_param, &vec![]); } let Some(keyword) = expr_call.arguments.keywords.iter().find(|arg| offset > arg.range().start().to_usize() && offset <= arg.range().end().to_usize()) else { return None; }; - for callable_eval in callable_evals.iter() { - let callable = callable_eval.symbol.get_symbol_as_weak(session, &mut None, &mut vec![], None); - let Some(callable_sym) = callable.weak.upgrade() else {continue}; + for callable_eval_sym_ptr in callable_eval_sym_ptrs.iter() { + let callable = callable_eval_sym_ptr.upgrade_weak(); + let Some(callable_sym) = callable else {return None;}; if callable_sym.borrow().typ() != SymType::CLASS || !callable_sym.borrow().is_field_class(session){ continue; }