Skip to content

Commit

Permalink
Auto merge of rust-lang#17542 - roife:fix-issue-17517, r=Veykril
Browse files Browse the repository at this point in the history
feat: go-to-def and find-references on control-flow keywords

fix rust-lang#17517.

This PR implements **go-to-definition** and **find-references** functionalities for control flow keywords, which is similar to the behaviors in the `highlight-related` module. Besides, this PR also fixes some incorrect behaviors in `highlight-related`.

## Changes

1. **Support for go-to-definition on control flow keywords**:
   This PR introduces functionality allowing users to navigate on the definition of control flow keywords (`return`, `break`, `continue`).
   Commit: 2a3244ee147f898dd828c06352645ae1713c260f..7391e7a608634709db002a4cb09229de4d12c056.

2. **Bug fixes and refactoring in highlight-related**:
   - **Handling return/break/continue within try_blocks**:
     This PR adjusted the behavior of these keywords when they occur within `try_blocks`. When encounter these keywords, the program should exit the outer function or loop which containing the `try_blocks`, rather than the `try_blocks` itself; while the `?` will cause the program to exit `try_blocks`.
     Commit: 59d697e807f0197f59814b37dca1563959da4aa1.
   - **Support highlighting keywords in macro expansion for highlight-related**:
     Commit: 88df24f01727c23a667a763ee3ee0cec22d5ad52.
   - Detailed description for the bug fixes
     + The previous implementation of `preorder_expr` incorrectly treated `try_blocks` as new contexts, thereby r-a will not continue to traverse inner `return` and `break/continue` statements. To resolve this, a new function `preorder_expr_with_ctx_checker` has been added, allowing users to specify which expressions to skip.
       * For example, when searching for the `?` in the context, r-a should skip `try_blocks` where the `?` insides just works for `try_blocks`. But when search for the `return` keyword, r-a should collect both the `return` keywords inside and outside the `try_blocks`
     + Thus, this PR added `WalkExpandedExprCtx` (builder pattern). It offers the following improvements: customizable context skipping, maintenance of loop depth (for `break`/`continue`), and handling macro expansion during traversal.

3. **Support for find-references on control flow keywords**:
   This PR enables users to find all references to control flow keywords.
   Commit: 9202a33f81218fb9c2edb5d42e6b4de85b0323a8.
  • Loading branch information
bors committed Jul 22, 2024
2 parents 692a42e + 687a15f commit 64cb0bf
Show file tree
Hide file tree
Showing 5 changed files with 1,209 additions and 194 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,35 @@ pub fn walk_expr(expr: &ast::Expr, cb: &mut dyn FnMut(ast::Expr)) {
})
}

pub fn is_closure_or_blk_with_modif(expr: &ast::Expr) -> bool {
match expr {
ast::Expr::BlockExpr(block_expr) => {
matches!(
block_expr.modifier(),
Some(
ast::BlockModifier::Async(_)
| ast::BlockModifier::Try(_)
| ast::BlockModifier::Const(_)
)
)
}
ast::Expr::ClosureExpr(_) => true,
_ => false,
}
}

/// Preorder walk all the expression's child expressions preserving events.
/// If the callback returns true on an [`WalkEvent::Enter`], the subtree of the expression will be skipped.
/// Note that the subtree may already be skipped due to the context analysis this function does.
pub fn preorder_expr(start: &ast::Expr, cb: &mut dyn FnMut(WalkEvent<ast::Expr>) -> bool) {
preorder_expr_with_ctx_checker(start, &is_closure_or_blk_with_modif, cb);
}

pub fn preorder_expr_with_ctx_checker(
start: &ast::Expr,
check_ctx: &dyn Fn(&ast::Expr) -> bool,
cb: &mut dyn FnMut(WalkEvent<ast::Expr>) -> bool,
) {
let mut preorder = start.syntax().preorder();
while let Some(event) = preorder.next() {
let node = match event {
Expand Down Expand Up @@ -71,20 +96,7 @@ pub fn preorder_expr(start: &ast::Expr, cb: &mut dyn FnMut(WalkEvent<ast::Expr>)
if ast::GenericArg::can_cast(node.kind()) {
preorder.skip_subtree();
} else if let Some(expr) = ast::Expr::cast(node) {
let is_different_context = match &expr {
ast::Expr::BlockExpr(block_expr) => {
matches!(
block_expr.modifier(),
Some(
ast::BlockModifier::Async(_)
| ast::BlockModifier::Try(_)
| ast::BlockModifier::Const(_)
)
)
}
ast::Expr::ClosureExpr(_) => true,
_ => false,
} && expr.syntax() != start.syntax();
let is_different_context = check_ctx(&expr) && expr.syntax() != start.syntax();
let skip = cb(WalkEvent::Enter(expr));
if skip || is_different_context {
preorder.skip_subtree();
Expand Down Expand Up @@ -394,7 +406,7 @@ fn for_each_break_expr(
}
}

fn eq_label_lt(lt1: &Option<ast::Lifetime>, lt2: &Option<ast::Lifetime>) -> bool {
pub fn eq_label_lt(lt1: &Option<ast::Lifetime>, lt2: &Option<ast::Lifetime>) -> bool {
lt1.as_ref().zip(lt2.as_ref()).map_or(false, |(lt, lbl)| lt.text() == lbl.text())
}

Expand Down
Loading

0 comments on commit 64cb0bf

Please sign in to comment.