Skip to content

Commit 8881504

Browse files
authored
Rollup merge of rust-lang#58805 - fabric-and-ink:redundant_import, r=petrochenkov
Lint for redundant imports This is an attempt at solving rust-lang#10178. The changes are suggested by `@petrochenkov`. I need some feedback on how to continue, since I get a lot of false positives in macro invocations in `libcore`. I suspect that the test ``` ... if directive.parent_scope.expansion == Mark::root() { return; } ... ``` is wrong. But I don't know how to check correctly if I am at a macro expansion root – given that this is the reason for the errors in the first place. Todos: - [x] Solve problem with false positives - [x] Turn hard error into warning - [x] Add unit tests Closes rust-lang#10178
2 parents 1dce36e + caa37d8 commit 8881504

File tree

30 files changed

+199
-42
lines changed

30 files changed

+199
-42
lines changed

src/liballoc/borrow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ impl<T> ToOwned for T
135135
/// Another example showing how to keep `Cow` in a struct:
136136
///
137137
/// ```
138-
/// use std::borrow::{Cow, ToOwned};
138+
/// use std::borrow::Cow;
139139
///
140140
/// struct Items<'a, X: 'a> where [X]: ToOwned<Owned = Vec<X>> {
141141
/// values: Cow<'a, [X]>,

src/libcore/cell.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,6 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
14231423
///
14241424
/// ```
14251425
/// use std::cell::UnsafeCell;
1426-
/// use std::marker::Sync;
14271426
///
14281427
/// # #[allow(dead_code)]
14291428
/// struct NotThreadSafe<T> {

src/librustc/lint/builtin.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ pub enum BuiltinLintDiagnostics {
482482
UnknownCrateTypes(Span, String, String),
483483
UnusedImports(String, Vec<(Span, String)>),
484484
NestedImplTrait { outer_impl_trait_span: Span, inner_impl_trait_span: Span },
485+
RedundantImport(Vec<(Span, bool)>, ast::Ident),
485486
}
486487

487488
impl BuiltinLintDiagnostics {
@@ -578,6 +579,15 @@ impl BuiltinLintDiagnostics {
578579
db.span_label(outer_impl_trait_span, "outer `impl Trait`");
579580
db.span_label(inner_impl_trait_span, "nested `impl Trait` here");
580581
}
582+
BuiltinLintDiagnostics::RedundantImport(spans, ident) => {
583+
for (span, is_imported) in spans {
584+
let introduced = if is_imported { "imported" } else { "defined" };
585+
db.span_label(
586+
span,
587+
format!("the item `{}` is already {} here", ident, introduced)
588+
);
589+
}
590+
}
581591
}
582592
}
583593
}

