]> git.lizzy.rs Git - rust.git/commitdiff
Check if the lint_name is from a tool and if the tool_lint exists
authorflip1995 <9744647+flip1995@users.noreply.github.com>
Mon, 30 Jul 2018 09:29:23 +0000 (11:29 +0200)
committerflip1995 <9744647+flip1995@users.noreply.github.com>
Mon, 30 Jul 2018 14:10:41 +0000 (16:10 +0200)
src/librustc/lint/context.rs
src/librustc/lint/levels.rs

index 14cfaa8153377d76f1adbdcc6c5acac35ffc2a66..15630157722fa502ea3c715648c4ad01f7508914 100644 (file)
@@ -42,7 +42,7 @@
 use std::default::Default as StdDefault;
 use syntax::ast;
 use syntax::edition;
-use syntax_pos::{MultiSpan, Span};
+use syntax_pos::{MultiSpan, Span, symbol::LocalInternedString};
 use errors::DiagnosticBuilder;
 use hir;
 use hir::def_id::LOCAL_CRATE;
@@ -133,6 +133,12 @@ pub enum CheckLintNameResult<'a> {
     /// The lint is either renamed or removed. This is the warning
     /// message, and an optional new name (`None` if removed).
     Warning(String, Option<String>),
+    /// The lint is from a tool. If the Option is None, then either
+    /// the lint does not exist in the tool or the code was not
+    /// compiled with the tool and therefore the lint was never
+    /// added to the `LintStore`. Otherwise the `LintId` will be
+    /// returned as if it where a rustc lint.
+    Tool(Option<&'a [LintId]>),
 }
 
 impl LintStore {
@@ -288,7 +294,7 @@ pub fn check_lint_name_cmdline(&self,
                                    sess: &Session,
                                    lint_name: &str,
                                    level: Level) {
-        let db = match self.check_lint_name(lint_name) {
+        let db = match self.check_lint_name(lint_name, None) {
             CheckLintNameResult::Ok(_) => None,
             CheckLintNameResult::Warning(ref msg, _) => {
                 Some(sess.struct_warn(msg))
@@ -296,6 +302,7 @@ pub fn check_lint_name_cmdline(&self,
             CheckLintNameResult::NoLint => {
                 Some(struct_err!(sess, E0602, "unknown lint: `{}`", lint_name))
             }
+            CheckLintNameResult::Tool(_) => unreachable!(),
         };
 
         if let Some(mut db) = db {
@@ -319,26 +326,41 @@ pub fn check_lint_name_cmdline(&self,
     /// it emits non-fatal warnings and there are *two* lint passes that
     /// inspect attributes, this is only run from the late pass to avoid
     /// printing duplicate warnings.
-    pub fn check_lint_name(&self, lint_name: &str) -> CheckLintNameResult {
-        match self.by_name.get(lint_name) {
-            Some(&Renamed(ref new_name, _)) => {
-                CheckLintNameResult::Warning(
-                    format!("lint `{}` has been renamed to `{}`", lint_name, new_name),
-                    Some(new_name.to_owned())
-                )
-            },
-            Some(&Removed(ref reason)) => {
-                CheckLintNameResult::Warning(
-                    format!("lint `{}` has been removed: `{}`", lint_name, reason),
-                    None
-                )
-            },
-            None => {
-                match self.lint_groups.get(lint_name) {
-                    None => CheckLintNameResult::NoLint,
-                    Some(ids) => CheckLintNameResult::Ok(&ids.0),
-                }
+    pub fn check_lint_name(
+        &self,
+        lint_name: &str,
+        tool_name: Option<LocalInternedString>,
+    ) -> CheckLintNameResult {
+        let complete_name = if let Some(tool_name) = tool_name {
+            format!("{}::{}", tool_name, lint_name)
+        } else {
+            lint_name.to_string()
+        };
+        if let Some(_) = tool_name {
+            match self.by_name.get(&complete_name) {
+                None => match self.lint_groups.get(&*complete_name) {
+                    None => return CheckLintNameResult::Tool(None),
+                    Some(ids) => return CheckLintNameResult::Tool(Some(&ids.0)),
+                },
+                Some(&Id(ref id)) => return CheckLintNameResult::Tool(Some(slice::from_ref(id))),
+                // If the lint was registered as removed or renamed by the lint tool, we don't need
+                // to treat tool_lints and rustc lints different and can use the code below.
+                _ => {}
             }
+        }
+        match self.by_name.get(&complete_name) {
+            Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning(
+                format!("lint `{}` has been renamed to `{}`", lint_name, new_name),
+                Some(new_name.to_owned()),
+            ),
+            Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
+                format!("lint `{}` has been removed: `{}`", lint_name, reason),
+                None,
+            ),
+            None => match self.lint_groups.get(&*complete_name) {
+                None => CheckLintNameResult::NoLint,
+                Some(ids) => CheckLintNameResult::Ok(&ids.0),
+            },
             Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
         }
     }
index b7b6aba970bff21c76a07c1e3f7a65913a7fec5e..6a29b8c3e3e6c11d7ce520b21d1b3a3c4a85d821 100644 (file)
@@ -227,8 +227,10 @@ pub fn push(&mut self, attrs: &[ast::Attribute]) -> BuilderPush {
                         continue
                     }
                 };
-                if let Some(lint_tool) = word.is_scoped() {
-                    if !self.sess.features_untracked().tool_lints {
+                let tool_name = if let Some(lint_tool) = word.is_scoped() {
+                    let gate_feature = !self.sess.features_untracked().tool_lints;
+                    let known_tool = attr::is_known_lint_tool(lint_tool);
+                    if gate_feature {
                         feature_gate::emit_feature_err(&sess.parse_sess,
                                                        "tool_lints",
                                                        word.span,
@@ -236,8 +238,7 @@ pub fn push(&mut self, attrs: &[ast::Attribute]) -> BuilderPush {
                                                        &format!("scoped lint `{}` is experimental",
                                                                 word.ident));
                     }
-
-                    if !attr::is_known_lint_tool(lint_tool) {
+                    if !known_tool {
                         span_err!(
                             sess,
                             lint_tool.span,
@@ -247,10 +248,16 @@ pub fn push(&mut self, attrs: &[ast::Attribute]) -> BuilderPush {
                         );
                     }
 
-                    continue
-                }
+                    if gate_feature || !known_tool {
+                        continue
+                    }
+
+                    Some(lint_tool.as_str())
+                } else {
+                    None
+                };
                 let name = word.name();
-                match store.check_lint_name(&name.as_str()) {
+                match store.check_lint_name(&name.as_str(), tool_name) {
                     CheckLintNameResult::Ok(ids) => {
                         let src = LintSource::Node(name, li.span);
                         for id in ids {
@@ -258,6 +265,19 @@ pub fn push(&mut self, attrs: &[ast::Attribute]) -> BuilderPush {
                         }
                     }
 
+                    CheckLintNameResult::Tool(result) => {
+                        if let Some(ids) = result {
+                            let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
+                            let src = LintSource::Node(Symbol::intern(complete_name), li.span);
+                            for id in ids {
+                                specs.insert(*id, (level, src));
+                            }
+                        }
+                        //FIXME: if Tool(None) is returned than the lint either does not exist in
+                        //the lint tool or the code doesn't get compiled with the lint tool and
+                        //therefore the lint cannot exist.
+                    }
+
                     _ if !self.warn_about_weird_lints => {}
 
                     CheckLintNameResult::Warning(msg, renamed) => {
@@ -298,7 +318,7 @@ pub fn push(&mut self, attrs: &[ast::Attribute]) -> BuilderPush {
                         if name.as_str().chars().any(|c| c.is_uppercase()) {
                             let name_lower = name.as_str().to_lowercase().to_string();
                             if let CheckLintNameResult::NoLint =
-                                    store.check_lint_name(&name_lower) {
+                                    store.check_lint_name(&name_lower, tool_name) {
                                 db.emit();
                             } else {
                                 db.span_suggestion_with_applicability(