|
1 | 1 | use if_chain::if_chain;
|
2 | 2 | use rustc_errors::Applicability;
|
3 |
| -use rustc_hir::{Block, ExprKind, PatKind, StmtKind}; |
| 3 | +use rustc_hir::def_id::DefId; |
| 4 | +use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; |
| 5 | +use rustc_hir::{Block, Expr, ExprKind, PatKind, StmtKind}; |
4 | 6 | use rustc_lint::{LateContext, LateLintPass, LintContext};
|
| 7 | +use rustc_middle::hir::map::Map; |
5 | 8 | use rustc_middle::lint::in_external_macro;
|
| 9 | +use rustc_middle::ty::subst::GenericArgKind; |
6 | 10 | use rustc_session::{declare_lint_pass, declare_tool_lint};
|
7 | 11 |
|
8 | 12 | use crate::utils::{in_macro, match_qpath, snippet_opt, span_lint_and_then};
|
@@ -49,6 +53,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetReturn {
|
49 | 53 | if let PatKind::Binding(.., ident, _) = local.pat.kind;
|
50 | 54 | if let ExprKind::Path(qpath) = &retexpr.kind;
|
51 | 55 | if match_qpath(qpath, &[&*ident.name.as_str()]);
|
| 56 | + if !last_statement_borrows(cx, initexpr); |
52 | 57 | if !in_external_macro(cx.sess(), initexpr.span);
|
53 | 58 | if !in_external_macro(cx.sess(), retexpr.span);
|
54 | 59 | if !in_external_macro(cx.sess(), local.span);
|
@@ -80,3 +85,57 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for LetReturn {
|
80 | 85 | }
|
81 | 86 | }
|
82 | 87 | }
|
| 88 | + |
| 89 | +fn last_statement_borrows<'tcx>(cx: &LateContext<'_, 'tcx>, expr: &'tcx Expr<'tcx>) -> bool { |
| 90 | + let mut visitor = BorrowVisitor { cx, borrows: false }; |
| 91 | + walk_expr(&mut visitor, expr); |
| 92 | + visitor.borrows |
| 93 | +} |
| 94 | + |
| 95 | +struct BorrowVisitor<'a, 'tcx> { |
| 96 | + cx: &'a LateContext<'a, 'tcx>, |
| 97 | + borrows: bool, |
| 98 | +} |
| 99 | + |
| 100 | +impl BorrowVisitor<'_, '_> { |
| 101 | + fn fn_def_id(&self, expr: &Expr<'_>) -> Option<DefId> { |
| 102 | + match &expr.kind { |
| 103 | + ExprKind::MethodCall(..) => self.cx.tables.type_dependent_def_id(expr.hir_id), |
| 104 | + ExprKind::Call( |
| 105 | + Expr { |
| 106 | + kind: ExprKind::Path(qpath), |
| 107 | + .. |
| 108 | + }, |
| 109 | + .., |
| 110 | + ) => self.cx.tables.qpath_res(qpath, expr.hir_id).opt_def_id(), |
| 111 | + _ => None, |
| 112 | + } |
| 113 | + } |
| 114 | +} |
| 115 | + |
| 116 | +impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> { |
| 117 | + type Map = Map<'tcx>; |
| 118 | + |
| 119 | + fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { |
| 120 | + if self.borrows { |
| 121 | + return; |
| 122 | + } |
| 123 | + |
| 124 | + if let Some(def_id) = self.fn_def_id(expr) { |
| 125 | + self.borrows = self |
| 126 | + .cx |
| 127 | + .tcx |
| 128 | + .fn_sig(def_id) |
| 129 | + .output() |
| 130 | + .skip_binder() |
| 131 | + .walk() |
| 132 | + .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_))); |
| 133 | + } |
| 134 | + |
| 135 | + walk_expr(self, expr); |
| 136 | + } |
| 137 | + |
| 138 | + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { |
| 139 | + NestedVisitorMap::None |
| 140 | + } |
| 141 | +} |
0 commit comments