@@ -98,8 +98,11 @@ impl PythonArchEval {
9898 } ;
9999 self . visit_sub_stmts ( session, & ast) ;
100100 if !self . file_mode {
101- self . handle_func_decorators ( session, maybe_func_stmt, self . sym_stack [ 0 ] . clone ( ) ) ;
102- PythonArchEval :: handle_function_returns ( session, maybe_func_stmt, & self . sym_stack [ 0 ] , & ast. last ( ) . unwrap ( ) . range ( ) . end ( ) , & mut self . diagnostics ) ;
101+ let func_stmt = maybe_func_stmt. unwrap ( ) ;
102+ self . diagnostics . extend (
103+ PythonArchEvalHooks :: handle_func_decorators ( session, func_stmt, self . sym_stack [ 0 ] . clone ( ) , self . file . clone ( ) , self . current_step )
104+ ) ;
105+ PythonArchEval :: handle_function_returns ( session, func_stmt, & self . sym_stack [ 0 ] , & ast. last ( ) . unwrap ( ) . range ( ) . end ( ) , & mut self . diagnostics ) ;
103106 PythonArchEval :: handle_func_evaluations ( ast, & self . sym_stack [ 0 ] ) ;
104107 }
105108 session. current_noqa = old_noqa;
@@ -766,7 +769,7 @@ impl PythonArchEval {
766769 self . visit_sub_stmts ( session, & func_stmt. body ) ;
767770 self . sym_stack . pop ( ) ;
768771 session. current_noqa = old_noqa;
769- PythonArchEval :: handle_function_returns ( session, Some ( func_stmt) , & function_sym, & func_stmt. range . end ( ) , & mut self . diagnostics ) ;
772+ PythonArchEval :: handle_function_returns ( session, func_stmt, & function_sym, & func_stmt. range . end ( ) , & mut self . diagnostics ) ;
770773 PythonArchEval :: handle_func_evaluations ( & func_stmt. body , & function_sym) ;
771774 function_sym. borrow_mut ( ) . as_func_mut ( ) . arch_eval_status = BuildStatus :: DONE ;
772775 }
@@ -934,12 +937,12 @@ impl PythonArchEval {
934937 // Evaluate return annotation and add it to function evaluations
935938 fn handle_function_returns (
936939 session : & mut SessionInfo ,
937- func_stmt : Option < & StmtFunctionDef > ,
940+ func_stmt : & StmtFunctionDef ,
938941 func_sym : & Rc < RefCell < Symbol > > ,
939942 max_infer : & TextSize ,
940943 diagnostics : & mut Vec < Diagnostic > ,
941944 ) {
942- if let Some ( returns_ann) = func_stmt. and_then ( |func_stmt| func_stmt . returns . as_ref ( ) ) {
945+ if let Some ( returns_ann) = func_stmt. returns . as_ref ( ) {
943946 let file_sym = func_sym. borrow ( ) . get_file ( ) . and_then ( |file_weak| file_weak. upgrade ( ) ) ;
944947 let mut deps = vec ! [ vec![ ] , vec![ ] ] ;
945948 let ( evaluations, diags) = Evaluation :: eval_from_ast (
@@ -971,7 +974,7 @@ impl PythonArchEval {
971974
972975 // Handle function evaluation if traversing the body did not get any evaluations
973976 // First we check if it is a function signature with no body ( like in stubs ) like def func():...
974- // If so we give it an Any evaluation because it is undetermined, otherwise we give it None, becauset that means
977+ // If so we give it an Any evaluation because it is undetermined, otherwise we give it None, because that means
975978 // we have a body but no return statement, which defaults to return None at the end
976979 fn handle_func_evaluations (
977980 func_body : & Vec < Stmt > ,
@@ -992,72 +995,6 @@ impl PythonArchEval {
992995 }
993996 }
994997
995- fn handle_api_returns_decorator ( & mut self , session : & mut SessionInfo , func_sym : Rc < RefCell < Symbol > > , arguments : & Arguments ) {
996- let Some ( Expr :: StringLiteral ( expr) ) = arguments. args . first ( ) else { return } ;
997- let returns_str = expr. value . to_string ( ) ;
998- if returns_str == S ! ( "self" ) {
999- func_sym. borrow_mut ( ) . set_evaluations ( vec ! [ Evaluation :: new_self( ) ] ) ;
1000- return ;
1001- }
1002- let Some ( model) = session. sync_odoo . models . get ( & oyarn ! ( "{}" , returns_str) ) . cloned ( ) else {
1003- add_diagnostic ( & mut self . diagnostics , Diagnostic :: new (
1004- FileMgr :: textRange_to_temporary_Range ( & expr. range ( ) ) ,
1005- Some ( DiagnosticSeverity :: ERROR ) ,
1006- Some ( NumberOrString :: String ( S ! ( "OLS30102" ) ) ) ,
1007- Some ( EXTENSION_NAME . to_string ( ) ) ,
1008- S ! ( "Unknown model. Check your addons path" ) ,
1009- None ,
1010- None ,
1011- ) , & session. current_noqa ) ;
1012- return ;
1013- } ;
1014- let Some ( ref main_model_sym) = model. borrow ( ) . get_main_symbols ( session, func_sym. borrow ( ) . find_module ( ) ) . first ( ) . cloned ( ) else {
1015- add_diagnostic ( & mut self . diagnostics , Diagnostic :: new (
1016- FileMgr :: textRange_to_temporary_Range ( & expr. range ( ) ) ,
1017- Some ( DiagnosticSeverity :: ERROR ) ,
1018- Some ( NumberOrString :: String ( S ! ( "OLS30101" ) ) ) ,
1019- Some ( EXTENSION_NAME . to_string ( ) ) ,
1020- S ! ( "This model is not in the dependencies of your module." ) ,
1021- None ,
1022- None ,
1023- ) , & session. current_noqa ) ;
1024- return
1025- } ;
1026- func_sym. borrow_mut ( ) . set_evaluations ( vec ! [ Evaluation :: eval_from_symbol( & Rc :: downgrade( main_model_sym) , Some ( false ) ) ] ) ;
1027- }
1028-
1029- /// For @api.constrains and @api.onchange, both can only take a simple field name
1030- fn handle_api_simple_field_decorator ( & mut self , session : & mut SessionInfo , func_sym : Rc < RefCell < Symbol > > , arguments : & Arguments ) {
1031- let from_module = func_sym. borrow ( ) . find_module ( ) ;
1032-
1033- let Some ( class_sym) = func_sym. borrow ( ) . get_in_parents ( & vec ! [ SymType :: CLASS ] , true ) . and_then (
1034- |class_sym_weak| class_sym_weak. upgrade ( )
1035- ) else {
1036- return ;
1037- } ;
1038-
1039- let Some ( model_name) = class_sym. borrow ( ) . as_class_sym ( ) . _model . as_ref ( ) . map ( |model| & model. name ) . cloned ( ) else {
1040- return ;
1041- } ;
1042-
1043- for arg in arguments. args . iter ( ) {
1044- let Expr :: StringLiteral ( expr) = arg else { return } ;
1045- let field_name = expr. value . to_string ( ) ;
1046- let ( syms, _) = class_sym. borrow ( ) . get_member_symbol ( session, & field_name, from_module. clone ( ) , false , false , true , false ) ;
1047- if syms. is_empty ( ) {
1048- add_diagnostic ( & mut self . diagnostics , Diagnostic :: new (
1049- FileMgr :: textRange_to_temporary_Range ( & expr. range ( ) ) ,
1050- Some ( DiagnosticSeverity :: ERROR ) ,
1051- Some ( NumberOrString :: String ( S ! ( "OLS30323" ) ) ) ,
1052- Some ( EXTENSION_NAME . to_string ( ) ) ,
1053- format ! ( "Field {field_name} does not exist on model {model_name}" ) ,
1054- None ,
1055- None ,
1056- ) , & session. current_noqa ) ;
1057- }
1058- }
1059- }
1060-
1061998 pub fn get_nested_sub_field (
1062999 session : & mut SessionInfo ,
10631000 field_name : & String ,
@@ -1098,82 +1035,4 @@ impl PythonArchEval {
10981035 }
10991036 syms
11001037 }
1101-
1102- /// For @api.depends, which can take a nested simple field name
1103- fn handle_api_nested_field_decorator ( & mut self , session : & mut SessionInfo , func_sym : Rc < RefCell < Symbol > > , arguments : & Arguments ) {
1104- let from_module = func_sym. borrow ( ) . find_module ( ) ;
1105-
1106- let Some ( class_sym) = func_sym. borrow ( ) . get_in_parents ( & vec ! [ SymType :: CLASS ] , true ) . and_then (
1107- |class_sym_weak| class_sym_weak. upgrade ( )
1108- ) else {
1109- return ;
1110- } ;
1111-
1112- let Some ( model_name) = class_sym. borrow ( ) . as_class_sym ( ) . _model . as_ref ( ) . map ( |model| & model. name ) . cloned ( ) else {
1113- return ;
1114- } ;
1115-
1116- for arg in arguments. args . iter ( ) {
1117- let Expr :: StringLiteral ( expr) = arg else { return } ;
1118- let field_name = expr. value . to_string ( ) ;
1119- let syms = PythonArchEval :: get_nested_sub_field ( session, & field_name, class_sym. clone ( ) , from_module. clone ( ) ) ;
1120- if syms. is_empty ( ) {
1121- add_diagnostic ( & mut self . diagnostics , Diagnostic :: new (
1122- FileMgr :: textRange_to_temporary_Range ( & expr. range ( ) ) ,
1123- Some ( DiagnosticSeverity :: ERROR ) ,
1124- Some ( NumberOrString :: String ( S ! ( "OLS30323" ) ) ) ,
1125- Some ( EXTENSION_NAME . to_string ( ) ) ,
1126- format ! ( "Field {field_name} does not exist on model {model_name}" ) ,
1127- None ,
1128- None ,
1129- ) , & session. current_noqa ) ;
1130- }
1131- }
1132- }
1133-
1134- /// Read function decorators and set evaluations where applicable
1135- /// - api.returns -> self -> Self, string -> model name if exists + validate
1136- /// - validates api.depends/onchange/constrains
1137- fn handle_func_decorators (
1138- & mut self ,
1139- session : & mut SessionInfo ,
1140- maybe_func_stmt : Option < & StmtFunctionDef > ,
1141- func_sym : Rc < RefCell < Symbol > > ,
1142- ) {
1143- let Some ( func_stmt) = maybe_func_stmt else { return } ;
1144- for decorator in func_stmt. decorator_list . iter ( ) {
1145- let ( decorator_base, decorator_args) = match & decorator. expression {
1146- Expr :: Call ( call_expr) => {
1147- ( & call_expr. func , & call_expr. arguments )
1148- } ,
1149- _ => { continue ; }
1150- } ;
1151- if decorator_args. args . is_empty ( ) {
1152- continue ; // All the decorators we handle have at least one arg for now
1153- }
1154- let mut deps = vec ! [ vec![ ] , vec![ ] ] ;
1155- if !self . file_mode {
1156- deps. push ( vec ! [ ] ) ;
1157- }
1158- let ( dec_evals, diags) = Evaluation :: eval_from_ast ( session, & decorator_base, self . sym_stack . last ( ) . unwrap ( ) . clone ( ) , & func_stmt. range . start ( ) , & mut deps) ;
1159- Symbol :: insert_dependencies ( & self . file , & mut deps, self . current_step ) ;
1160- self . diagnostics . extend ( diags) ;
1161- for decorator_eval in dec_evals. iter ( ) {
1162- let EvaluationSymbolPtr :: WEAK ( decorator_eval_sym_weak) = decorator_eval. symbol . get_symbol ( session, & mut None , & mut self . diagnostics , None ) else { continue } ;
1163- let Some ( dec_sym) = decorator_eval_sym_weak. weak . upgrade ( ) else { continue } ;
1164- let dec_sym_tree = dec_sym. borrow ( ) . get_tree ( ) ;
1165- if !dec_sym_tree. 0 . ends_with ( & [ Sy ! ( "odoo" ) , Sy ! ( "api" ) ] ) {
1166- continue ;
1167- }
1168- if dec_sym_tree. 1 == vec ! [ Sy !( "returns" ) ] && SyncOdoo :: is_in_main_entry ( session, & dec_sym_tree. 0 ) {
1169- self . handle_api_returns_decorator ( session, func_sym. clone ( ) , decorator_args) ;
1170- } else if [ vec ! [ Sy !( "onchange" ) ] , vec ! [ Sy !( "constrains" ) ] ] . contains ( & dec_sym_tree. 1 ) && SyncOdoo :: is_in_main_entry ( session, & dec_sym_tree. 0 ) {
1171- self . handle_api_simple_field_decorator ( session, func_sym. clone ( ) , decorator_args) ;
1172- } else if dec_sym_tree. 1 == vec ! [ Sy !( "depends" ) ] && SyncOdoo :: is_in_main_entry ( session, & dec_sym_tree. 0 ) {
1173- self . handle_api_nested_field_decorator ( session, func_sym. clone ( ) , decorator_args) ;
1174- }
1175- }
1176- }
1177- }
1178-
11791038}
0 commit comments