From 84d6c8584392b736801427c789504800bc638cd2 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Wed, 7 Sep 2022 00:06:54 +0100 Subject: [PATCH] Trigger warnings for unused wasm-bindgen attributes This attempts to do something similar to #3070, but without potentially dangerous fallout from strict-mode failing on all the existing code out there. Instead of forcing a compiler error like strict-mode does, this PR will internally generate unused variables with spans pointing to unused attributes, so that users get a relatively meaningful warning. Here's how the result looks like on example from #2874: ``` warning: unused variable: `typescript_type` --> tests\headless\snippets.rs:67:28 | 67 | #[wasm_bindgen(getter, typescript_type = "Thing[]")] | ^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_typescript_type` | = note: `#[warn(unused_variables)]` on by default ``` This is not 100% perfect - until Rust has a built-in `compile_warning!`, nothing is - but is a better status quo than the current one and can help users find problematic attributes without actually breaking their builds. Fixes #3038. --- crates/macro-support/src/lib.rs | 4 +- crates/macro-support/src/parser.rs | 68 +++++++++++++++++++----------- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/crates/macro-support/src/lib.rs b/crates/macro-support/src/lib.rs index 9996849596a..b7a35ae1bed 100644 --- a/crates/macro-support/src/lib.rs +++ b/crates/macro-support/src/lib.rs @@ -35,7 +35,7 @@ pub fn expand(attr: TokenStream, input: TokenStream) -> Result true, _ => false, diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index a3148fdb184..d40eaae97b1 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -41,6 +41,8 @@ const JS_KEYWORDS: [&str; 20] = [ struct AttributeParseState { parsed: Cell, checks: Cell, + #[cfg(not(feature = "strict-macro"))] + unused_attrs: std::cell::RefCell>, } /// Parsed attributes from a `#[wasm_bindgen(..)]`. @@ -94,35 +96,40 @@ macro_rules! methods { ($(($name:ident, $variant:ident($($contents:tt)*)),)*) => { $(methods!(@method $name, $variant($($contents)*));)* - #[cfg(feature = "strict-macro")] fn check_used(self) -> Result<(), Diagnostic> { // Account for the fact this method was called ATTRS.with(|state| state.checks.set(state.checks.get() + 1)); - let mut errors = Vec::new(); - for (used, attr) in self.attrs.iter() { - if used.get() { - continue - } - // The check below causes rustc to crash on powerpc64 platforms - // with an LLVM error. To avoid this, we instead use #[cfg()] - // and duplicate the function below. See #58516 for details. - /*if !cfg!(feature = "strict-macro") { - continue - }*/ - let span = match attr { - $(BindgenAttr::$variant(span, ..) => span,)* - }; - errors.push(Diagnostic::span_error(*span, "unused #[wasm_bindgen] attribute")); + let unused = + self.attrs + .iter() + .filter_map(|(used, attr)| if used.get() { None } else { Some(attr) }) + .map(|attr| { + match attr { + $(BindgenAttr::$variant(span, ..) => { + #[cfg(feature = "strict-macro")] + { + Diagnostic::span_error(*span, "unused #[wasm_bindgen] attribute") + } + + #[cfg(not(feature = "strict-macro"))] + { + Ident::new(stringify!($name), *span) + } + },)* + } + }); + + #[cfg(feature = "strict-macro")] + { + Diagnostic::from_vec(unused.collect()) } - Diagnostic::from_vec(errors) - } - #[cfg(not(feature = "strict-macro"))] - fn check_used(self) -> Result<(), Diagnostic> { - // Account for the fact this method was called - ATTRS.with(|state| state.checks.set(state.checks.get() + 1)); - Ok(()) + #[cfg(not(feature = "strict-macro"))] + { + ATTRS.with(|state| state.unused_attrs.borrow_mut().extend(unused)); + Ok(()) + } } }; @@ -1617,12 +1624,25 @@ pub fn reset_attrs_used() { ATTRS.with(|state| { state.parsed.set(0); state.checks.set(0); + #[cfg(not(feature = "strict-macro"))] + state.unused_attrs.borrow_mut().clear(); }) } -pub fn assert_all_attrs_checked() { +pub fn check_unused_attrs(tokens: &mut TokenStream) { ATTRS.with(|state| { assert_eq!(state.parsed.get(), state.checks.get()); + #[cfg(not(feature = "strict-macro"))] + { + let unused = &*state.unused_attrs.borrow(); + tokens.extend(quote::quote! { + // Anonymous scope to prevent name clashes. + const _: () = { + #(let #unused: ();)* + }; + }); + } + let _ = tokens; }) }