@@ -23,7 +23,7 @@ use super::features_utils::TypeInfo;
23
23
24
24
25
25
#[ allow( non_camel_case_types) ]
26
- #[ derive( Debug ) ]
26
+ #[ derive( Debug , Clone ) ]
27
27
pub enum ExpectedType {
28
28
MODEL_NAME ,
29
29
DOMAIN ( Rc < RefCell < Symbol > > ) ,
@@ -32,9 +32,10 @@ pub enum ExpectedType {
32
32
DOMAIN_FIELD ( Rc < RefCell < Symbol > > ) ,
33
33
DOMAIN_COMPARATOR ,
34
34
CLASS ( Rc < RefCell < Symbol > > ) ,
35
- SIMPLE_FIELD ,
35
+ SIMPLE_FIELD ( Option < OYarn > ) ,
36
36
NESTED_FIELD ( Option < OYarn > ) ,
37
37
METHOD_NAME ,
38
+ INHERITS ,
38
39
}
39
40
40
41
pub struct CompletionFeature ;
@@ -159,8 +160,10 @@ fn complete_assign_stmt(session: &mut SessionInfo<'_>, file: &Rc<RefCell<Symbol>
159
160
let mut expected_type = vec ! [ ] ;
160
161
if stmt_assign. targets . len ( ) == 1 {
161
162
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
+ _ => { }
164
167
}
165
168
}
166
169
}
@@ -376,7 +379,7 @@ fn complete_expr(expr: &Expr, session: &mut SessionInfo, file: &Rc<RefCell<Symbo
376
379
Expr :: Lambda ( expr_lambda) => compare_lambda ( session, file, expr_lambda, offset, is_param, expected_type) ,
377
380
Expr :: If ( expr_if) => complete_if_expr ( session, file, expr_if, offset, is_param, expected_type) ,
378
381
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 ) ,
380
383
Expr :: ListComp ( _) => None ,
381
384
Expr :: SetComp ( _) => None ,
382
385
Expr :: DictComp ( _) => None ,
@@ -460,15 +463,44 @@ fn complete_if_expr(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>, expr_
460
463
461
464
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 > {
462
465
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
+ }
464
476
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) ;
466
484
}
467
485
}
468
486
}
469
487
None
470
488
}
471
489
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
+
472
504
fn complete_yield ( session : & mut SessionInfo , file : & Rc < RefCell < Symbol > > , expr_yield : & ExprYield , offset : usize , is_param : bool , expected_type : & Vec < ExpectedType > ) -> Option < CompletionResponse > {
473
505
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 ( ) {
474
506
return complete_expr ( expr_yield. value . as_ref ( ) . unwrap ( ) , session, file, offset, is_param, expected_type) ;
@@ -522,7 +554,7 @@ fn complete_decorator_call(
522
554
let expected_types = if ( version_comparison < Ordering :: Equal && dec_sym_tree. 0 . ends_with ( & [ Sy ! ( "odoo" ) , Sy ! ( "api" ) ] ) ) ||
523
555
( version_comparison >= Ordering :: Equal && dec_sym_tree. 0 . ends_with ( & [ Sy ! ( "odoo" ) , Sy ! ( "orm" ) , Sy ! ( "decorators" ) ] ) ) {
524
556
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 ) ]
526
558
} else if dec_sym_tree. 1 == vec ! [ Sy !( "depends" ) ] && SyncOdoo :: is_in_main_entry ( session, & dec_sym_tree. 0 ) {
527
559
& vec ! [ ExpectedType :: NESTED_FIELD ( None ) ]
528
560
} else {
@@ -717,7 +749,7 @@ fn complete_string_literal(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>
717
749
ExpectedType :: DOMAIN_FIELD ( parent) => {
718
750
add_nested_field_names ( session, & mut items, current_module. clone ( ) , expr_string_literal. value . to_str ( ) , parent. clone ( ) , true , & None ) ;
719
751
} ,
720
- ExpectedType :: SIMPLE_FIELD | ExpectedType :: NESTED_FIELD ( _) | ExpectedType :: METHOD_NAME => ' field_block: {
752
+ ExpectedType :: SIMPLE_FIELD ( _ ) | ExpectedType :: NESTED_FIELD ( _) | ExpectedType :: METHOD_NAME => ' field_block: {
721
753
let scope = Symbol :: get_scope_symbol ( file. clone ( ) , expr_string_literal. range ( ) . start ( ) . to_u32 ( ) , true ) ;
722
754
let Some ( parent_class) = scope. borrow ( ) . get_in_parents ( & vec ! [ SymType :: CLASS ] , true ) . and_then ( |p| p. upgrade ( ) ) else {
723
755
break ' field_block;
@@ -726,16 +758,17 @@ fn complete_string_literal(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>
726
758
break ' field_block;
727
759
}
728
760
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 ) ,
731
763
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 ) ,
733
765
ExpectedType :: NESTED_FIELD ( maybe_field_type) => add_nested_field_names (
734
766
session, & mut items, current_module. clone ( ) , expr_string_literal. value . to_str ( ) , parent_class, false , maybe_field_type) ,
735
767
_ => unreachable ! ( )
736
768
}
737
769
} ,
738
770
ExpectedType :: CLASS ( _) => { } ,
771
+ ExpectedType :: INHERITS => { } ,
739
772
}
740
773
}
741
774
Some ( CompletionResponse :: List ( CompletionList {
@@ -764,7 +797,7 @@ fn complete_attribut(session: &mut SessionInfo, file: &Rc<RefCell<Symbol>>, attr
764
797
let parent_sym_types = Symbol :: follow_ref ( & parent_sym_eval, session, & mut None , false , false , None , & mut vec ! [ ] ) ;
765
798
for parent_sym_type in parent_sym_types. iter ( ) {
766
799
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 )
768
801
}
769
802
}
770
803
}
@@ -997,17 +1030,24 @@ fn add_model_attributes(
997
1030
is_super : bool ,
998
1031
only_fields : bool ,
999
1032
only_methods : bool ,
1000
- attribute_name : & str
1033
+ attribute_name : & str ,
1034
+ specific_field_type : & Option < OYarn > ,
1001
1035
) {
1002
1036
let all_symbols = Symbol :: all_members ( & parent_sym, session, true , only_fields, only_methods, from_module. clone ( ) , is_super) ;
1003
1037
for ( _symbol_name, symbols) in all_symbols {
1004
1038
//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 ;
1009
1045
}
1010
1046
}
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
+ }
1011
1051
}
1012
1052
}
1013
1053
0 commit comments