Skip to content

Commit 6ea1888

Browse files
Add lint for redundant imports
Co-authored-by: Stephan Schauerte <stephan.schauerte@gmail.com>
1 parent 52e8856 commit 6ea1888

File tree

4 files changed

+129
-1
lines changed

4 files changed

+129
-1
lines changed

src/librustc/lint/builtin.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,12 @@ declare_lint! {
392392
"nested occurrence of `impl Trait` type"
393393
}
394394

395+
declare_lint! {
396+
pub REDUNDANT_IMPORT,
397+
Warn,
398+
"redundant import"
399+
}
400+
395401
/// Does nothing as a lint pass, but registers some `Lint`s
396402
/// that are used by other parts of the compiler.
397403
#[derive(Copy, Clone)]

src/librustc_resolve/resolve_imports.rs

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,19 @@ use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyErro
77
use crate::{Resolver, Segment};
88
use crate::{names_to_string, module_to_string};
99
use crate::{resolve_error, ResolutionError, Suggestion};
10+
use crate::ModuleKind;
1011
use crate::macros::ParentScope;
1112

1213
use errors::Applicability;
1314

1415
use rustc_data_structures::ptr_key::PtrKey;
1516
use rustc::ty;
1617
use rustc::lint::builtin::BuiltinLintDiagnostics;
17-
use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE};
18+
use rustc::lint::builtin::{
19+
DUPLICATE_MACRO_EXPORTS,
20+
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
21+
REDUNDANT_IMPORT,
22+
};
1823
use rustc::hir::def_id::{CrateNum, DefId};
1924
use rustc::hir::def::*;
2025
use rustc::session::DiagnosticMessageId;
@@ -1230,10 +1235,96 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
12301235
import[ns] = Some(PathResolution::new(def));
12311236
});
12321237

1238+
self.check_for_redundant_imports(
1239+
ident,
1240+
directive,
1241+
source_bindings,
1242+
target_bindings,
1243+
target,
1244+
);
1245+
12331246
debug!("(resolving single import) successfully resolved import");
12341247
None
12351248
}
12361249

1250+
fn check_for_redundant_imports(
1251+
&mut self,
1252+
ident: Ident,
1253+
directive: &'b ImportDirective<'b>,
1254+
source_bindings: &PerNS<Cell<Result<&'b NameBinding<'b>, Determinacy>>>,
1255+
target_bindings: &PerNS<Cell<Option<&'b NameBinding<'b>>>>,
1256+
target: Ident,
1257+
) {
1258+
// Check if we are at the root of a macro expansion and skip if we are.
1259+
if directive.parent_scope.expansion != Mark::root() {
1260+
return;
1261+
}
1262+
1263+
if let ModuleKind::Def(_, _) = directive.parent_scope.module.kind {
1264+
return;
1265+
}
1266+
1267+
let mut is_redundant = PerNS {
1268+
value_ns: None,
1269+
type_ns: None,
1270+
macro_ns: None,
1271+
};
1272+
1273+
let mut redundant_span = PerNS {
1274+
value_ns: None,
1275+
type_ns: None,
1276+
macro_ns: None,
1277+
};
1278+
1279+
self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
1280+
if binding.def() == Def::Err {
1281+
return;
1282+
}
1283+
1284+
let orig_blacklisted_binding = mem::replace(
1285+
&mut this.blacklisted_binding,
1286+
target_bindings[ns].get()
1287+
);
1288+
1289+
match this.early_resolve_ident_in_lexical_scope(
1290+
target,
1291+
ScopeSet::Import(ns),
1292+
&directive.parent_scope,
1293+
false,
1294+
false,
1295+
directive.span,
1296+
) {
1297+
Ok(other_binding) => {
1298+
is_redundant[ns] = Some(binding.def() == other_binding.def());
1299+
redundant_span[ns] = Some(other_binding.span);
1300+
}
1301+
Err(_) => is_redundant[ns] = Some(false)
1302+
}
1303+
1304+
this.blacklisted_binding = orig_blacklisted_binding;
1305+
});
1306+
1307+
if !is_redundant.is_empty() &&
1308+
is_redundant.present_items().all(|is_redundant| is_redundant)
1309+
{
1310+
self.session.buffer_lint(
1311+
REDUNDANT_IMPORT,
1312+
directive.id,
1313+
directive.span,
1314+
&format!("the item `{}` is imported redundantly", ident),
1315+
);
1316+
1317+
for span in redundant_span.present_items() {
1318+
self.session.buffer_lint(
1319+
REDUNDANT_IMPORT,
1320+
directive.id,
1321+
span,
1322+
"another import"
1323+
);
1324+
}
1325+
}
1326+
}
1327+
12371328
fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) {
12381329
let module = match directive.imported_module.get().unwrap() {
12391330
ModuleOrUniformRoot::Module(module) => module,

src/test/ui/lint/use-redundant.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// compile-pass
2+
3+
use crate::foo::Bar; //~ WARNING first import
4+
5+
mod foo {
6+
pub type Bar = i32;
7+
}
8+
9+
fn baz() -> Bar {
10+
3
11+
}
12+
13+
fn main() {
14+
use crate::foo::Bar; //~ WARNING redundant import
15+
let _a: Bar = 3;
16+
baz();
17+
}

src/test/ui/lint/use-redundant.stderr

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
warning: the item `Bar` is imported redundantly
2+
--> $DIR/use-redundant.rs:14:9
3+
|
4+
LL | use crate::foo::Bar; //~ WARNING redundant import
5+
| ^^^^^^^^^^^^^^^
6+
|
7+
= note: #[warn(redundant_import)] on by default
8+
9+
warning: another import
10+
--> $DIR/use-redundant.rs:3:5
11+
|
12+
LL | use crate::foo::Bar; //~ WARNING first import
13+
| ^^^^^^^^^^^^^^^
14+

0 commit comments

Comments
 (0)