From 5e6702117223b61057957ca2593f03e3f45ccd8a Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Fri, 25 Jan 2019 14:29:47 -0500 Subject: [PATCH] add typo suggestion to unknown attribute error --- src/librustc_resolve/macros.rs | 70 +++++++++++++++++-- src/test/ui/issues/issue-49074.stderr | 2 +- .../ui/macros/macro-reexport-removed.stderr | 2 +- .../ui/proc-macro/derive-still-gated.stderr | 2 +- src/test/ui/suggestions/attribute-typos.rs | 13 ++++ .../ui/suggestions/attribute-typos.stderr | 27 +++++++ 6 files changed, 108 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/suggestions/attribute-typos.rs create mode 100644 src/test/ui/suggestions/attribute-typos.stderr diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index fb5b6c97689d0..78b5518203084 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -19,7 +19,9 @@ use syntax::ext::base::{Annotatable, MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; use syntax::ext::hygiene::{self, Mark}; use syntax::ext::tt::macro_rules; -use syntax::feature_gate::{feature_err, is_builtin_attr_name, GateIssue}; +use syntax::feature_gate::{ + feature_err, is_builtin_attr_name, AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES, +}; use syntax::symbol::{Symbol, keywords}; use syntax::visit::Visitor; use syntax::util::lev_distance::find_best_match_for_name; @@ -310,15 +312,18 @@ impl<'a> Resolver<'a> { if !features.rustc_attrs { let msg = "unless otherwise specified, attributes with the prefix \ `rustc_` are reserved for internal compiler diagnostics"; - feature_err(&self.session.parse_sess, "rustc_attrs", path.span, - GateIssue::Language, &msg).emit(); + self.report_unknown_attribute(path.span, &name, msg, "rustc_attrs"); } } else if !features.custom_attribute { let msg = format!("The attribute `{}` is currently unknown to the \ compiler and may have meaning added to it in the \ future", path); - feature_err(&self.session.parse_sess, "custom_attribute", path.span, - GateIssue::Language, &msg).emit(); + self.report_unknown_attribute( + path.span, + &name, + &msg, + "custom_attribute", + ); } } } else { @@ -339,6 +344,61 @@ impl<'a> Resolver<'a> { Ok((def, self.get_macro(def))) } + fn report_unknown_attribute(&self, span: Span, name: &str, msg: &str, feature: &str) { + let mut err = feature_err( + &self.session.parse_sess, + feature, + span, + GateIssue::Language, + &msg, + ); + + let features = self.session.features_untracked(); + + let attr_candidates = BUILTIN_ATTRIBUTES + .iter() + .filter_map(|(name, _, _, gate)| { + if name.starts_with("rustc_") && !features.rustc_attrs { + return None; + } + + match gate { + AttributeGate::Gated(Stability::Unstable, ..) + if self.session.opts.unstable_features.is_nightly_build() => + { + Some(name) + } + AttributeGate::Gated(Stability::Deprecated(..), ..) => Some(name), + AttributeGate::Ungated => Some(name), + _ => None, + } + }) + .map(|name| Symbol::intern(name)) + .chain( + // Add built-in macro attributes as well. + self.builtin_macros.iter().filter_map(|(name, binding)| { + match binding.macro_kind() { + Some(MacroKind::Attr) => Some(*name), + _ => None, + } + }), + ) + .collect::>(); + + let lev_suggestion = find_best_match_for_name(attr_candidates.iter(), &name, None); + + if let Some(suggestion) = lev_suggestion { + err.span_suggestion( + span, + "a built-in attribute with a similar name exists", + suggestion.to_string(), + Applicability::MaybeIncorrect, + ); + } + + err.emit(); + } + pub fn resolve_macro_to_def_inner( &mut self, path: &ast::Path, diff --git a/src/test/ui/issues/issue-49074.stderr b/src/test/ui/issues/issue-49074.stderr index d4648270f2d30..a25d8ee352686 100644 --- a/src/test/ui/issues/issue-49074.stderr +++ b/src/test/ui/issues/issue-49074.stderr @@ -2,7 +2,7 @@ error[E0658]: The attribute `marco_use` is currently unknown to the compiler and --> $DIR/issue-49074.rs:3:3 | LL | #[marco_use] // typo - | ^^^^^^^^^ + | ^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_use` | = help: add #![feature(custom_attribute)] to the crate attributes to enable diff --git a/src/test/ui/macros/macro-reexport-removed.stderr b/src/test/ui/macros/macro-reexport-removed.stderr index 7c3555a92ed8b..6cfec3ee762dd 100644 --- a/src/test/ui/macros/macro-reexport-removed.stderr +++ b/src/test/ui/macros/macro-reexport-removed.stderr @@ -14,7 +14,7 @@ error[E0658]: The attribute `macro_reexport` is currently unknown to the compile --> $DIR/macro-reexport-removed.rs:5:3 | LL | #[macro_reexport(macro_one)] //~ ERROR attribute `macro_reexport` is currently unknown - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_export` | = help: add #![feature(custom_attribute)] to the crate attributes to enable diff --git a/src/test/ui/proc-macro/derive-still-gated.stderr b/src/test/ui/proc-macro/derive-still-gated.stderr index d54a593f78311..ece1b6212914d 100644 --- a/src/test/ui/proc-macro/derive-still-gated.stderr +++ b/src/test/ui/proc-macro/derive-still-gated.stderr @@ -2,7 +2,7 @@ error[E0658]: The attribute `derive_A` is currently unknown to the compiler and --> $DIR/derive-still-gated.rs:8:3 | LL | #[derive_A] //~ ERROR attribute `derive_A` is currently unknown - | ^^^^^^^^ + | ^^^^^^^^ help: a built-in attribute with a similar name exists: `derive` | = help: add #![feature(custom_attribute)] to the crate attributes to enable diff --git a/src/test/ui/suggestions/attribute-typos.rs b/src/test/ui/suggestions/attribute-typos.rs new file mode 100644 index 0000000000000..13c6308b97e85 --- /dev/null +++ b/src/test/ui/suggestions/attribute-typos.rs @@ -0,0 +1,13 @@ +#[deprcated] //~ ERROR E0658 +fn foo() {} //~| HELP a built-in attribute with a similar name exists + //~| SUGGESTION deprecated + //~| HELP add #![feature(custom_attribute)] to the crate attributes to enable + +#[tests] //~ ERROR E0658 +fn bar() {} //~| HELP a built-in attribute with a similar name exists + //~| SUGGESTION test + //~| HELP add #![feature(custom_attribute)] to the crate attributes to enable + +#[rustc_err] //~ ERROR E0658 +fn main() {} //~| HELP add #![feature(rustc_attrs)] to the crate attributes to enable + // don't suggest rustc attributes diff --git a/src/test/ui/suggestions/attribute-typos.stderr b/src/test/ui/suggestions/attribute-typos.stderr new file mode 100644 index 0000000000000..e40da787e96ca --- /dev/null +++ b/src/test/ui/suggestions/attribute-typos.stderr @@ -0,0 +1,27 @@ +error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642) + --> $DIR/attribute-typos.rs:11:3 + | +LL | #[rustc_err] //~ ERROR E0658 + | ^^^^^^^^^ + | + = help: add #![feature(rustc_attrs)] to the crate attributes to enable + +error[E0658]: The attribute `tests` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) + --> $DIR/attribute-typos.rs:6:3 + | +LL | #[tests] //~ ERROR E0658 + | ^^^^^ help: a built-in attribute with a similar name exists: `test` + | + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error[E0658]: The attribute `deprcated` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) + --> $DIR/attribute-typos.rs:1:3 + | +LL | #[deprcated] //~ ERROR E0658 + | ^^^^^^^^^ help: a built-in attribute with a similar name exists: `deprecated` + | + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`.