Skip to content

[IMP] server: completion of inherits model attr #352

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 42 additions & 17 deletions server/src/features/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use super::features_utils::TypeInfo;


#[allow(non_camel_case_types)]
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum ExpectedType {
MODEL_NAME,
DOMAIN(Rc<RefCell<Symbol>>),
Expand All @@ -32,7 +32,7 @@ pub enum ExpectedType {
DOMAIN_FIELD(Rc<RefCell<Symbol>>),
DOMAIN_COMPARATOR,
CLASS(Rc<RefCell<Symbol>>),
SIMPLE_FIELD,
SIMPLE_FIELD(Option<OYarn>),
NESTED_FIELD(Option<OYarn>),
METHOD_NAME,
}
Expand Down Expand Up @@ -159,7 +159,7 @@ fn complete_assign_stmt(session: &mut SessionInfo<'_>, file: &Rc<RefCell<Symbol>
let mut expected_type = vec![];
if stmt_assign.targets.len() == 1 {
if let Some(target_name) = stmt_assign.targets.first().unwrap().as_name_expr() {
if target_name.id == "_inherit" {
if ["_inherit", "_inherits"].contains(&target_name.id.as_str()) {
expected_type.push(ExpectedType::MODEL_NAME);
}
}
Expand Down Expand Up @@ -376,7 +376,7 @@ fn complete_expr(expr: &Expr, session: &mut SessionInfo, file: &Rc<RefCell<Symbo
Expr::Lambda(expr_lambda) => compare_lambda(session, file, expr_lambda, offset, is_param, expected_type),
Expr::If(expr_if) => complete_if_expr(session, file, expr_if, offset, is_param, expected_type),
Expr::Dict(expr_dict) => complete_dict(session, file, expr_dict, offset, is_param, expected_type),
Expr::Set(_) => None,
Expr::Set(expr_set) => complete_set(session, file, expr_set, offset, is_param, expected_type),
Expr::ListComp(_) => None,
Expr::SetComp(_) => None,
Expr::DictComp(_) => None,
Expand Down Expand Up @@ -460,14 +460,32 @@ fn complete_if_expr(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>, expr_

fn complete_dict(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>, expr_dict: &ruff_python_ast::ExprDict, offset: usize, is_param: bool, expected_type: &Vec<ExpectedType>) -> Option<CompletionResponse> {
for dict_item in expr_dict.items.iter() {
if dict_item.key.is_some() {
if let Some(dict_item_key) = &dict_item.key {
if offset > dict_item_key.range().start().to_usize() && offset <= dict_item_key.range().end().to_usize() {
return complete_expr( dict_item_key, session, file, offset, is_param, expected_type);
}
if offset > dict_item.value.range().start().to_usize() && offset <= dict_item.value.range().end().to_usize() {
return complete_expr( &dict_item.value, session, file, offset, is_param, expected_type);
// if expected type has model name, replace it with simple field
// for _inherits completion
let mut expected_type = expected_type.clone();
if expected_type.iter().any(|t| matches!(t, ExpectedType::MODEL_NAME)) {
expected_type.retain(|t| !matches!(t, ExpectedType::MODEL_NAME));
expected_type.push(ExpectedType::SIMPLE_FIELD(Some(Sy!("Many2one"))));
}
return complete_expr( &dict_item.value, session, file, offset, is_param, &expected_type);
}
}
}
None
}
fn complete_set(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>, expr_set: &ruff_python_ast::ExprSet, offset: usize, is_param: bool, expected_type: &Vec<ExpectedType>) -> Option<CompletionResponse> {
for set_item in expr_set.elts.iter() {
if offset > set_item.range().start().to_usize() && offset <= set_item.range().end().to_usize() {
return complete_expr( set_item, session, file, offset, is_param, expected_type);
}
}
None
}

fn complete_yield(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>, expr_yield: &ExprYield, offset: usize, is_param: bool, expected_type: &Vec<ExpectedType>) -> Option<CompletionResponse> {
if expr_yield.value.is_some() && offset > expr_yield.value.as_ref().unwrap().range().start().to_usize() && offset <= expr_yield.value.as_ref().unwrap().range().end().to_usize() {
Expand Down Expand Up @@ -522,7 +540,7 @@ fn complete_decorator_call(
let expected_types = if (version_comparison < Ordering::Equal && dec_sym_tree.0.ends_with(&[Sy!("odoo"), Sy!("api")])) ||
(version_comparison >= Ordering::Equal && dec_sym_tree.0.ends_with(&[Sy!("odoo"), Sy!("orm"), Sy!("decorators")])) {
if [vec![Sy!("onchange")], vec![Sy!("constrains")]].contains(&dec_sym_tree.1) && SyncOdoo::is_in_main_entry(session, &dec_sym_tree.0) {
&vec![ExpectedType::SIMPLE_FIELD]
&vec![ExpectedType::SIMPLE_FIELD(None)]
} else if dec_sym_tree.1 == vec![Sy!("depends")] && SyncOdoo::is_in_main_entry(session, &dec_sym_tree.0){
&vec![ExpectedType::NESTED_FIELD(None)]
} else {
Expand Down Expand Up @@ -717,7 +735,7 @@ fn complete_string_literal(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>
ExpectedType::DOMAIN_FIELD(parent) => {
add_nested_field_names(session, &mut items, current_module.clone(), expr_string_literal.value.to_str(), parent.clone(), true, &None);
},
ExpectedType::SIMPLE_FIELD | ExpectedType::NESTED_FIELD(_) | ExpectedType::METHOD_NAME => 'field_block: {
ExpectedType::SIMPLE_FIELD(_) | ExpectedType::NESTED_FIELD(_) | ExpectedType::METHOD_NAME => 'field_block: {
let scope = Symbol::get_scope_symbol(file.clone(), expr_string_literal.range().start().to_u32(), true);
let Some(parent_class) = scope.borrow().get_in_parents(&vec![SymType::CLASS], true).and_then(|p| p.upgrade()) else {
break 'field_block;
Expand All @@ -726,10 +744,10 @@ fn complete_string_literal(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>
break 'field_block;
}
match expected_type {
ExpectedType::SIMPLE_FIELD => add_model_attributes(
session, &mut items, current_module.clone(), parent_class, false, true, false, expr_string_literal.value.to_str()),
ExpectedType::SIMPLE_FIELD(maybe_field_type) => add_model_attributes(
session, &mut items, current_module.clone(), parent_class, false, true, false, expr_string_literal.value.to_str(), maybe_field_type),
ExpectedType::METHOD_NAME => add_model_attributes(
session, &mut items, current_module.clone(), parent_class, false, false, true, expr_string_literal.value.to_str()),
session, &mut items, current_module.clone(), parent_class, false, false, true, expr_string_literal.value.to_str(), &None),
ExpectedType::NESTED_FIELD(maybe_field_type) => add_nested_field_names(
session, &mut items, current_module.clone(), expr_string_literal.value.to_str(), parent_class, false, maybe_field_type),
_ => unreachable!()
Expand Down Expand Up @@ -764,7 +782,7 @@ fn complete_attribut(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>, attr
let parent_sym_types = Symbol::follow_ref(&parent_sym_eval, session, &mut None, false, false, None, &mut vec![]);
for parent_sym_type in parent_sym_types.iter() {
let Some(parent_sym) = parent_sym_type.upgrade_weak() else {continue};
add_model_attributes(session, &mut items, from_module.clone(), parent_sym, parent_sym_eval.as_weak().is_super, false, false, attr.attr.id.as_str())
add_model_attributes(session, &mut items, from_module.clone(), parent_sym, parent_sym_eval.as_weak().is_super, false, false, attr.attr.id.as_str(), &None)
}
}
}
Expand Down Expand Up @@ -998,18 +1016,25 @@ fn add_model_attributes(
is_super: bool,
only_fields: bool,
only_methods: bool,
attribute_name: &str
attribute_name: &str,
specific_field_type: &Option<OYarn>,
){
let mut all_symbols: HashMap<OYarn, Vec<(Rc<RefCell<Symbol>>, Option<OYarn>)>> = HashMap::new();
Symbol::all_members(&parent_sym, session, &mut all_symbols, true, only_fields, only_methods, from_module.clone(), &mut None, is_super);
for (_symbol_name, symbols) in all_symbols {
//we could use symbol_name to remove duplicated names, but it would hide functions vs variables
if _symbol_name.starts_with(attribute_name) {
if let Some((final_sym, dep)) = symbols.first() {
let context_of_symbol = HashMap::from([(S!("base_attr"), ContextValue::SYMBOL(Rc::downgrade(&parent_sym)))]);
items.push(build_completion_item_from_symbol(session, vec![final_sym.clone()], context_of_symbol));
let Some((final_sym, _dep)) = symbols.first() else {
continue;
};
if let Some(field_type) = specific_field_type {
if !final_sym.borrow().is_specific_field(session, &[field_type.as_str()]) {
continue;
}
}
if _symbol_name.starts_with(attribute_name) {
let context_of_symbol = HashMap::from([(S!("base_attr"), ContextValue::SYMBOL(Rc::downgrade(&parent_sym)))]);
items.push(build_completion_item_from_symbol(session, vec![final_sym.clone()], context_of_symbol));
}
}
}

Expand Down