diff options
| author | Jason Newcomb <jsnewcomb@pm.me> | 2021-08-04 13:48:45 -0400 |
|---|---|---|
| committer | Jason Newcomb <jsnewcomb@pm.me> | 2021-08-14 19:49:54 -0400 |
| commit | 251dd30d77c98cbebd1c68840fce029affe9b6a8 (patch) | |
| tree | e1efdac07311d834631939ce5643ed725d88d6ea /clippy_lints | |
| parent | 4838c78ba4ef784379ae6ec5617479de2a32d3f6 (diff) | |
| download | rust-251dd30d77c98cbebd1c68840fce029affe9b6a8.tar.gz rust-251dd30d77c98cbebd1c68840fce029affe9b6a8.zip | |
Improve `manual_map`
In some cases check if a borrow made in the scrutinee expression would prevent creating the closure used by `map`
Diffstat (limited to 'clippy_lints')
| -rw-r--r-- | clippy_lints/src/manual_map.rs | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs index 7dec1595e0d..3ea88f52a1c 100644 --- a/clippy_lints/src/manual_map.rs +++ b/clippy_lints/src/manual_map.rs @@ -4,12 +4,14 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable}; use clippy_utils::{ can_move_expr_to_closure, in_constant, is_else_clause, is_lang_ctor, is_lint_allowed, path_to_local_id, - peel_hir_expr_refs, + peel_hir_expr_refs, peel_hir_expr_while, CaptureKind, }; use rustc_ast::util::parser::PREC_POSTFIX; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome}; -use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, HirId, MatchSource, Mutability, Pat, PatKind}; +use rustc_hir::{ + def::Res, Arm, BindingAnnotation, Block, Expr, ExprKind, HirId, MatchSource, Mutability, Pat, PatKind, Path, QPath, +}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -111,10 +113,6 @@ impl LateLintPass<'_> for ManualMap { return; } - if !can_move_expr_to_closure(cx, some_expr) { - return; - } - // Determine which binding mode to use. let explicit_ref = some_pat.contains_explicit_ref_binding(); let binding_ref = explicit_ref.or_else(|| (ty_ref_count != pat_ref_count).then(|| ty_mutability)); @@ -125,6 +123,32 @@ impl LateLintPass<'_> for ManualMap { None => "", }; + match can_move_expr_to_closure(cx, some_expr) { + Some(captures) => { + // Check if captures the closure will need conflict with borrows made in the scrutinee. + // TODO: check all the references made in the scrutinee expression. This will require interacting + // with the borrow checker. Currently only `<local>[.<field>]*` is checked for. + if let Some(binding_ref_mutability) = binding_ref { + let e = peel_hir_expr_while(scrutinee, |e| match e.kind { + ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) => Some(e), + _ => None, + }); + if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind { + match captures.get(l) { + Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return, + Some(CaptureKind::Ref(Mutability::Not)) + if binding_ref_mutability == Mutability::Mut => + { + return; + } + Some(CaptureKind::Ref(Mutability::Not)) | None => (), + } + } + } + }, + None => return, + }; + let mut app = Applicability::MachineApplicable; // Remove address-of expressions from the scrutinee. Either `as_ref` will be called, or |
