|  | 
| 1 | 1 | use clippy_utils::diagnostics::span_lint_and_sugg; | 
| 2 |  | -use clippy_utils::path_res; | 
|  | 2 | +use clippy_utils::{ReturnType, ReturnVisitor, path_res, visit_returns}; | 
| 3 | 3 | use rustc_ast::ast::LitKind; | 
| 4 | 4 | use rustc_errors::Applicability; | 
| 5 | 5 | use rustc_hir::def::Res; | 
| 6 |  | -use rustc_hir::intravisit::{FnKind, Visitor}; | 
| 7 |  | -use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnRetTy, Lit, MutTy, Mutability, PrimTy, Ty, TyKind, intravisit}; | 
|  | 6 | +use rustc_hir::intravisit::FnKind; | 
|  | 7 | +use rustc_hir::{Body, ExprKind, FnDecl, FnRetTy, Lit, MutTy, Mutability, PrimTy, Ty, TyKind}; | 
| 8 | 8 | use rustc_lint::{LateContext, LateLintPass}; | 
| 9 | 9 | use rustc_session::declare_lint_pass; | 
| 10 | 10 | use rustc_span::Span; | 
| @@ -67,49 +67,36 @@ fn extract_anonymous_ref<'tcx>(hir_ty: &Ty<'tcx>) -> Option<&'tcx Ty<'tcx>> { | 
| 67 | 67 |     Some(ty) | 
| 68 | 68 | } | 
| 69 | 69 | 
 | 
| 70 |  | -fn is_str_literal(expr: &Expr<'_>) -> bool { | 
| 71 |  | -    matches!( | 
| 72 |  | -        expr.kind, | 
| 73 |  | -        ExprKind::Lit(Lit { | 
| 74 |  | -            node: LitKind::Str(..), | 
| 75 |  | -            .. | 
| 76 |  | -        }), | 
| 77 |  | -    ) | 
| 78 |  | -} | 
| 79 |  | - | 
| 80 |  | -struct FindNonLiteralReturn; | 
|  | 70 | +struct LiteralReturnVisitor; | 
| 81 | 71 | 
 | 
| 82 |  | -impl<'hir> Visitor<'hir> for FindNonLiteralReturn { | 
|  | 72 | +impl ReturnVisitor for LiteralReturnVisitor { | 
| 83 | 73 |     type Result = std::ops::ControlFlow<()>; | 
| 84 |  | -    type NestedFilter = intravisit::nested_filter::None; | 
|  | 74 | +    fn visit_return(&mut self, kind: ReturnType<'_>) -> Self::Result { | 
|  | 75 | +        let expr = match kind { | 
|  | 76 | +            ReturnType::Implicit(e) | ReturnType::Explicit(e) => e, | 
|  | 77 | +            ReturnType::UnitReturnExplicit(_) | ReturnType::MissingElseImplicit(_) => { | 
|  | 78 | +                panic!("Function which returns `&str` has a unit return!") | 
|  | 79 | +            }, | 
|  | 80 | +            ReturnType::DivergingImplicit(_) => { | 
|  | 81 | +                // If this block is implicitly returning `!`, it can return `&'static str`. | 
|  | 82 | +                return Self::Result::Continue(()); | 
|  | 83 | +            }, | 
|  | 84 | +        }; | 
| 85 | 85 | 
 | 
| 86 |  | -    fn visit_expr(&mut self, expr: &'hir Expr<'hir>) -> Self::Result { | 
| 87 |  | -        if let ExprKind::Ret(Some(ret_val_expr)) = expr.kind | 
| 88 |  | -            && !is_str_literal(ret_val_expr) | 
| 89 |  | -        { | 
| 90 |  | -            Self::Result::Break(()) | 
|  | 86 | +        if matches!( | 
|  | 87 | +            expr.kind, | 
|  | 88 | +            ExprKind::Lit(Lit { | 
|  | 89 | +                node: LitKind::Str(..), | 
|  | 90 | +                .. | 
|  | 91 | +            }) | 
|  | 92 | +        ) { | 
|  | 93 | +            Self::Result::Continue(()) | 
| 91 | 94 |         } else { | 
| 92 |  | -            intravisit::walk_expr(self, expr) | 
|  | 95 | +            Self::Result::Break(()) | 
| 93 | 96 |         } | 
| 94 | 97 |     } | 
| 95 | 98 | } | 
| 96 | 99 | 
 | 
| 97 |  | -fn check_implicit_returns_static_str(body: &Body<'_>) -> bool { | 
| 98 |  | -    // TODO: Improve this to the same complexity as the Visitor to catch more implicit return cases. | 
| 99 |  | -    if let ExprKind::Block(block, _) = body.value.kind | 
| 100 |  | -        && let Some(implicit_ret) = block.expr | 
| 101 |  | -    { | 
| 102 |  | -        return is_str_literal(implicit_ret); | 
| 103 |  | -    } | 
| 104 |  | - | 
| 105 |  | -    false | 
| 106 |  | -} | 
| 107 |  | - | 
| 108 |  | -fn check_explicit_returns_static_str(expr: &Expr<'_>) -> bool { | 
| 109 |  | -    let mut visitor = FindNonLiteralReturn; | 
| 110 |  | -    visitor.visit_expr(expr).is_continue() | 
| 111 |  | -} | 
| 112 |  | - | 
| 113 | 100 | impl<'tcx> LateLintPass<'tcx> for UnnecessaryLiteralBound { | 
| 114 | 101 |     fn check_fn( | 
| 115 | 102 |         &mut self, | 
| @@ -143,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryLiteralBound { | 
| 143 | 130 |         } | 
| 144 | 131 | 
 | 
| 145 | 132 |         // Check for all return statements returning literals | 
| 146 |  | -        if check_explicit_returns_static_str(body.value) && check_implicit_returns_static_str(body) { | 
|  | 133 | +        if visit_returns(LiteralReturnVisitor, body.value).is_continue() { | 
| 147 | 134 |             span_lint_and_sugg( | 
| 148 | 135 |                 cx, | 
| 149 | 136 |                 UNNECESSARY_LITERAL_BOUND, | 
|  | 
0 commit comments