Skip to content

Commit

Permalink
Add lint for unused macros
Browse files Browse the repository at this point in the history
  • Loading branch information
est31 committed May 13, 2017
1 parent ef3ec5e commit df188b8
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 3 deletions.
7 changes: 7 additions & 0 deletions src/librustc/lint/builtin.rs
Expand Up @@ -76,6 +76,12 @@ declare_lint! {
"detects unreachable patterns"
}

declare_lint! {
pub UNUSED_MACROS,
Warn,
"detects macros that were not used"
}

declare_lint! {
pub WARNINGS,
Warn,
Expand Down Expand Up @@ -259,6 +265,7 @@ impl LintPass for HardwiredLints {
DEAD_CODE,
UNREACHABLE_CODE,
UNREACHABLE_PATTERNS,
UNUSED_MACROS,
WARNINGS,
UNUSED_FEATURES,
STABLE_FEATURES,
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_driver/driver.rs
Expand Up @@ -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();
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_lint/lib.rs
Expand Up @@ -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:
//
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_resolve/lib.rs
Expand Up @@ -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>>,

Expand Down Expand Up @@ -1400,6 +1406,7 @@ impl<'a> Resolver<'a> {
potentially_unused_imports: Vec::new(),
struct_constructors: DefIdMap(),
found_unresolved_macro: false,
unused_macros: FxHashMap(),
}
}

Expand Down
29 changes: 27 additions & 2 deletions src/librustc_resolve/macros.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
}
}
}
}

Expand Down Expand Up @@ -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);
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/libsyntax/ext/base.rs
Expand Up @@ -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)]
Expand Down Expand Up @@ -618,6 +619,7 @@ impl Resolver for DummyResolver {
_force: bool) -> Result<Rc<SyntaxExtension>, Determinacy> {
Err(Determinacy::Determined)
}
fn check_unused_macros(&self) {}
}

#[derive(Clone)]
Expand Down Expand Up @@ -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`,
Expand Down

0 comments on commit df188b8

Please sign in to comment.