]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/same_name_method.rs
Auto merge of #9539 - Jarcho:ice_9445, r=flip1995
[rust.git] / clippy_lints / src / same_name_method.rs
index 22b458969551272c8083bf6cf97559055947c65c..dead36e3bea8f124d00e128cebc06372a0ee9bcc 100644 (file)
@@ -1,7 +1,7 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind};
+use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::AssocKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 declare_lint_pass!(SameNameMethod => [SAME_NAME_METHOD]);
 
 struct ExistingName {
-    impl_methods: BTreeMap<Symbol, Span>,
+    impl_methods: BTreeMap<Symbol, (Span, HirId)>,
     trait_methods: BTreeMap<Symbol, Vec<Span>>,
 }
 
 impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
+    #[expect(clippy::too_many_lines)]
     fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
         let mut map = FxHashMap::<Res, ExistingName>::default();
 
-        for item in cx.tcx.hir().items() {
-            if let ItemKind::Impl(Impl {
-                items,
-                of_trait,
-                self_ty,
-                ..
-            }) = &item.kind
+        for id in cx.tcx.hir().items() {
+            if matches!(cx.tcx.def_kind(id.def_id), DefKind::Impl)
+                && let item = cx.tcx.hir().item(id)
+                && let ItemKind::Impl(Impl {
+                    items,
+                    of_trait,
+                    self_ty,
+                    ..
+                }) = &item.kind
+                && let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind
             {
-                if let TyKind::Path(QPath::Resolved(_, Path { res, .. })) = self_ty.kind {
-                    if !map.contains_key(res) {
-                        map.insert(
-                            *res,
-                            ExistingName {
-                                impl_methods: BTreeMap::new(),
-                                trait_methods: BTreeMap::new(),
-                            },
-                        );
-                    }
-                    let existing_name = map.get_mut(res).unwrap();
-
-                    match of_trait {
-                        Some(trait_ref) => {
-                            let mut methods_in_trait: BTreeSet<Symbol> = if_chain! {
-                                if let Some(Node::TraitRef(TraitRef { path, .. })) =
-                                    cx.tcx.hir().find(trait_ref.hir_ref_id);
-                                if let Res::Def(DefKind::Trait, did) = path.res;
-                                then{
-                                    // FIXME: if
-                                    // `rustc_middle::ty::assoc::AssocItems::items` is public,
-                                    // we can iterate its keys instead of `in_definition_order`,
-                                    // which's more efficient
-                                    cx.tcx
-                                        .associated_items(did)
-                                        .in_definition_order()
-                                        .filter(|assoc_item| {
-                                            matches!(assoc_item.kind, AssocKind::Fn)
-                                        })
-                                        .map(|assoc_item| assoc_item.name)
-                                        .collect()
-                                }else{
-                                    BTreeSet::new()
-                                }
-                            };
-
-                            let mut check_trait_method = |method_name: Symbol, trait_method_span: Span| {
-                                if let Some(impl_span) = existing_name.impl_methods.get(&method_name) {
-                                    span_lint_and_then(
-                                        cx,
-                                        SAME_NAME_METHOD,
-                                        *impl_span,
-                                        "method's name is the same as an existing method in a trait",
-                                        |diag| {
-                                            diag.span_note(
-                                                trait_method_span,
-                                                &format!("existing `{}` defined here", method_name),
-                                            );
-                                        },
-                                    );
-                                }
-                                if let Some(v) = existing_name.trait_methods.get_mut(&method_name) {
-                                    v.push(trait_method_span);
-                                } else {
-                                    existing_name.trait_methods.insert(method_name, vec![trait_method_span]);
-                                }
-                            };
+                if !map.contains_key(res) {
+                    map.insert(
+                        *res,
+                        ExistingName {
+                            impl_methods: BTreeMap::new(),
+                            trait_methods: BTreeMap::new(),
+                        },
+                    );
+                }
+                let existing_name = map.get_mut(res).unwrap();
 
-                            for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
-                                matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
-                            }) {
-                                let method_name = impl_item_ref.ident.name;
-                                methods_in_trait.remove(&method_name);
-                                check_trait_method(method_name, impl_item_ref.span);
+                match of_trait {
+                    Some(trait_ref) => {
+                        let mut methods_in_trait: BTreeSet<Symbol> = if_chain! {
+                            if let Some(Node::TraitRef(TraitRef { path, .. })) =
+                                cx.tcx.hir().find(trait_ref.hir_ref_id);
+                            if let Res::Def(DefKind::Trait, did) = path.res;
+                            then{
+                                // FIXME: if
+                                // `rustc_middle::ty::assoc::AssocItems::items` is public,
+                                // we can iterate its keys instead of `in_definition_order`,
+                                // which's more efficient
+                                cx.tcx
+                                    .associated_items(did)
+                                    .in_definition_order()
+                                    .filter(|assoc_item| {
+                                        matches!(assoc_item.kind, AssocKind::Fn)
+                                    })
+                                    .map(|assoc_item| assoc_item.name)
+                                    .collect()
+                            }else{
+                                BTreeSet::new()
                             }
+                        };
 
-                            for method_name in methods_in_trait {
-                                check_trait_method(method_name, item.span);
+                        let mut check_trait_method = |method_name: Symbol, trait_method_span: Span| {
+                            if let Some((impl_span, hir_id)) = existing_name.impl_methods.get(&method_name) {
+                                span_lint_hir_and_then(
+                                    cx,
+                                    SAME_NAME_METHOD,
+                                    *hir_id,
+                                    *impl_span,
+                                    "method's name is the same as an existing method in a trait",
+                                    |diag| {
+                                        diag.span_note(
+                                            trait_method_span,
+                                            &format!("existing `{method_name}` defined here"),
+                                        );
+                                    },
+                                );
                             }
-                        },
-                        None => {
-                            for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
-                                matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
-                            }) {
-                                let method_name = impl_item_ref.ident.name;
-                                let impl_span = impl_item_ref.span;
-                                if let Some(trait_spans) = existing_name.trait_methods.get(&method_name) {
-                                    span_lint_and_then(
-                                        cx,
-                                        SAME_NAME_METHOD,
-                                        impl_span,
-                                        "method's name is the same as an existing method in a trait",
-                                        |diag| {
-                                            // TODO should we `span_note` on every trait?
-                                            // iterate on trait_spans?
-                                            diag.span_note(
-                                                trait_spans[0],
-                                                &format!("existing `{}` defined here", method_name),
-                                            );
-                                        },
-                                    );
-                                }
-                                existing_name.impl_methods.insert(method_name, impl_span);
+                            if let Some(v) = existing_name.trait_methods.get_mut(&method_name) {
+                                v.push(trait_method_span);
+                            } else {
+                                existing_name.trait_methods.insert(method_name, vec![trait_method_span]);
                             }
-                        },
-                    }
+                        };
+
+                        for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
+                            matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
+                        }) {
+                            let method_name = impl_item_ref.ident.name;
+                            methods_in_trait.remove(&method_name);
+                            check_trait_method(method_name, impl_item_ref.span);
+                        }
+
+                        for method_name in methods_in_trait {
+                            check_trait_method(method_name, item.span);
+                        }
+                    },
+                    None => {
+                        for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
+                            matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
+                        }) {
+                            let method_name = impl_item_ref.ident.name;
+                            let impl_span = impl_item_ref.span;
+                            let hir_id = impl_item_ref.id.hir_id();
+                            if let Some(trait_spans) = existing_name.trait_methods.get(&method_name) {
+                                span_lint_hir_and_then(
+                                    cx,
+                                    SAME_NAME_METHOD,
+                                    hir_id,
+                                    impl_span,
+                                    "method's name is the same as an existing method in a trait",
+                                    |diag| {
+                                        // TODO should we `span_note` on every trait?
+                                        // iterate on trait_spans?
+                                        diag.span_note(
+                                            trait_spans[0],
+                                            &format!("existing `{method_name}` defined here"),
+                                        );
+                                    },
+                                );
+                            }
+                            existing_name.impl_methods.insert(method_name, (impl_span, hir_id));
+                        }
+                    },
                 }
             }
         }