diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 0e3d93175..f10c35cde 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -525,7 +525,11 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo .iter() .filter(|&&(_, name)| !name.as_str().starts_with('_')) .any(|&(_, name)| { - let mut walker = ContainsName { name, result: false }; + let mut walker = ContainsName { + name, + result: false, + cx, + }; // Scan block block diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index 7f937de1d..55f6121a0 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // find out if and which field was set by this `consecutive_statement` if let Some((field_ident, assign_rhs)) = field_reassigned_by_stmt(consecutive_statement, binding_name) { // interrupt and cancel lint if assign_rhs references the original binding - if contains_name(binding_name, assign_rhs) { + if contains_name(binding_name, assign_rhs, cx) { cancel_lint = true; break; } diff --git a/clippy_lints/src/loops/needless_range_loop.rs b/clippy_lints/src/loops/needless_range_loop.rs index 27ba27202..3bca93d80 100644 --- a/clippy_lints/src/loops/needless_range_loop.rs +++ b/clippy_lints/src/loops/needless_range_loop.rs @@ -81,7 +81,7 @@ pub(super) fn check<'tcx>( let skip = if starts_at_zero { String::new() - } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start) { + } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start, cx) { return; } else { format!(".skip({})", snippet(cx, start.span, "..")) @@ -109,7 +109,7 @@ pub(super) fn check<'tcx>( if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) { String::new() - } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) { + } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr, cx) { return; } else { match limits { diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs index 43e2d1ec8..46769cf23 100644 --- a/clippy_utils/src/lib.rs +++ b/clippy_utils/src/lib.rs @@ -116,6 +116,8 @@ use crate::consts::{constant, Constant}; use crate::ty::{can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type, ty_is_fn_once_param}; use crate::visitors::for_each_expr; +use rustc_middle::hir::nested_filter; + #[macro_export] macro_rules! extract_msrv_attr { ($context:ident) => { @@ -1253,22 +1255,33 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { } } -pub struct ContainsName { +pub struct ContainsName<'a, 'tcx> { + pub cx: &'a LateContext<'tcx>, pub name: Symbol, pub result: bool, } -impl<'tcx> Visitor<'tcx> for ContainsName { +impl<'a, 'tcx> Visitor<'tcx> for ContainsName<'a, 'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + fn visit_name(&mut self, name: Symbol) { if self.name == name { self.result = true; } } + + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } } /// Checks if an `Expr` contains a certain name. -pub fn contains_name(name: Symbol, expr: &Expr<'_>) -> bool { - let mut cn = ContainsName { name, result: false }; +pub fn contains_name<'tcx>(name: Symbol, expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> bool { + let mut cn = ContainsName { + name, + result: false, + cx, + }; cn.visit_expr(expr); cn.result } diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 7367910ea..1f989bb12 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -247,3 +247,24 @@ mod issue6312 { } } } + +struct Collection { + items: Vec, + len: usize, +} + +impl Default for Collection { + fn default() -> Self { + Self { + items: vec![1, 2, 3], + len: 0, + } + } +} + +#[allow(clippy::redundant_closure_call)] +fn issue10136() { + let mut c = Collection::default(); + // don't lint, since c.items was used to calculate this value + c.len = (|| c.items.len())(); +}