about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-01-28 22:25:47 +0100
committerGitHub <noreply@github.com>2019-01-28 22:25:47 +0100
commitd3bb907eff4e1c59667ee0fccbc21a08d023bd74 (patch)
treefd9439f1ce04d749b825bee8c4a8d6dda59b7736
parentb1b67cdec152abdee33729f23d95911536a7483f (diff)
parent5e6702117223b61057957ca2593f03e3f45ccd8a (diff)
downloadrust-d3bb907eff4e1c59667ee0fccbc21a08d023bd74.tar.gz
rust-d3bb907eff4e1c59667ee0fccbc21a08d023bd74.zip
Rollup merge of #57904 - euclio:attribute-typos, r=davidtwco
add typo suggestion to unknown attribute error

Provides a suggestion using Levenshtein distance to suggest built-in attributes and attribute macros.

Fixes #49270.
-rw-r--r--src/librustc_resolve/macros.rs70
-rw-r--r--src/test/ui/issues/issue-49074.stderr2
-rw-r--r--src/test/ui/macros/macro-reexport-removed.stderr2
-rw-r--r--src/test/ui/proc-macro/derive-still-gated.stderr2
-rw-r--r--src/test/ui/suggestions/attribute-typos.rs13
-rw-r--r--src/test/ui/suggestions/attribute-typos.stderr27
6 files changed, 108 insertions, 8 deletions
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index fb5b6c97689..78b55182030 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::<Vec<_>>();
+
+        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 d4648270f2d..a25d8ee3526 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 7c3555a92ed..6cfec3ee762 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 d54a593f783..ece1b621291 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 00000000000..13c6308b97e
--- /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 00000000000..e40da787e96
--- /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`.