src/librustc/ty/query/on_disk_cache.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,6 @@ impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E>
778778
value: &V)
779779
-> Result<(), E::Error>
780780
{
781-
use crate::ty::codec::TyEncoder;
782781
let start_pos = self.position();
783782

784783
tag.encode(self)?;

src/librustc_codegen_llvm/context.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,6 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
377377
// Returns a Value of the "eh_unwind_resume" lang item if one is defined,
378378
// otherwise declares it as an external function.
379379
fn eh_unwind_resume(&self) -> &'ll Value {
380-
use crate::attributes;
381380
let unwresume = &self.eh_unwind_resume;
382381
if let Some(llfn) = unwresume.get() {
383382
return llfn;

src/librustc_codegen_ssa/mir/rvalue.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,6 @@ fn cast_int_to_float<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
750750
// All inputs greater or equal to (f32::MAX + 0.5 ULP) are rounded to infinity,
751751
// and for everything else LLVM's uitofp works just fine.
752752
use rustc_apfloat::ieee::Single;
753-
use rustc_apfloat::Float;
754753
const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1)
755754
<< (Single::MAX_EXP - Single::PRECISION as i16);
756755
let max = bx.cx().const_uint_big(int_ty, MAX_F32_PLUS_HALF_ULP);

src/librustc_errors/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ impl CodeSuggestion {
155155
/// Returns the assembled code suggestions and whether they should be shown with an underline.
156156
pub fn splice_lines(&self, cm: &SourceMapperDyn)
157157
-> Vec<(String, Vec<SubstitutionPart>)> {
158-
use syntax_pos::{CharPos, Loc, Pos};
158+
use syntax_pos::{CharPos, Pos};
159159

160160
fn push_trailing(buf: &mut String,
161161
line_opt: Option<&Cow<'_, str>>,

src/librustc_interface/profile/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ fn total_duration(traces: &[trace::Rec]) -> Duration {
6161
fn profile_queries_thread(r: Receiver<ProfileQueriesMsg>) {
6262
use self::trace::*;
6363
use std::fs::File;
64-
use std::time::{Instant};
6564

6665
let mut profq_msgs: Vec<ProfileQueriesMsg> = vec![];
6766
let mut frame: StackFrame = StackFrame { parse_st: ParseState::Clear, traces: vec![] };

src/librustc_mir/hair/pattern/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,6 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
427427

428428
let mut kind = match (lo, hi) {
429429
(PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => {
430-
use std::cmp::Ordering;
431430
let cmp = compare_const_vals(
432431
self.tcx,
433432
lo,

src/librustc_mir/interpret/operator.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
331331
val: ImmTy<'tcx, M::PointerTag>,
332332
) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
333333
use rustc::mir::UnOp::*;
334-
use rustc_apfloat::ieee::{Single, Double};
335-
use rustc_apfloat::Float;
336334

337335
let layout = val.layout;
338336
let val = val.to_scalar()?;

src/librustc_resolve/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1733,7 +1733,6 @@ impl<'a> Resolver<'a> {
17331733
/// just that an error occurred.
17341734
pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool)
17351735
-> Result<hir::Path, ()> {
1736-
use std::iter;
17371736
let mut errored = false;
17381737

17391738
let path = if path_str.starts_with("::") {

src/librustc_resolve/resolve_imports.rs

Lines changed: 93 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+
UNUSED_IMPORTS,
22+
};
1823
use rustc::hir::def_id::{CrateNum, DefId};
1924
use rustc::hir::def::*;
2025
use rustc::session::DiagnosticMessageId;
@@ -1230,10 +1235,97 @@ 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+
// Skip if the import was produced by a macro.
1259+
if directive.parent_scope.expansion != Mark::root() {
1260+
return;
1261+
}
1262+
1263+
// Skip if we are inside a named module (in contrast to an anonymous
1264+
// module defined by a block).
1265+
if let ModuleKind::Def(_, _) = directive.parent_scope.module.kind {
1266+
return;
1267+
}
1268+
1269+
let mut is_redundant = PerNS {
1270+
value_ns: None,
1271+
type_ns: None,
1272+
macro_ns: None,
1273+
};
1274+
1275+
let mut redundant_span = PerNS {
1276+
value_ns: None,
1277+
type_ns: None,
1278+
macro_ns: None,
1279+
};
1280+
1281+
self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
1282+
if binding.def() == Def::Err {
1283+
return;
1284+
}
1285+
1286+
let orig_blacklisted_binding = mem::replace(
1287+
&mut this.blacklisted_binding,
1288+
target_bindings[ns].get()
1289+
);
1290+
1291+
match this.early_resolve_ident_in_lexical_scope(
1292+
target,
1293+
ScopeSet::Import(ns),
1294+
&directive.parent_scope,
1295+
false,
1296+
false,
1297+
directive.span,
1298+
) {
1299+
Ok(other_binding) => {
1300+
is_redundant[ns] = Some(
1301+
binding.def() == other_binding.def()
1302+
&& !other_binding.is_ambiguity()
1303+
);
1304+
redundant_span[ns] =
1305+
Some((other_binding.span, other_binding.is_import()));
1306+
}
1307+
Err(_) => is_redundant[ns] = Some(false)
1308+
}
1309+
1310+
this.blacklisted_binding = orig_blacklisted_binding;
1311+
});
1312+
1313+
if !is_redundant.is_empty() &&
1314+
is_redundant.present_items().all(|is_redundant| is_redundant)
1315+
{
1316+
self.session.buffer_lint_with_diagnostic(
1317+
UNUSED_IMPORTS,
1318+
directive.id,
1319+
directive.span,
1320+
&format!("the item `{}` is imported redundantly", ident),
1321+
BuiltinLintDiagnostics::RedundantImport(
1322+
redundant_span.present_items().collect(),
1323+
ident,
1324+
),
1325+
);
1326+
}
1327+
}
1328+
12371329
fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) {
12381330
let module = match directive.imported_module.get().unwrap() {
12391331
ModuleOrUniformRoot::Module(module) => module,

src/librustc_traits/lowering/environment.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ crate fn environment<'a, 'tcx>(
190190
tcx: TyCtxt<'a, 'tcx, 'tcx>,
191191
def_id: DefId
192192
) -> Environment<'tcx> {
193-
use super::{Lower, IntoFromEnvGoal};
193+
use super::IntoFromEnvGoal;
194194
use rustc::hir::{Node, TraitItemKind, ImplItemKind, ItemKind, ForeignItemKind};
195195

196196
debug!("environment(def_id = {:?})", def_id);

src/librustc_typeck/check/wfcheck.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,6 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
420420
def_id: DefId,
421421
return_ty: Option<Ty<'tcx>>,
422422
) {
423-
use ty::subst::Subst;
424-
use rustc::ty::TypeFoldable;
425-
426423
let predicates = fcx.tcx.predicates_of(def_id);
427424

428425
let generics = tcx.generics_of(def_id);
@@ -1010,8 +1007,6 @@ fn check_false_global_bounds<'a, 'gcx, 'tcx>(
10101007
span: Span,
10111008
id: hir::HirId)
10121009
{
1013-
use rustc::ty::TypeFoldable;
1014-
10151010
let empty_env = ty::ParamEnv::empty();
10161011

10171012
let def_id = fcx.tcx.hir().local_def_id_from_hir_id(id);

src/librustdoc/html/render.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,8 +1061,6 @@ themePicker.onblur = handleThemeButtonsBlur;
10611061
}
10621062

10631063
if cx.shared.include_sources {
1064-
use std::path::Component;
1065-
10661064
let mut hierarchy = Hierarchy::new(OsString::new());
10671065
for source in cx.shared.local_sources.iter()
10681066
.filter_map(|p| p.0.strip_prefix(&cx.shared.src_root)

src/librustdoc/test.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,7 @@ pub fn make_test(s: &str,
371371
// Uses libsyntax to parse the doctest and find if there's a main fn and the extern
372372
// crate already is included.
373373
let (already_has_main, already_has_extern_crate, found_macro) = crate::syntax::with_globals(|| {
374-
use crate::syntax::{ast, parse::{self, ParseSess}, source_map::FilePathMapping};
375-
use crate::syntax_pos::FileName;
374+
use crate::syntax::{parse::{self, ParseSess}, source_map::FilePathMapping};
376375
use errors::emitter::EmitterWriter;
377376
use errors::Handler;
378377

src/test/run-pass/binding/match-arm-statics.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ pub mod glfw {
4545
}
4646

4747
fn issue_6533() {
48-
use glfw;
49-
5048
fn action_to_str(state: glfw::InputState) -> &'static str {
5149
use glfw::{RELEASE, PRESS, REPEAT};
5250
match state {

src/test/run-pass/ifmt.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,6 @@ pub fn main() {
238238
// Basic test to make sure that we can invoke the `write!` macro with an
239239
// fmt::Write instance.
240240
fn test_write() {
241-
use std::fmt::Write;
242241
let mut buf = String::new();
243242
write!(&mut buf, "{}", 3);
244243
{
@@ -267,7 +266,6 @@ fn test_print() {
267266
// Just make sure that the macros are defined, there's not really a lot that we
268267
// can do with them just yet (to test the output)
269268
fn test_format_args() {
270-
use std::fmt::Write;
271269
let mut buf = String::new();
272270
{
273271
let w = &mut buf;

src/test/run-pass/invalid_const_promotion.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ fn foo() {
2525
#[cfg(unix)]
2626
fn check_status(status: std::process::ExitStatus)
2727
{
28-
use libc;
2928
use std::os::unix::process::ExitStatusExt;
3029

3130
assert!(status.signal() == Some(libc::SIGILL)

src/test/run-pass/issues/issue-38556.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,5 @@ macro_rules! reexport {
99
reexport!();
1010

1111
fn main() {
12-
use Bar;
1312
fn f(_: Bar) {}
1413
}

src/test/run-pass/issues/issue-39367.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ fn arena() -> &'static ArenaSet<Vec<u8>> {
1515
fn require_sync<T: Sync>(_: &T) { }
1616
unsafe fn __stability() -> &'static ArenaSet<Vec<u8>> {
1717
use std::mem::transmute;
18-
use std::boxed::Box;
1918
static mut DATA: *const ArenaSet<Vec<u8>> = 0 as *const ArenaSet<Vec<u8>>;
2019

2120
static mut ONCE: Once = ONCE_INIT;

src/test/run-pass/out-of-stack.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ fn loud_recurse() {
3636
#[cfg(unix)]
3737
fn check_status(status: std::process::ExitStatus)
3838
{
39-
use libc;
4039
use std::os::unix::process::ExitStatusExt;
4140

4241
assert!(!status.success());

src/test/run-pass/rfcs/rfc-2126-extern-absolute-paths/basic.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// compile-flags:--extern xcrate
55
// edition:2018
66

7+
#![allow(unused_imports)]
8+
79
use xcrate::Z;
810

911
fn f() {

src/test/run-pass/traits/traits-multidispatch-infer-convert-target.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ where T : Convert<U>
2828
}
2929

3030
fn main() {
31-
use std::default::Default;
3231
// T = i16, U = u32
3332
test(22_i16, Default::default(), 2, 4);
3433

src/test/ui/lint/lint-unused-imports.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ mod bar {
6666

6767
fn g() {
6868
use self::g; //~ ERROR unused import: `self::g`
69+
//~^ ERROR the item `g` is imported redundantly
6970
fn f() {
7071
self::g();
7172
}
@@ -75,6 +76,7 @@ fn g() {
7576
#[allow(unused_variables)]
7677
fn h() {
7778
use test2::foo; //~ ERROR unused import: `test2::foo`
79+
//~^ ERROR the item `foo` is imported redundantly
7880
let foo = 0;
7981
}
8082

0 commit comments

Comments
 (0)