about summary refs log tree commit diff
diff options
context:
space:
mode:
authorest31 <MTest31@outlook.com>2017-05-11 10:26:07 +0200
committerest31 <MTest31@outlook.com>2017-05-13 16:02:29 +0200
commitdf188b8f976a49c226068e42a6c3ae2e15956daf (patch)
treeab3ba0ff5418ec021df14d24e0c0a9efec7f2705
parentef3ec5ece5bdf8950810225a9a3bc3cd1926e3d5 (diff)
downloadrust-df188b8f976a49c226068e42a6c3ae2e15956daf.tar.gz
rust-df188b8f976a49c226068e42a6c3ae2e15956daf.zip
Add lint for unused macros
-rw-r--r--src/librustc/lint/builtin.rs7
-rw-r--r--src/librustc_driver/driver.rs2
-rw-r--r--src/librustc_lint/lib.rs3
-rw-r--r--src/librustc_resolve/lib.rs7
-rw-r--r--src/librustc_resolve/macros.rs29
-rw-r--r--src/libsyntax/ext/base.rs6
6 files changed, 51 insertions, 3 deletions
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index e681d55cf94..07140f71aeb 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -77,6 +77,12 @@ declare_lint! {
 }
 
 declare_lint! {
+    pub UNUSED_MACROS,
+    Warn,
+    "detects macros that were not used"
+}
+
+declare_lint! {
     pub WARNINGS,
     Warn,
     "mass-change the level for lints which produce warnings"
@@ -259,6 +265,7 @@ impl LintPass for HardwiredLints {
             DEAD_CODE,
             UNREACHABLE_CODE,
             UNREACHABLE_PATTERNS,
+            UNUSED_MACROS,
             WARNINGS,
             UNUSED_FEATURES,
             STABLE_FEATURES,
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 8fddbe110b0..eff5d2b2f37 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -699,6 +699,8 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
 
         let krate = ecx.monotonic_expander().expand_crate(krate);
 
+        ecx.check_unused_macros();
+
         let mut missing_fragment_specifiers: Vec<_> =
             ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect();
         missing_fragment_specifiers.sort();
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 2d0b5a6a51c..479c7206cb4 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -171,7 +171,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                     UNUSED_MUST_USE,
                     UNUSED_UNSAFE,
                     PATH_STATEMENTS,
-                    UNUSED_ATTRIBUTES);
+                    UNUSED_ATTRIBUTES,
+                    UNUSED_MACROS);
 
     // Guidelines for creating a future incompatibility lint:
     //
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index c4512cb38c4..f78dd4890e2 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1195,6 +1195,12 @@ pub struct Resolver<'a> {
     pub whitelisted_legacy_custom_derives: Vec<Name>,
     pub found_unresolved_macro: bool,
 
+    // List of macros that we need to warn about as being unused.
+    // The bool is true if the macro is unused, and false if its used.
+    // Setting a bool to false should be much faster than removing a single
+    // element from a FxHashSet.
+    unused_macros: FxHashMap<DefId, bool>,
+
     // Maps the `Mark` of an expansion to its containing module or block.
     invocations: FxHashMap<Mark, &'a InvocationData<'a>>,
 
@@ -1400,6 +1406,7 @@ impl<'a> Resolver<'a> {
             potentially_unused_imports: Vec::new(),
             struct_constructors: DefIdMap(),
             found_unresolved_macro: false,
+            unused_macros: FxHashMap(),
         }
     }
 
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index c08421cb937..29ca163b0b4 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -16,7 +16,7 @@ use resolve_imports::ImportResolver;
 use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex};
 use rustc::hir::def::{Def, Export};
 use rustc::hir::map::{self, DefCollector};
-use rustc::ty;
+use rustc::{ty, lint};
 use syntax::ast::{self, Name, Ident};
 use syntax::attr::{self, HasAttrs};
 use syntax::errors::DiagnosticBuilder;
@@ -291,12 +291,35 @@ impl<'a> base::Resolver for Resolver<'a> {
             },
         };
         self.macro_defs.insert(invoc.expansion_data.mark, def.def_id());
+        self.unused_macros.get_mut(&def.def_id()).map(|m| *m = false);
         Ok(Some(self.get_macro(def)))
     }
 
     fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
                      -> Result<Rc<SyntaxExtension>, Determinacy> {
-        self.resolve_macro_to_def(scope, path, kind, force).map(|def| self.get_macro(def))
+        self.resolve_macro_to_def(scope, path, kind, force).map(|def| {
+            self.unused_macros.get_mut(&def.def_id()).map(|m| *m = false);
+            self.get_macro(def)
+        })
+    }
+
+    fn check_unused_macros(&self) {
+        for (did, _) in self.unused_macros.iter().filter(|&(_, b)| *b) {
+            let span = match *self.macro_map[did] {
+                           SyntaxExtension::NormalTT(_, sp, _) => sp,
+                           SyntaxExtension::IdentTT(_, sp, _) => sp,
+                           _ => None
+                       };
+            if let Some(span) = span {
+                let lint = lint::builtin::UNUSED_MACROS;
+                let msg = "unused macro".to_string();
+                // We are using CRATE_NODE_ID here even though its inaccurate, as we
+                // sadly don't have the NodeId of the macro definition.
+                self.session.add_lint(lint, ast::CRATE_NODE_ID, span, msg);
+            } else {
+                bug!("attempted to create unused macro error, but span not available");
+            }
+        }
     }
 }
 
@@ -687,6 +710,8 @@ impl<'a> Resolver<'a> {
         if attr::contains_name(&item.attrs, "macro_export") {
             let def = Def::Macro(def_id, MacroKind::Bang);
             self.macro_exports.push(Export { name: ident.name, def: def, span: item.span });
+        } else {
+            self.unused_macros.insert(def_id, true);
         }
     }
 
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index f731c5abdd6..b0253ec3905 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -589,6 +589,7 @@ pub trait Resolver {
                      -> Result<Option<Rc<SyntaxExtension>>, Determinacy>;
     fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
                      -> Result<Rc<SyntaxExtension>, Determinacy>;
+    fn check_unused_macros(&self);
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -618,6 +619,7 @@ impl Resolver for DummyResolver {
                      _force: bool) -> Result<Rc<SyntaxExtension>, Determinacy> {
         Err(Determinacy::Determined)
     }
+    fn check_unused_macros(&self) {}
 }
 
 #[derive(Clone)]
@@ -800,6 +802,10 @@ impl<'a> ExtCtxt<'a> {
     pub fn name_of(&self, st: &str) -> ast::Name {
         Symbol::intern(st)
     }
+
+    pub fn check_unused_macros(&self) {
+        self.resolver.check_unused_macros();
+    }
 }
 
 /// Extract a string literal from the macro expanded version of `expr`,