Process a `try-catch-finally` statement.
(try_stmt: &'b Try<'b>, scope: &mut ScopeState, ctx: &ForwardWalkCtx<'_>)
| 7194 | |
| 7195 | /// Process a `try-catch-finally` statement. |
| 7196 | fn process_try<'b>(try_stmt: &'b Try<'b>, scope: &mut ScopeState, ctx: &ForwardWalkCtx<'_>) { |
| 7197 | let pre_try_scope = scope.clone(); |
| 7198 | |
| 7199 | // Check if cursor is inside the try body. |
| 7200 | let try_body_span = try_stmt.block.span(); |
| 7201 | let cursor_in_try = ctx.cursor_offset >= try_body_span.start.offset |
| 7202 | && ctx.cursor_offset <= try_body_span.end.offset; |
| 7203 | |
| 7204 | if cursor_in_try { |
| 7205 | // Walk only the try body. |
| 7206 | walk_body_forward(try_stmt.block.statements.iter(), scope, ctx); |
| 7207 | return; |
| 7208 | } |
| 7209 | |
| 7210 | // Check if cursor is inside a catch block. |
| 7211 | for catch in try_stmt.catch_clauses.iter() { |
| 7212 | let catch_span = catch.block.span(); |
| 7213 | if ctx.cursor_offset >= catch_span.start.offset |
| 7214 | && ctx.cursor_offset <= catch_span.end.offset |
| 7215 | { |
| 7216 | // Bind the caught exception variable. |
| 7217 | if let Some(ref var) = catch.variable { |
| 7218 | let var_name = var.name.to_string(); |
| 7219 | let parsed_hint = extract_hint_type(&catch.hint); |
| 7220 | let resolved = crate::completion::type_resolution::type_hint_to_classes_typed( |
| 7221 | &parsed_hint, |
| 7222 | &ctx.current_class.name, |
| 7223 | ctx.all_classes, |
| 7224 | ctx.class_loader, |
| 7225 | ); |
| 7226 | let exception_types = ResolvedType::from_classes_with_hint(resolved, parsed_hint); |
| 7227 | // Merge pre-try scope (since the exception could have |
| 7228 | // been thrown at any point in the try body) with the |
| 7229 | // catch variable. |
| 7230 | *scope = pre_try_scope.clone(); |
| 7231 | if !exception_types.is_empty() { |
| 7232 | scope.set(&var_name, exception_types); |
| 7233 | } |
| 7234 | } else { |
| 7235 | *scope = pre_try_scope.clone(); |
| 7236 | } |
| 7237 | walk_body_forward(catch.block.statements.iter(), scope, ctx); |
| 7238 | return; |
| 7239 | } |
| 7240 | } |
| 7241 | |
| 7242 | // Check if cursor is inside the finally block. |
| 7243 | if let Some(ref finally) = try_stmt.finally_clause { |
| 7244 | let finally_span = finally.block.span(); |
| 7245 | if ctx.cursor_offset >= finally_span.start.offset |
| 7246 | && ctx.cursor_offset <= finally_span.end.offset |
| 7247 | { |
| 7248 | // In finally, merge all possible paths. |
| 7249 | walk_body_forward(try_stmt.block.statements.iter(), scope, ctx); |
| 7250 | walk_body_forward(finally.block.statements.iter(), scope, ctx); |
| 7251 | return; |
| 7252 | } |
| 7253 | } |
no test coverage detected