|
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