@@ -23,7 +23,7 @@ use super::features_utils::TypeInfo;
2323
2424
2525#[ allow( non_camel_case_types) ]
26- #[ derive( Debug ) ]
26+ #[ derive( Debug , Clone ) ]
2727pub enum ExpectedType {
2828 MODEL_NAME ,
2929 DOMAIN ( Rc < RefCell < Symbol > > ) ,
@@ -32,9 +32,10 @@ pub enum ExpectedType {
3232 DOMAIN_FIELD ( Rc < RefCell < Symbol > > ) ,
3333 DOMAIN_COMPARATOR ,
3434 CLASS ( Rc < RefCell < Symbol > > ) ,
35- SIMPLE_FIELD ,
35+ SIMPLE_FIELD ( Option < OYarn > ) ,
3636 NESTED_FIELD ( Option < OYarn > ) ,
3737 METHOD_NAME ,
38+ INHERITS ,
3839}
3940
4041pub struct CompletionFeature ;
@@ -159,8 +160,10 @@ fn complete_assign_stmt(session: &mut SessionInfo<'_>, file: &Rc<RefCell<Symbol>
159160 let mut expected_type = vec ! [ ] ;
160161 if stmt_assign. targets . len ( ) == 1 {
161162 if let Some ( target_name) = stmt_assign. targets . first ( ) . unwrap ( ) . as_name_expr ( ) {
162- if target_name. id == "_inherit" {
163- expected_type. push ( ExpectedType :: MODEL_NAME ) ;
163+ match target_name. id . as_str ( ) {
164+ "_inherit" => expected_type. push ( ExpectedType :: MODEL_NAME ) ,
165+ "_inherits" => expected_type. push ( ExpectedType :: INHERITS ) ,
166+ _ => { }
164167 }
165168 }
166169 }
@@ -376,7 +379,7 @@ fn complete_expr(expr: &Expr, session: &mut SessionInfo, file: &Rc<RefCell<Symbo
376379 Expr :: Lambda ( expr_lambda) => compare_lambda ( session, file, expr_lambda, offset, is_param, expected_type) ,
377380 Expr :: If ( expr_if) => complete_if_expr ( session, file, expr_if, offset, is_param, expected_type) ,
378381 Expr :: Dict ( expr_dict) => complete_dict ( session, file, expr_dict, offset, is_param, expected_type) ,
379- Expr :: Set ( _ ) => None ,
382+ Expr :: Set ( expr_set ) => complete_set ( session , file , expr_set , offset , is_param , expected_type ) ,
380383 Expr :: ListComp ( _) => None ,
381384 Expr :: SetComp ( _) => None ,
382385 Expr :: DictComp ( _) => None ,
@@ -460,15 +463,44 @@ fn complete_if_expr(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>, expr_
460463
461464fn 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 > {
462465 for dict_item in expr_dict. items . iter ( ) {
463- if dict_item. key . is_some ( ) {
466+ if let Some ( dict_item_key) = & dict_item. key {
467+ // For expected type INHERITS, we want to complete the model name for the key
468+ // and a simple field of type Many2one for the value
469+ if offset > dict_item_key. range ( ) . start ( ) . to_usize ( ) && offset <= dict_item_key. range ( ) . end ( ) . to_usize ( ) {
470+ let expected_type= expected_type. iter ( ) . map ( |e| match e {
471+ ExpectedType :: INHERITS => ExpectedType :: MODEL_NAME ,
472+ _ => e. clone ( ) ,
473+ } ) . collect ( ) ;
474+ return complete_expr ( dict_item_key, session, file, offset, is_param, & expected_type) ;
475+ }
464476 if offset > dict_item. value . range ( ) . start ( ) . to_usize ( ) && offset <= dict_item. value . range ( ) . end ( ) . to_usize ( ) {
465- return complete_expr ( & dict_item. value , session, file, offset, is_param, expected_type) ;
477+ // if expected type has model name, replace it with simple field
478+ // for _inherits completion
479+ let expected_type = expected_type. iter ( ) . map ( |e| match e {
480+ ExpectedType :: INHERITS => ExpectedType :: SIMPLE_FIELD ( Some ( Sy ! ( "Many2one" ) ) ) ,
481+ _ => e. clone ( ) ,
482+ } ) . collect ( ) ;
483+ return complete_expr ( & dict_item. value , session, file, offset, is_param, & expected_type) ;
466484 }
467485 }
468486 }
469487 None
470488}
471489
490+ 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 > {
491+ for set_item in expr_set. elts . iter ( ) {
492+ if offset > set_item. range ( ) . start ( ) . to_usize ( ) && offset <= set_item. range ( ) . end ( ) . to_usize ( ) {
493+ // A set expression here is just starting to write the inherits dict
494+ let expected_type= expected_type. iter ( ) . map ( |e| match e {
495+ ExpectedType :: INHERITS => ExpectedType :: MODEL_NAME ,
496+ _ => e. clone ( ) ,
497+ } ) . collect ( ) ;
498+ return complete_expr ( set_item, session, file, offset, is_param, & expected_type) ;
499+ }
500+ }
501+ None
502+ }
503+
472504fn complete_yield ( session : & mut SessionInfo , file : & Rc < RefCell < Symbol > > , expr_yield : & ExprYield , offset : usize , is_param : bool , expected_type : & Vec < ExpectedType > ) -> Option < CompletionResponse > {
473505 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 ( ) {
474506 return complete_expr ( expr_yield. value . as_ref ( ) . unwrap ( ) , session, file, offset, is_param, expected_type) ;
@@ -522,7 +554,7 @@ fn complete_decorator_call(
522554 let expected_types = if ( version_comparison < Ordering :: Equal && dec_sym_tree. 0 . ends_with ( & [ Sy ! ( "odoo" ) , Sy ! ( "api" ) ] ) ) ||
523555 ( version_comparison >= Ordering :: Equal && dec_sym_tree. 0 . ends_with ( & [ Sy ! ( "odoo" ) , Sy ! ( "orm" ) , Sy ! ( "decorators" ) ] ) ) {
524556 if [ vec ! [ Sy !( "onchange" ) ] , vec ! [ Sy !( "constrains" ) ] ] . contains ( & dec_sym_tree. 1 ) && SyncOdoo :: is_in_main_entry ( session, & dec_sym_tree. 0 ) {
525- & vec ! [ ExpectedType :: SIMPLE_FIELD ]
557+ & vec ! [ ExpectedType :: SIMPLE_FIELD ( None ) ]
526558 } else if dec_sym_tree. 1 == vec ! [ Sy !( "depends" ) ] && SyncOdoo :: is_in_main_entry ( session, & dec_sym_tree. 0 ) {
527559 & vec ! [ ExpectedType :: NESTED_FIELD ( None ) ]
528560 } else {
@@ -717,7 +749,7 @@ fn complete_string_literal(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>
717749 ExpectedType :: DOMAIN_FIELD ( parent) => {
718750 add_nested_field_names ( session, & mut items, current_module. clone ( ) , expr_string_literal. value . to_str ( ) , parent. clone ( ) , true , & None ) ;
719751 } ,
720- ExpectedType :: SIMPLE_FIELD | ExpectedType :: NESTED_FIELD ( _) | ExpectedType :: METHOD_NAME => ' field_block: {
752+ ExpectedType :: SIMPLE_FIELD ( _ ) | ExpectedType :: NESTED_FIELD ( _) | ExpectedType :: METHOD_NAME => ' field_block: {
721753 let scope = Symbol :: get_scope_symbol ( file. clone ( ) , expr_string_literal. range ( ) . start ( ) . to_u32 ( ) , true ) ;
722754 let Some ( parent_class) = scope. borrow ( ) . get_in_parents ( & vec ! [ SymType :: CLASS ] , true ) . and_then ( |p| p. upgrade ( ) ) else {
723755 break ' field_block;
@@ -726,16 +758,17 @@ fn complete_string_literal(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>
726758 break ' field_block;
727759 }
728760 match expected_type {
729- ExpectedType :: SIMPLE_FIELD => add_model_attributes (
730- session, & mut items, current_module. clone ( ) , parent_class, false , true , false , expr_string_literal. value . to_str ( ) ) ,
761+ ExpectedType :: SIMPLE_FIELD ( maybe_field_type ) => add_model_attributes (
762+ session, & mut items, current_module. clone ( ) , parent_class, false , true , false , expr_string_literal. value . to_str ( ) , maybe_field_type ) ,
731763 ExpectedType :: METHOD_NAME => add_model_attributes (
732- session, & mut items, current_module. clone ( ) , parent_class, false , false , true , expr_string_literal. value . to_str ( ) ) ,
764+ session, & mut items, current_module. clone ( ) , parent_class, false , false , true , expr_string_literal. value . to_str ( ) , & None ) ,
733765 ExpectedType :: NESTED_FIELD ( maybe_field_type) => add_nested_field_names (
734766 session, & mut items, current_module. clone ( ) , expr_string_literal. value . to_str ( ) , parent_class, false , maybe_field_type) ,
735767 _ => unreachable ! ( )
736768 }
737769 } ,
738770 ExpectedType :: CLASS ( _) => { } ,
771+ ExpectedType :: INHERITS => { } ,
739772 }
740773 }
741774 Some ( CompletionResponse :: List ( CompletionList {
@@ -764,7 +797,7 @@ fn complete_attribut(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>, attr
764797 let parent_sym_types = Symbol :: follow_ref ( & parent_sym_eval, session, & mut None , false , false , None , & mut vec ! [ ] ) ;
765798 for parent_sym_type in parent_sym_types. iter ( ) {
766799 let Some ( parent_sym) = parent_sym_type. upgrade_weak ( ) else { continue } ;
767- 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 ( ) )
800+ 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 )
768801 }
769802 }
770803 }
@@ -997,17 +1030,24 @@ fn add_model_attributes(
9971030 is_super : bool ,
9981031 only_fields : bool ,
9991032 only_methods : bool ,
1000- attribute_name : & str
1033+ attribute_name : & str ,
1034+ specific_field_type : & Option < OYarn > ,
10011035) {
10021036 let all_symbols = Symbol :: all_members ( & parent_sym, session, true , only_fields, only_methods, from_module. clone ( ) , is_super) ;
10031037 for ( _symbol_name, symbols) in all_symbols {
10041038 //we could use symbol_name to remove duplicated names, but it would hide functions vs variables
1005- if _symbol_name. starts_with ( attribute_name) {
1006- if let Some ( ( final_sym, dep) ) = symbols. first ( ) {
1007- let context_of_symbol = HashMap :: from ( [ ( S ! ( "base_attr" ) , ContextValue :: SYMBOL ( Rc :: downgrade ( & parent_sym) ) ) ] ) ;
1008- items. push ( build_completion_item_from_symbol ( session, vec ! [ final_sym. clone( ) ] , context_of_symbol) ) ;
1039+ let Some ( ( final_sym, _dep) ) = symbols. first ( ) else {
1040+ continue ;
1041+ } ;
1042+ if let Some ( field_type) = specific_field_type {
1043+ if !final_sym. borrow ( ) . is_specific_field ( session, & [ field_type. as_str ( ) ] ) {
1044+ continue ;
10091045 }
10101046 }
1047+ if _symbol_name. starts_with ( attribute_name) {
1048+ let context_of_symbol = HashMap :: from ( [ ( S ! ( "base_attr" ) , ContextValue :: SYMBOL ( Rc :: downgrade ( & parent_sym) ) ) ] ) ;
1049+ items. push ( build_completion_item_from_symbol ( session, vec ! [ final_sym. clone( ) ] , context_of_symbol) ) ;
1050+ }
10111051 }
10121052}
10131053
0 commit comments