Skip to content

Commit 47e8476

Browse files
committed
Implement a ReturnVisitor
1 parent f328623 commit 47e8476

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

clippy_utils/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#![feature(rustc_private)]
1111
#![feature(assert_matches)]
1212
#![feature(unwrap_infallible)]
13+
#![feature(associated_type_defaults)]
1314
#![recursion_limit = "512"]
1415
#![allow(
1516
clippy::missing_errors_doc,
@@ -30,6 +31,7 @@
3031
// FIXME: switch to something more ergonomic here, once available.
3132
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
3233
extern crate rustc_ast;
34+
extern crate rustc_ast_ir;
3335
extern crate rustc_ast_pretty;
3436
extern crate rustc_attr;
3537
extern crate rustc_const_eval;
@@ -69,6 +71,7 @@ pub mod numeric_literal;
6971
pub mod paths;
7072
pub mod ptr;
7173
pub mod qualify_min_const_fn;
74+
mod returns;
7275
pub mod source;
7376
pub mod str_utils;
7477
pub mod sugg;
@@ -81,6 +84,7 @@ pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
8184
pub use self::hir_utils::{
8285
HirEqInterExpr, SpanlessEq, SpanlessHash, both, count_eq, eq_expr_value, hash_expr, hash_stmt, is_bool, over,
8386
};
87+
pub use returns::{ReturnVisitor, visit_returns};
8488

8589
use core::mem;
8690
use core::ops::ControlFlow;

clippy_utils/src/returns.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use std::ops::ControlFlow;
2+
3+
use rustc_ast::visit::VisitorResult;
4+
use rustc_ast_ir::try_visit;
5+
use rustc_hir::intravisit::{self, Visitor};
6+
use rustc_hir::{Block, Expr, ExprKind};
7+
8+
pub trait ReturnVisitor {
9+
type Result: VisitorResult = ();
10+
11+
fn visit_implicit_return(&mut self, expr: &Expr<'_>) -> Self::Result {
12+
self.visit_return(expr)
13+
}
14+
15+
fn visit_explicit_return(&mut self, expr: &Expr<'_>) -> Self::Result {
16+
self.visit_return(expr)
17+
}
18+
19+
/// In the example below, this function will be called with the `{ todo!(); }` block
20+
/// after the `;` due to the `NeverToAny` adjustment leading to the block returning `u8`
21+
/// with no expression directly attributable.
22+
/// ```no_run
23+
/// fn example() -> u8 {
24+
/// { todo!(); }
25+
/// }
26+
/// ```
27+
fn visit_diverging_implicit_return(&mut self, block: &Block<'_>) -> Self::Result;
28+
fn visit_return(&mut self, expr: &Expr<'_>) -> Self::Result;
29+
}
30+
31+
struct ExplicitReturnDriver<V>(V);
32+
33+
impl<V: ReturnVisitor> Visitor<'_> for ExplicitReturnDriver<V> {
34+
type Result = V::Result;
35+
type NestedFilter = intravisit::nested_filter::None;
36+
37+
fn visit_expr(&mut self, expr: &Expr<'_>) -> Self::Result {
38+
if let ExprKind::Ret(Some(ret_val_expr)) = expr.kind {
39+
self.0.visit_explicit_return(ret_val_expr)
40+
} else {
41+
intravisit::walk_expr(self, expr)
42+
}
43+
}
44+
}
45+
46+
fn visit_implicit_returns<V>(visitor: &mut V, expr: &Expr<'_>) -> V::Result
47+
where
48+
V: ReturnVisitor,
49+
{
50+
let cont = || V::Result::from_branch(ControlFlow::Continue(()));
51+
match expr.kind {
52+
ExprKind::Block(block, _) => {
53+
if let Some(expr) = block.expr {
54+
visit_implicit_returns(visitor, expr)
55+
} else {
56+
visitor.visit_diverging_implicit_return(block)
57+
}
58+
},
59+
ExprKind::If(_, true_block, else_block) => {
60+
try_visit!(visit_implicit_returns(visitor, true_block));
61+
visit_implicit_returns(visitor, else_block.unwrap())
62+
},
63+
ExprKind::Match(_, arms, _) => {
64+
for arm in arms {
65+
try_visit!(visit_implicit_returns(visitor, arm.body));
66+
}
67+
68+
cont()
69+
},
70+
71+
_ => visitor.visit_implicit_return(expr),
72+
}
73+
}
74+
75+
pub fn visit_returns<V>(visitor: V, expr: &Expr<'_>) -> V::Result
76+
where
77+
V: ReturnVisitor,
78+
{
79+
let mut explicit_driver = ExplicitReturnDriver(visitor);
80+
try_visit!(explicit_driver.visit_expr(expr));
81+
82+
visit_implicit_returns(&mut explicit_driver.0, expr)
83+
}

0 commit comments

Comments
 (0)