1- use emmylua_parser:: { LuaAstNode , LuaCallExpr , LuaClosureExpr } ;
1+ use emmylua_parser:: { LuaAstNode , LuaCallArgList , LuaCallExpr , LuaClosureExpr , LuaExpr } ;
22use rowan:: NodeOrToken ;
33
4- use crate :: { DiagnosticCode , LuaPropertyOwnerId , LuaSignatureId , SemanticModel } ;
4+ use crate :: { DiagnosticCode , LuaPropertyOwnerId , LuaSignatureId , LuaType , SemanticModel } ;
55
66use super :: DiagnosticContext ;
77
@@ -10,7 +10,8 @@ pub const CODES: &[DiagnosticCode] = &[DiagnosticCode::AwaitInSync];
1010pub fn check ( context : & mut DiagnosticContext , semantic_model : & SemanticModel ) -> Option < ( ) > {
1111 let root = semantic_model. get_root ( ) . clone ( ) ;
1212 for call_expr in root. descendants :: < LuaCallExpr > ( ) {
13- check_call_expr ( context, semantic_model, call_expr) ;
13+ check_call_expr ( context, semantic_model, call_expr. clone ( ) ) ;
14+ check_pcall_or_xpcall ( context, semantic_model, call_expr) ;
1415 }
1516
1617 Some ( ( ) )
@@ -21,9 +22,9 @@ fn check_call_expr(
2122 semantic_model : & SemanticModel ,
2223 call_expr : LuaCallExpr ,
2324) -> Option < ( ) > {
24- let prefix_node = call_expr. get_prefix_expr ( ) ?;
25+ let prefix_expr = call_expr. get_prefix_expr ( ) ?;
2526 let property_owner =
26- semantic_model. get_property_owner_id ( NodeOrToken :: Node ( prefix_node . syntax ( ) . clone ( ) ) ) ?;
27+ semantic_model. get_property_owner_id ( NodeOrToken :: Node ( prefix_expr . syntax ( ) . clone ( ) ) ) ?;
2728
2829 let property = semantic_model
2930 . get_db ( )
@@ -33,7 +34,7 @@ fn check_call_expr(
3334 if !check_call_is_in_async_function ( semantic_model, call_expr) . unwrap_or ( false ) {
3435 context. add_diagnostic (
3536 DiagnosticCode :: AwaitInSync ,
36- prefix_node . get_range ( ) ,
37+ prefix_expr . get_range ( ) ,
3738 "await in sync function" . to_string ( ) ,
3839 None ,
3940 ) ;
@@ -43,17 +44,90 @@ fn check_call_expr(
4344 Some ( ( ) )
4445}
4546
47+ fn check_pcall_or_xpcall (
48+ context : & mut DiagnosticContext ,
49+ semantic_model : & SemanticModel ,
50+ call_expr : LuaCallExpr ,
51+ ) -> Option < ( ) > {
52+ let prefix_expr = call_expr. get_prefix_expr ( ) ?;
53+ if let LuaExpr :: NameExpr ( name_expr) = prefix_expr {
54+ let name = name_expr. get_name_text ( ) ?;
55+ if name == "pcall" || name == "xpcall" {
56+ let arg_list = call_expr. get_args_list ( ) ?;
57+ let first_arg = arg_list. get_args ( ) . next ( ) ?;
58+ let range = first_arg. get_range ( ) ;
59+ let arg_type = semantic_model. infer_expr ( first_arg) ?;
60+ let is_async = match & arg_type {
61+ LuaType :: DocFunction ( f) => f. is_async ( ) ,
62+ LuaType :: Signature ( sig) => {
63+ let property_owner = LuaPropertyOwnerId :: Signature ( * sig) ;
64+
65+ let property = semantic_model
66+ . get_db ( )
67+ . get_property_index ( )
68+ . get_property ( property_owner) ?;
69+ property. is_async
70+ }
71+ _ => return None ,
72+ } ;
73+
74+ if is_async {
75+ if !check_call_is_in_async_function ( semantic_model, call_expr) . unwrap_or ( false ) {
76+ context. add_diagnostic (
77+ DiagnosticCode :: AwaitInSync ,
78+ range,
79+ "await in sync function" . to_string ( ) ,
80+ None ,
81+ ) ;
82+ }
83+ }
84+ }
85+ }
86+
87+ Some ( ( ) )
88+ }
89+
4690fn check_call_is_in_async_function (
4791 semantic_model : & SemanticModel ,
4892 call_expr : LuaCallExpr ,
4993) -> Option < bool > {
5094 let file_id = semantic_model. get_file_id ( ) ;
51- let closure = call_expr. ancestors :: < LuaClosureExpr > ( ) . next ( ) ?;
52- let signature_id = LuaSignatureId :: from_closure ( file_id, & closure) ;
53- let property_owner = LuaPropertyOwnerId :: Signature ( signature_id) ;
54- let property = semantic_model
55- . get_db ( )
56- . get_property_index ( )
57- . get_property ( property_owner) ?;
58- Some ( property. is_async )
95+ let closures = call_expr. ancestors :: < LuaClosureExpr > ( ) ;
96+ for closure in closures {
97+ let signature_id = LuaSignatureId :: from_closure ( file_id, & closure) ;
98+ let property_owner = LuaPropertyOwnerId :: Signature ( signature_id) ;
99+ let is_async = match semantic_model
100+ . get_db ( )
101+ . get_property_index ( )
102+ . get_property ( property_owner)
103+ {
104+ Some ( p) => p. is_async ,
105+ None => false ,
106+ } ;
107+ if is_async {
108+ return Some ( true ) ;
109+ }
110+
111+ if !is_in_pcall_or_xpcall ( closure) . unwrap_or ( false ) {
112+ break ;
113+ }
114+ }
115+
116+ Some ( false )
117+ }
118+
119+ // special case
120+ fn is_in_pcall_or_xpcall ( closure : LuaClosureExpr ) -> Option < bool > {
121+ let call_expr = closure
122+ . get_parent :: < LuaCallArgList > ( ) ?
123+ . get_parent :: < LuaCallExpr > ( ) ?;
124+ let prefix_expr = call_expr. get_prefix_expr ( ) ?;
125+ if let LuaExpr :: NameExpr ( name_expr) = prefix_expr {
126+ let name = name_expr. get_name_text ( ) ?;
127+ if name == "pcall" || name == "xpcall" {
128+ return Some ( true ) ;
129+ }
130+ }
131+
132+ Some ( false )
59133}
0 commit comments