Skip to content

Commit 29d68ed

Browse files
Add lint for redundant imports
Co-authored-by: Stephan Schauerte <[email protected]>
1 parent befeeb7 commit 29d68ed

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;
@@ -1227,10 +1232,96 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
12271232
import[ns] = Some(PathResolution::new(def));
12281233
});
12291234

1235+
self.check_for_redundant_imports(
1236+
ident,
1237+
directive,
1238+
source_bindings,
1239+
target_bindings,
1240+
target,
1241+
);
1242+
12301243
debug!("(resolving single import) successfully resolved import");
12311244
None
12321245
}
12331246

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