diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 9844df3c650..8e295af234c 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -1,6 +1,6 @@ use crate::utils::{ - iter_input_pats, match_def_path, qpath_res, return_ty, snippet, snippet_opt, span_help_and_lint, span_lint, - span_lint_and_then, type_is_unsafe_function, + attrs::is_proc_macro, iter_input_pats, match_def_path, qpath_res, return_ty, snippet, snippet_opt, + span_help_and_lint, span_lint, span_lint_and_then, type_is_unsafe_function, }; use matches::matches; use rustc::hir::{self, def::Res, def_id::DefId, intravisit}; @@ -234,7 +234,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { check_needless_must_use(cx, decl, item.hir_id, item.span, fn_header_span, attr); return; } - if cx.access_levels.is_exported(item.hir_id) { + if cx.access_levels.is_exported(item.hir_id) && !is_proc_macro(&item.attrs) { check_must_use_candidate( cx, decl, @@ -254,7 +254,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { if let Some(attr) = attr { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); check_needless_must_use(cx, &sig.decl, item.hir_id, item.span, fn_header_span, attr); - } else if cx.access_levels.is_exported(item.hir_id) { + } else if cx.access_levels.is_exported(item.hir_id) && !is_proc_macro(&item.attrs) { check_must_use_candidate( cx, &sig.decl, @@ -284,7 +284,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions { let body = cx.tcx.hir().body(eid); Self::check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id); - if attr.is_none() && cx.access_levels.is_exported(item.hir_id) { + if attr.is_none() && cx.access_levels.is_exported(item.hir_id) && !is_proc_macro(&item.attrs) { check_must_use_candidate( cx, &sig.decl, diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index eaad932cb67..2520f366b32 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -114,3 +114,16 @@ fn parse_attrs(sess: &Session, attrs: &[ast::Attribute], name: &' } } } + +/// Return true if the attributes contain any of `proc_macro`, +/// `proc_macro_derive` or `proc_macro_attribute`, false otherwise +pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool { + use syntax_pos::Symbol; + + let syms = [ + Symbol::intern("proc_macro"), + Symbol::intern("proc_macro_derive"), + Symbol::intern("proc_macro_attribute"), + ]; + attrs.iter().any(|attr| syms.iter().any(move |&s| attr.check_name(s))) +} diff --git a/tests/ui/proc_macro.rs b/tests/ui/proc_macro.rs index dd8bd58c015..59914b8b8f6 100644 --- a/tests/ui/proc_macro.rs +++ b/tests/ui/proc_macro.rs @@ -1,8 +1,26 @@ //! Check that we correctly lint procedural macros. - #![crate_type = "proc-macro"] +extern crate proc_macro; + +use proc_macro::TokenStream; + #[allow(dead_code)] fn f() { let _x = 3.14; } + +#[proc_macro] +pub fn mybangmacro(t: TokenStream) -> TokenStream { + t +} + +#[proc_macro_derive(MyDerivedTrait)] +pub fn myderive(t: TokenStream) -> TokenStream { + t +} + +#[proc_macro_attribute] +pub fn myattribute(t: TokenStream, a: TokenStream) -> TokenStream { + t +} diff --git a/tests/ui/proc_macro.stderr b/tests/ui/proc_macro.stderr index 78c3880db49..872cbc66af6 100644 --- a/tests/ui/proc_macro.stderr +++ b/tests/ui/proc_macro.stderr @@ -1,5 +1,5 @@ error: approximate value of `f{32, 64}::consts::PI` found. Consider using it directly - --> $DIR/proc_macro.rs:7:14 + --> $DIR/proc_macro.rs:10:14 | LL | let _x = 3.14; | ^^^^