diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs index b1345d0b751..cf526409374 100644 --- a/clippy_lints/src/macro_use.rs +++ b/clippy_lints/src/macro_use.rs @@ -1,10 +1,11 @@ -use crate::utils::{snippet, span_lint_and_sugg}; +use crate::utils::{snippet, span_lint_and_sugg, in_macro}; use if_chain::if_chain; use rustc_ast::ast; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::edition::Edition; +use rustc_session::{impl_lint_pass, declare_tool_lint}; +use rustc_span::{edition::Edition, Span}; declare_clippy_lint! { /// **What it does:** Checks for `#[macro_use] use...`. @@ -12,21 +13,27 @@ declare_clippy_lint! { /// **Why is this bad?** Since the Rust 2018 edition you can import /// macro's directly, this is considered idiomatic. /// - /// **Known problems:** This lint does not generate an auto-applicable suggestion. + /// **Known problems:** None. /// /// **Example:** /// ```rust /// #[macro_use] /// use lazy_static; /// ``` - pub MACRO_USE_IMPORTS, + pub MACRO_USE_IMPORT, pedantic, "#[macro_use] is no longer needed" } -declare_lint_pass!(MacroUseImports => [MACRO_USE_IMPORTS]); +#[derive(Default)] +pub struct MacroUseImport { + collected: FxHashSet, +} + +impl_lint_pass!(MacroUseImport => [MACRO_USE_IMPORT]); + +impl EarlyLintPass for MacroUseImport { -impl EarlyLintPass for MacroUseImports { fn check_item(&mut self, ecx: &EarlyContext<'_>, item: &ast::Item) { if_chain! { if ecx.sess.opts.edition == Edition::Edition2018; @@ -36,18 +43,59 @@ impl EarlyLintPass for MacroUseImports { .iter() .find(|attr| attr.ident().map(|s| s.to_string()) == Some("macro_use".to_string())); then { + let import_path = snippet(ecx, use_tree.span, "_"); + let mac_names = find_used_macros(ecx, &import_path); let msg = "`macro_use` attributes are no longer needed in the Rust 2018 edition"; - let help = format!("use {}::", snippet(ecx, use_tree.span, "_")); + let help = format!("use {}::", import_path); span_lint_and_sugg( ecx, - MACRO_USE_IMPORTS, + MACRO_USE_IMPORT, mac_attr.span, msg, - "remove the attribute and import the macro directly, try", + // "remove the attribute and import the macro directly, try", + "", help, Applicability::HasPlaceholders, ); } } } + + fn check_expr(&mut self, ecx: &EarlyContext<'_>, expr: &ast::Expr) { + if in_macro(expr.span) { + let name = snippet(ecx, ecx.sess.source_map().span_until_char(expr.span.source_callsite(), '!'), "_"); + if let Some(callee) = expr.span.source_callee() { + if self.collected.insert(callee.def_site) { + println!("EXPR {:#?}", name); + } + } + } + } + fn check_stmt(&mut self, ecx: &EarlyContext<'_>, stmt: &ast::Stmt) { + if in_macro(stmt.span) { + let name = snippet(ecx, ecx.sess.source_map().span_until_char(stmt.span.source_callsite(), '!'), "_"); + if let Some(callee) = stmt.span.source_callee() { + println!("EXPR {:#?}", name); + } + } + } + fn check_pat(&mut self, ecx: &EarlyContext<'_>, pat: &ast::Pat) { + if in_macro(pat.span) { + let name = snippet(ecx, ecx.sess.source_map().span_until_char(pat.span.source_callsite(), '!'), "_"); + if let Some(callee) = pat.span.source_callee() { + println!("EXPR {:#?}", name); + } + } + } +} + +fn find_used_macros(ecx: &EarlyContext<'_>, path: &str) { + for it in ecx.krate.module.items.iter() { + if in_macro(it.span) { + // println!("{:#?}", it) + } + } + for x in ecx.sess.imported_macro_spans.borrow().iter() { + // println!("{:?}", x); + } } diff --git a/macro_use_import b/macro_use_import new file mode 100755 index 00000000000..61d3a827f1f Binary files /dev/null and b/macro_use_import differ diff --git a/tests/ui/macro_use_import.rs b/tests/ui/macro_use_import.rs new file mode 100644 index 00000000000..6490a2107d5 --- /dev/null +++ b/tests/ui/macro_use_import.rs @@ -0,0 +1,12 @@ +// compile-flags: --edition 2018 +#![warn(clippy::macro_use_import)] + +use std::collections::HashMap; +#[macro_use] +use std::prelude; + +fn main() { + let _ = HashMap::::new(); + serde_if_integer128!(""); + println!(); +} diff --git a/tests/ui/macro_use_import.stderr b/tests/ui/macro_use_import.stderr new file mode 100644 index 00000000000..1d86ba58441 --- /dev/null +++ b/tests/ui/macro_use_import.stderr @@ -0,0 +1,10 @@ +error: `macro_use` attributes are no longer needed in the Rust 2018 edition + --> $DIR/macro_use_import.rs:5:1 + | +LL | #[macro_use] + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use std::prelude::` + | + = note: `-D clippy::macro-use-import` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/macro_use_import.stdout b/tests/ui/macro_use_import.stdout new file mode 100644 index 00000000000..e69de29bb2d