| use clippy_utils::diagnostics::span_lint_hir_and_then; | 
 | use clippy_utils::source::snippet; | 
 | use hir::def::{DefKind, Res}; | 
 | use rustc_data_structures::fx::FxHashSet; | 
 | use rustc_errors::Applicability; | 
 | use rustc_hir::{self as hir, AmbigArg}; | 
 | use rustc_lint::{LateContext, LateLintPass, LintContext}; | 
 | use rustc_session::impl_lint_pass; | 
 | use rustc_span::edition::Edition; | 
 | use rustc_span::{Span}; | 
 | use std::collections::BTreeMap; | 
 | use rustc_attr_data_structures::{AttributeKind, find_attr}; | 
 |  | 
 | declare_clippy_lint! { | 
 |     /// ### What it does | 
 |     /// Checks for `#[macro_use] use...`. | 
 |     /// | 
 |     /// ### Why is this bad? | 
 |     /// Since the Rust 2018 edition you can import | 
 |     /// macro's directly, this is considered idiomatic. | 
 |     /// | 
 |     /// ### Example | 
 |     /// ```rust,ignore | 
 |     /// #[macro_use] | 
 |     /// extern crate some_crate; | 
 |     /// | 
 |     /// fn main() { | 
 |     ///     some_macro!(); | 
 |     /// } | 
 |     /// ``` | 
 |     /// | 
 |     /// Use instead: | 
 |     /// | 
 |     /// ```rust,ignore | 
 |     /// use some_crate::some_macro; | 
 |     /// | 
 |     /// fn main() { | 
 |     ///     some_macro!(); | 
 |     /// } | 
 |     /// ``` | 
 |     #[clippy::version = "1.44.0"] | 
 |     pub MACRO_USE_IMPORTS, | 
 |     pedantic, | 
 |     "#[macro_use] is no longer needed" | 
 | } | 
 |  | 
 | /// `MacroRefData` includes the name of the macro. | 
 | #[derive(Debug, Clone)] | 
 | pub struct MacroRefData { | 
 |     name: String, | 
 | } | 
 |  | 
 | impl MacroRefData { | 
 |     pub fn new(name: String) -> Self { | 
 |         Self { name } | 
 |     } | 
 | } | 
 |  | 
 | #[derive(Default)] | 
 | pub struct MacroUseImports { | 
 |     /// the actual import path used and the span of the attribute above it. The value is | 
 |     /// the location, where the lint should be emitted. | 
 |     imports: Vec<(String, Span, hir::HirId)>, | 
 |     /// the span of the macro reference, kept to ensure only one reference is used per macro call. | 
 |     collected: FxHashSet<Span>, | 
 |     mac_refs: Vec<MacroRefData>, | 
 | } | 
 |  | 
 | impl_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]); | 
 |  | 
 | impl MacroUseImports { | 
 |     fn push_unique_macro(&mut self, cx: &LateContext<'_>, span: Span) { | 
 |         let call_site = span.source_callsite(); | 
 |         let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_"); | 
 |         if span.source_callee().is_some() && !self.collected.contains(&call_site) { | 
 |             let name = if name.contains("::") { | 
 |                 name.split("::").last().unwrap().to_string() | 
 |             } else { | 
 |                 name.to_string() | 
 |             }; | 
 |  | 
 |             self.mac_refs.push(MacroRefData::new(name)); | 
 |             self.collected.insert(call_site); | 
 |         } | 
 |     } | 
 |  | 
 |     fn push_unique_macro_pat_ty(&mut self, cx: &LateContext<'_>, span: Span) { | 
 |         let call_site = span.source_callsite(); | 
 |         let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_"); | 
 |         if span.source_callee().is_some() && !self.collected.contains(&call_site) { | 
 |             self.mac_refs.push(MacroRefData::new(name.to_string())); | 
 |             self.collected.insert(call_site); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | impl LateLintPass<'_> for MacroUseImports { | 
 |     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { | 
 |         if cx.sess().opts.edition >= Edition::Edition2018 | 
 |             && let hir::ItemKind::Use(path, _kind) = &item.kind | 
 |             && let hir_id = item.hir_id() | 
 |             && let attrs = cx.tcx.hir_attrs(hir_id) | 
 |             && let Some(mac_attr_span) = find_attr!(attrs, AttributeKind::MacroUse {span, ..} => *span) | 
 |             && let Some(Res::Def(DefKind::Mod, id)) = path.res.type_ns | 
 |             && !id.is_local() | 
 |         { | 
 |             for kid in cx.tcx.module_children(id) { | 
 |                 if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res { | 
 |                     let def_path = cx.tcx.def_path_str(mac_id); | 
 |                     self.imports.push((def_path, mac_attr_span, hir_id)); | 
 |                 } | 
 |             } | 
 |         } else if item.span.from_expansion() { | 
 |             self.push_unique_macro_pat_ty(cx, item.span); | 
 |         } | 
 |     } | 
 |     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { | 
 |         if expr.span.from_expansion() { | 
 |             self.push_unique_macro(cx, expr.span); | 
 |         } | 
 |     } | 
 |     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) { | 
 |         if stmt.span.from_expansion() { | 
 |             self.push_unique_macro(cx, stmt.span); | 
 |         } | 
 |     } | 
 |     fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) { | 
 |         if pat.span.from_expansion() { | 
 |             self.push_unique_macro_pat_ty(cx, pat.span); | 
 |         } | 
 |     } | 
 |     fn check_ty(&mut self, cx: &LateContext<'_>, ty: &hir::Ty<'_, AmbigArg>) { | 
 |         if ty.span.from_expansion() { | 
 |             self.push_unique_macro_pat_ty(cx, ty.span); | 
 |         } | 
 |     } | 
 |     fn check_crate_post(&mut self, cx: &LateContext<'_>) { | 
 |         let mut used = BTreeMap::new(); | 
 |         let mut check_dup = vec![]; | 
 |         for (import, span, hir_id) in &self.imports { | 
 |             let found_idx = self.mac_refs.iter().position(|mac| import.ends_with(&mac.name)); | 
 |  | 
 |             if let Some(idx) = found_idx { | 
 |                 self.mac_refs.remove(idx); | 
 |                 let seg = import.split("::").collect::<Vec<_>>(); | 
 |  | 
 |                 match seg.as_slice() { | 
 |                     // an empty path is impossible | 
 |                     // a path should always consist of 2 or more segments | 
 |                     [] | [_] => return, | 
 |                     [root, item] => { | 
 |                         if !check_dup.contains(&(*item).to_string()) { | 
 |                             used.entry(( | 
 |                                 (*root).to_string(), | 
 |                                 span, | 
 |                                 hir_id.local_id, | 
 |                                 cx.tcx.def_path_hash(hir_id.owner.def_id.into()), | 
 |                             )) | 
 |                             .or_insert_with(|| (vec![], hir_id)) | 
 |                             .0 | 
 |                             .push((*item).to_string()); | 
 |                             check_dup.push((*item).to_string()); | 
 |                         } | 
 |                     }, | 
 |                     [root, rest @ ..] => { | 
 |                         if rest.iter().all(|item| !check_dup.contains(&(*item).to_string())) { | 
 |                             let filtered = rest | 
 |                                 .iter() | 
 |                                 .filter_map(|item| { | 
 |                                     if check_dup.contains(&(*item).to_string()) { | 
 |                                         None | 
 |                                     } else { | 
 |                                         Some((*item).to_string()) | 
 |                                     } | 
 |                                 }) | 
 |                                 .collect::<Vec<_>>(); | 
 |                             used.entry(( | 
 |                                 (*root).to_string(), | 
 |                                 span, | 
 |                                 hir_id.local_id, | 
 |                                 cx.tcx.def_path_hash(hir_id.owner.def_id.into()), | 
 |                             )) | 
 |                             .or_insert_with(|| (vec![], hir_id)) | 
 |                             .0 | 
 |                             .push(filtered.join("::")); | 
 |                             check_dup.extend(filtered); | 
 |                         } else { | 
 |                             let rest = rest.to_vec(); | 
 |                             used.entry(( | 
 |                                 (*root).to_string(), | 
 |                                 span, | 
 |                                 hir_id.local_id, | 
 |                                 cx.tcx.def_path_hash(hir_id.owner.def_id.into()), | 
 |                             )) | 
 |                             .or_insert_with(|| (vec![], hir_id)) | 
 |                             .0 | 
 |                             .push(rest.join("::")); | 
 |                             check_dup.extend(rest.iter().map(ToString::to_string)); | 
 |                         } | 
 |                     }, | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         // If mac_refs is not empty we have encountered an import we could not handle | 
 |         // such as `std::prelude::v1::foo` or some other macro that expands to an import. | 
 |         if self.mac_refs.is_empty() { | 
 |             for ((root, span, ..), (path, hir_id)) in used { | 
 |                 let import = if let [single] = &path[..] { | 
 |                     format!("{root}::{single}") | 
 |                 } else { | 
 |                     format!("{root}::{{{}}}", path.join(", ")) | 
 |                 }; | 
 |  | 
 |                 span_lint_hir_and_then( | 
 |                     cx, | 
 |                     MACRO_USE_IMPORTS, | 
 |                     *hir_id, | 
 |                     *span, | 
 |                     "`macro_use` attributes are no longer needed in the Rust 2018 edition", | 
 |                     |diag| { | 
 |                         diag.span_suggestion( | 
 |                             *span, | 
 |                             "remove the attribute and import the macro directly, try", | 
 |                             format!("use {import};"), | 
 |                             Applicability::MaybeIncorrect, | 
 |                         ); | 
 |                     }, | 
 |                 ); | 
 |             } | 
 |         } | 
 |     } | 
 | } |