Skip to content

Commit df188b8

Browse files
committed
Add lint for unused macros
1 parent ef3ec5e commit df188b8

File tree

6 files changed

+51
-3
lines changed

6 files changed

+51
-3
lines changed

src/librustc/lint/builtin.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ declare_lint! {
7676
"detects unreachable patterns"
7777
}
7878

79+
declare_lint! {
80+
pub UNUSED_MACROS,
81+
Warn,
82+
"detects macros that were not used"
83+
}
84+
7985
declare_lint! {
8086
pub WARNINGS,
8187
Warn,
@@ -259,6 +265,7 @@ impl LintPass for HardwiredLints {
259265
DEAD_CODE,
260266
UNREACHABLE_CODE,
261267
UNREACHABLE_PATTERNS,
268+
UNUSED_MACROS,
262269
WARNINGS,
263270
UNUSED_FEATURES,
264271
STABLE_FEATURES,

src/librustc_driver/driver.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,8 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
699699

700700
let krate = ecx.monotonic_expander().expand_crate(krate);
701701

702+
ecx.check_unused_macros();
703+
702704
let mut missing_fragment_specifiers: Vec<_> =
703705
ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect();
704706
missing_fragment_specifiers.sort();

src/librustc_lint/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
171171
UNUSED_MUST_USE,
172172
UNUSED_UNSAFE,
173173
PATH_STATEMENTS,
174-
UNUSED_ATTRIBUTES);
174+
UNUSED_ATTRIBUTES,
175+
UNUSED_MACROS);
175176

176177
// Guidelines for creating a future incompatibility lint:
177178
//

src/librustc_resolve/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,6 +1195,12 @@ pub struct Resolver<'a> {
11951195
pub whitelisted_legacy_custom_derives: Vec<Name>,
11961196
pub found_unresolved_macro: bool,
11971197

1198+
// List of macros that we need to warn about as being unused.
1199+
// The bool is true if the macro is unused, and false if its used.
1200+
// Setting a bool to false should be much faster than removing a single
1201+
// element from a FxHashSet.
1202+
unused_macros: FxHashMap<DefId, bool>,
1203+
11981204
// Maps the `Mark` of an expansion to its containing module or block.
11991205
invocations: FxHashMap<Mark, &'a InvocationData<'a>>,
12001206

@@ -1400,6 +1406,7 @@ impl<'a> Resolver<'a> {
14001406
potentially_unused_imports: Vec::new(),
14011407
struct_constructors: DefIdMap(),
14021408
found_unresolved_macro: false,
1409+
unused_macros: FxHashMap(),
14031410
}
14041411
}
14051412

src/librustc_resolve/macros.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use resolve_imports::ImportResolver;
1616
use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex};
1717
use rustc::hir::def::{Def, Export};
1818
use rustc::hir::map::{self, DefCollector};
19-
use rustc::ty;
19+
use rustc::{ty, lint};
2020
use syntax::ast::{self, Name, Ident};
2121
use syntax::attr::{self, HasAttrs};
2222
use syntax::errors::DiagnosticBuilder;
@@ -291,12 +291,35 @@ impl<'a> base::Resolver for Resolver<'a> {
291291
},
292292
};
293293
self.macro_defs.insert(invoc.expansion_data.mark, def.def_id());
294+
self.unused_macros.get_mut(&def.def_id()).map(|m| *m = false);
294295
Ok(Some(self.get_macro(def)))
295296
}
296297

297298
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
298299
-> Result<Rc<SyntaxExtension>, Determinacy> {
299-
self.resolve_macro_to_def(scope, path, kind, force).map(|def| self.get_macro(def))
300+
self.resolve_macro_to_def(scope, path, kind, force).map(|def| {
301+
self.unused_macros.get_mut(&def.def_id()).map(|m| *m = false);
302+
self.get_macro(def)
303+
})
304+
}
305+
306+
fn check_unused_macros(&self) {
307+
for (did, _) in self.unused_macros.iter().filter(|&(_, b)| *b) {
308+
let span = match *self.macro_map[did] {
309+
SyntaxExtension::NormalTT(_, sp, _) => sp,
310+
SyntaxExtension::IdentTT(_, sp, _) => sp,
311+
_ => None
312+
};
313+
if let Some(span) = span {
314+
let lint = lint::builtin::UNUSED_MACROS;
315+
let msg = "unused macro".to_string();
316+
// We are using CRATE_NODE_ID here even though its inaccurate, as we
317+
// sadly don't have the NodeId of the macro definition.
318+
self.session.add_lint(lint, ast::CRATE_NODE_ID, span, msg);
319+
} else {
320+
bug!("attempted to create unused macro error, but span not available");
321+
}
322+
}
300323
}
301324
}
302325

@@ -687,6 +710,8 @@ impl<'a> Resolver<'a> {
687710
if attr::contains_name(&item.attrs, "macro_export") {
688711
let def = Def::Macro(def_id, MacroKind::Bang);
689712
self.macro_exports.push(Export { name: ident.name, def: def, span: item.span });
713+
} else {
714+
self.unused_macros.insert(def_id, true);
690715
}
691716
}
692717

src/libsyntax/ext/base.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ pub trait Resolver {
589589
-> Result<Option<Rc<SyntaxExtension>>, Determinacy>;
590590
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
591591
-> Result<Rc<SyntaxExtension>, Determinacy>;
592+
fn check_unused_macros(&self);
592593
}
593594

594595
#[derive(Copy, Clone, Debug)]
@@ -618,6 +619,7 @@ impl Resolver for DummyResolver {
618619
_force: bool) -> Result<Rc<SyntaxExtension>, Determinacy> {
619620
Err(Determinacy::Determined)
620621
}
622+
fn check_unused_macros(&self) {}
621623
}
622624

623625
#[derive(Clone)]
@@ -800,6 +802,10 @@ impl<'a> ExtCtxt<'a> {
800802
pub fn name_of(&self, st: &str) -> ast::Name {
801803
Symbol::intern(st)
802804
}
805+
806+
pub fn check_unused_macros(&self) {
807+
self.resolver.check_unused_macros();
808+
}
803809
}
804810

805811
/// Extract a string literal from the macro expanded version of `expr`,

0 commit comments

Comments
 (0)