Rollup merge of #58805 - fabric-and-ink:redundant_import, r=petrochenkov
Lint for redundant imports Add lint for redundant imports. The changes are suggested by @petrochenkov. Closes #10178.
This commit is contained in:
commit
dffdd8f728
30 changed files with 198 additions and 42 deletions
|
@ -135,7 +135,7 @@ impl<T> ToOwned for T
|
|||
/// Another example showing how to keep `Cow` in a struct:
|
||||
///
|
||||
/// ```
|
||||
/// use std::borrow::{Cow, ToOwned};
|
||||
/// use std::borrow::Cow;
|
||||
///
|
||||
/// struct Items<'a, X: 'a> where [X]: ToOwned<Owned = Vec<X>> {
|
||||
/// values: Cow<'a, [X]>,
|
||||
|
|
|
@ -1421,7 +1421,6 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
|
|||
///
|
||||
/// ```
|
||||
/// use std::cell::UnsafeCell;
|
||||
/// use std::marker::Sync;
|
||||
///
|
||||
/// # #[allow(dead_code)]
|
||||
/// struct NotThreadSafe<T> {
|
||||
|
|
|
@ -483,6 +483,7 @@ pub enum BuiltinLintDiagnostics {
|
|||
UnknownCrateTypes(Span, String, String),
|
||||
UnusedImports(String, Vec<(Span, String)>),
|
||||
NestedImplTrait { outer_impl_trait_span: Span, inner_impl_trait_span: Span },
|
||||
RedundantImport(Vec<(Span, bool)>, ast::Ident),
|
||||
}
|
||||
|
||||
impl BuiltinLintDiagnostics {
|
||||
|
@ -579,6 +580,15 @@ impl BuiltinLintDiagnostics {
|
|||
db.span_label(outer_impl_trait_span, "outer `impl Trait`");
|
||||
db.span_label(inner_impl_trait_span, "nested `impl Trait` here");
|
||||
}
|
||||
BuiltinLintDiagnostics::RedundantImport(spans, ident) => {
|
||||
for (span, is_imported) in spans {
|
||||
let introduced = if is_imported { "imported" } else { "defined" };
|
||||
db.span_label(
|
||||
span,
|
||||
format!("the item `{}` is already {} here", ident, introduced)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -777,7 +777,6 @@ impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E>
|
|||
value: &V)
|
||||
-> Result<(), E::Error>
|
||||
{
|
||||
use crate::ty::codec::TyEncoder;
|
||||
let start_pos = self.position();
|
||||
|
||||
tag.encode(self)?;
|
||||
|
|
|
@ -372,7 +372,6 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
// Returns a Value of the "eh_unwind_resume" lang item if one is defined,
|
||||
// otherwise declares it as an external function.
|
||||
fn eh_unwind_resume(&self) -> &'ll Value {
|
||||
use crate::attributes;
|
||||
let unwresume = &self.eh_unwind_resume;
|
||||
if let Some(llfn) = unwresume.get() {
|
||||
return llfn;
|
||||
|
|
|
@ -732,7 +732,6 @@ fn cast_int_to_float<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// All inputs greater or equal to (f32::MAX + 0.5 ULP) are rounded to infinity,
|
||||
// and for everything else LLVM's uitofp works just fine.
|
||||
use rustc_apfloat::ieee::Single;
|
||||
use rustc_apfloat::Float;
|
||||
const MAX_F32_PLUS_HALF_ULP: u128 = ((1 << (Single::PRECISION + 1)) - 1)
|
||||
<< (Single::MAX_EXP - Single::PRECISION as i16);
|
||||
let max = bx.cx().const_uint_big(int_ty, MAX_F32_PLUS_HALF_ULP);
|
||||
|
|
|
@ -77,7 +77,6 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
|
|||
}
|
||||
|
||||
fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
|
||||
use syntax_pos::DUMMY_SP;
|
||||
if ty.is_sized(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ impl CodeSuggestion {
|
|||
/// Returns the assembled code suggestions and whether they should be shown with an underline.
|
||||
pub fn splice_lines(&self, cm: &SourceMapperDyn)
|
||||
-> Vec<(String, Vec<SubstitutionPart>)> {
|
||||
use syntax_pos::{CharPos, Loc, Pos};
|
||||
use syntax_pos::{CharPos, Pos};
|
||||
|
||||
fn push_trailing(buf: &mut String,
|
||||
line_opt: Option<&Cow<'_, str>>,
|
||||
|
|
|
@ -62,7 +62,6 @@ fn total_duration(traces: &[trace::Rec]) -> Duration {
|
|||
fn profile_queries_thread(r: Receiver<ProfileQueriesMsg>) {
|
||||
use self::trace::*;
|
||||
use std::fs::File;
|
||||
use std::time::{Instant};
|
||||
|
||||
let mut profq_msgs: Vec<ProfileQueriesMsg> = vec![];
|
||||
let mut frame: StackFrame = StackFrame { parse_st: ParseState::Clear, traces: vec![] };
|
||||
|
|
|
@ -427,7 +427,6 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
|
|||
|
||||
let mut kind = match (lo, hi) {
|
||||
(PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => {
|
||||
use std::cmp::Ordering;
|
||||
let cmp = compare_const_vals(
|
||||
self.tcx,
|
||||
lo,
|
||||
|
|
|
@ -331,8 +331,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
|
|||
val: ImmTy<'tcx, M::PointerTag>,
|
||||
) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
|
||||
use rustc::mir::UnOp::*;
|
||||
use rustc_apfloat::ieee::{Single, Double};
|
||||
use rustc_apfloat::Float;
|
||||
|
||||
let layout = val.layout;
|
||||
let val = val.to_scalar()?;
|
||||
|
|
|
@ -1738,7 +1738,6 @@ impl<'a> Resolver<'a> {
|
|||
/// just that an error occurred.
|
||||
pub fn resolve_str_path_error(&mut self, span: Span, path_str: &str, is_value: bool)
|
||||
-> Result<hir::Path, ()> {
|
||||
use std::iter;
|
||||
let mut errored = false;
|
||||
|
||||
let path = if path_str.starts_with("::") {
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyErro
|
|||
use crate::{Resolver, Segment};
|
||||
use crate::{names_to_string, module_to_string};
|
||||
use crate::{resolve_error, ResolutionError, Suggestion};
|
||||
use crate::ModuleKind;
|
||||
use crate::macros::ParentScope;
|
||||
|
||||
use errors::Applicability;
|
||||
|
@ -14,7 +15,11 @@ use errors::Applicability;
|
|||
use rustc_data_structures::ptr_key::PtrKey;
|
||||
use rustc::ty;
|
||||
use rustc::lint::builtin::BuiltinLintDiagnostics;
|
||||
use rustc::lint::builtin::{DUPLICATE_MACRO_EXPORTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE};
|
||||
use rustc::lint::builtin::{
|
||||
DUPLICATE_MACRO_EXPORTS,
|
||||
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
||||
UNUSED_IMPORTS,
|
||||
};
|
||||
use rustc::hir::def_id::{CrateNum, DefId};
|
||||
use rustc::hir::def::*;
|
||||
use rustc::session::DiagnosticMessageId;
|
||||
|
@ -1227,10 +1232,97 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
|||
import[ns] = Some(PathResolution::new(def));
|
||||
});
|
||||
|
||||
self.check_for_redundant_imports(
|
||||
ident,
|
||||
directive,
|
||||
source_bindings,
|
||||
target_bindings,
|
||||
target,
|
||||
);
|
||||
|
||||
debug!("(resolving single import) successfully resolved import");
|
||||
None
|
||||
}
|
||||
|
||||
fn check_for_redundant_imports(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
directive: &'b ImportDirective<'b>,
|
||||
source_bindings: &PerNS<Cell<Result<&'b NameBinding<'b>, Determinacy>>>,
|
||||
target_bindings: &PerNS<Cell<Option<&'b NameBinding<'b>>>>,
|
||||
target: Ident,
|
||||
) {
|
||||
// Skip if the import was produced by a macro.
|
||||
if directive.parent_scope.expansion != Mark::root() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if we are inside a named module (in contrast to an anonymous
|
||||
// module defined by a block).
|
||||
if let ModuleKind::Def(_, _) = directive.parent_scope.module.kind {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut is_redundant = PerNS {
|
||||
value_ns: None,
|
||||
type_ns: None,
|
||||
macro_ns: None,
|
||||
};
|
||||
|
||||
let mut redundant_span = PerNS {
|
||||
value_ns: None,
|
||||
type_ns: None,
|
||||
macro_ns: None,
|
||||
};
|
||||
|
||||
self.per_ns(|this, ns| if let Some(binding) = source_bindings[ns].get().ok() {
|
||||
if binding.def() == Def::Err {
|
||||
return;
|
||||
}
|
||||
|
||||
let orig_blacklisted_binding = mem::replace(
|
||||
&mut this.blacklisted_binding,
|
||||
target_bindings[ns].get()
|
||||
);
|
||||
|
||||
match this.early_resolve_ident_in_lexical_scope(
|
||||
target,
|
||||
ScopeSet::Import(ns),
|
||||
&directive.parent_scope,
|
||||
false,
|
||||
false,
|
||||
directive.span,
|
||||
) {
|
||||
Ok(other_binding) => {
|
||||
is_redundant[ns] = Some(
|
||||
binding.def() == other_binding.def()
|
||||
&& !other_binding.is_ambiguity()
|
||||
);
|
||||
redundant_span[ns] =
|
||||
Some((other_binding.span, other_binding.is_import()));
|
||||
}
|
||||
Err(_) => is_redundant[ns] = Some(false)
|
||||
}
|
||||
|
||||
this.blacklisted_binding = orig_blacklisted_binding;
|
||||
});
|
||||
|
||||
if !is_redundant.is_empty() &&
|
||||
is_redundant.present_items().all(|is_redundant| is_redundant)
|
||||
{
|
||||
self.session.buffer_lint_with_diagnostic(
|
||||
UNUSED_IMPORTS,
|
||||
directive.id,
|
||||
directive.span,
|
||||
&format!("the item `{}` is imported redundantly", ident),
|
||||
BuiltinLintDiagnostics::RedundantImport(
|
||||
redundant_span.present_items().collect(),
|
||||
ident,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) {
|
||||
let module = match directive.imported_module.get().unwrap() {
|
||||
ModuleOrUniformRoot::Module(module) => module,
|
||||
|
|
|
@ -420,9 +420,6 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
|
|||
def_id: DefId,
|
||||
return_ty: Option<Ty<'tcx>>,
|
||||
) {
|
||||
use ty::subst::Subst;
|
||||
use rustc::ty::TypeFoldable;
|
||||
|
||||
let predicates = fcx.tcx.predicates_of(def_id);
|
||||
|
||||
let generics = tcx.generics_of(def_id);
|
||||
|
@ -1010,8 +1007,6 @@ fn check_false_global_bounds<'a, 'gcx, 'tcx>(
|
|||
span: Span,
|
||||
id: hir::HirId)
|
||||
{
|
||||
use rustc::ty::TypeFoldable;
|
||||
|
||||
let empty_env = ty::ParamEnv::empty();
|
||||
|
||||
let def_id = fcx.tcx.hir().local_def_id_from_hir_id(id);
|
||||
|
|
|
@ -1069,8 +1069,6 @@ themePicker.onblur = handleThemeButtonsBlur;
|
|||
}
|
||||
|
||||
if cx.shared.include_sources {
|
||||
use std::path::Component;
|
||||
|
||||
let mut hierarchy = Hierarchy::new(OsString::new());
|
||||
for source in cx.shared.local_sources.iter()
|
||||
.filter_map(|p| p.0.strip_prefix(&cx.shared.src_root)
|
||||
|
|
|
@ -371,8 +371,7 @@ pub fn make_test(s: &str,
|
|||
// Uses libsyntax to parse the doctest and find if there's a main fn and the extern
|
||||
// crate already is included.
|
||||
let (already_has_main, already_has_extern_crate, found_macro) = crate::syntax::with_globals(|| {
|
||||
use crate::syntax::{ast, parse::{self, ParseSess}, source_map::FilePathMapping};
|
||||
use crate::syntax_pos::FileName;
|
||||
use crate::syntax::{parse::{self, ParseSess}, source_map::FilePathMapping};
|
||||
use errors::emitter::EmitterWriter;
|
||||
use errors::Handler;
|
||||
|
||||
|
|
|
@ -45,8 +45,6 @@ pub mod glfw {
|
|||
}
|
||||
|
||||
fn issue_6533() {
|
||||
use glfw;
|
||||
|
||||
fn action_to_str(state: glfw::InputState) -> &'static str {
|
||||
use glfw::{RELEASE, PRESS, REPEAT};
|
||||
match state {
|
||||
|
|
|
@ -238,7 +238,6 @@ pub fn main() {
|
|||
// Basic test to make sure that we can invoke the `write!` macro with an
|
||||
// fmt::Write instance.
|
||||
fn test_write() {
|
||||
use std::fmt::Write;
|
||||
let mut buf = String::new();
|
||||
write!(&mut buf, "{}", 3);
|
||||
{
|
||||
|
@ -267,7 +266,6 @@ fn test_print() {
|
|||
// Just make sure that the macros are defined, there's not really a lot that we
|
||||
// can do with them just yet (to test the output)
|
||||
fn test_format_args() {
|
||||
use std::fmt::Write;
|
||||
let mut buf = String::new();
|
||||
{
|
||||
let w = &mut buf;
|
||||
|
|
|
@ -25,7 +25,6 @@ fn foo() {
|
|||
#[cfg(unix)]
|
||||
fn check_status(status: std::process::ExitStatus)
|
||||
{
|
||||
use libc;
|
||||
use std::os::unix::process::ExitStatusExt;
|
||||
|
||||
assert!(status.signal() == Some(libc::SIGILL)
|
||||
|
|
|
@ -9,6 +9,5 @@ macro_rules! reexport {
|
|||
reexport!();
|
||||
|
||||
fn main() {
|
||||
use Bar;
|
||||
fn f(_: Bar) {}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ fn arena() -> &'static ArenaSet<Vec<u8>> {
|
|||
fn require_sync<T: Sync>(_: &T) { }
|
||||
unsafe fn __stability() -> &'static ArenaSet<Vec<u8>> {
|
||||
use std::mem::transmute;
|
||||
use std::boxed::Box;
|
||||
static mut DATA: *const ArenaSet<Vec<u8>> = 0 as *const ArenaSet<Vec<u8>>;
|
||||
|
||||
static mut ONCE: Once = ONCE_INIT;
|
||||
|
|
|
@ -36,7 +36,6 @@ fn loud_recurse() {
|
|||
#[cfg(unix)]
|
||||
fn check_status(status: std::process::ExitStatus)
|
||||
{
|
||||
use libc;
|
||||
use std::os::unix::process::ExitStatusExt;
|
||||
|
||||
assert!(!status.success());
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
// compile-flags:--extern xcrate
|
||||
// edition:2018
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use xcrate::Z;
|
||||
|
||||
fn f() {
|
||||
|
|
|
@ -28,7 +28,6 @@ where T : Convert<U>
|
|||
}
|
||||
|
||||
fn main() {
|
||||
use std::default::Default;
|
||||
// T = i16, U = u32
|
||||
test(22_i16, Default::default(), 2, 4);
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ mod bar {
|
|||
|
||||
fn g() {
|
||||
use self::g; //~ ERROR unused import: `self::g`
|
||||
//~^ ERROR the item `g` is imported redundantly
|
||||
fn f() {
|
||||
self::g();
|
||||
}
|
||||
|
@ -75,6 +76,7 @@ fn g() {
|
|||
#[allow(unused_variables)]
|
||||
fn h() {
|
||||
use test2::foo; //~ ERROR unused import: `test2::foo`
|
||||
//~^ ERROR the item `foo` is imported redundantly
|
||||
let foo = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,14 +34,36 @@ error: unused import: `foo::Square`
|
|||
LL | use foo::Square;
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: the item `g` is imported redundantly
|
||||
--> $DIR/lint-unused-imports.rs:68:9
|
||||
|
|
||||
LL | / fn g() {
|
||||
LL | | use self::g;
|
||||
| | ^^^^^^^
|
||||
LL | |
|
||||
LL | | fn f() {
|
||||
LL | | self::g();
|
||||
LL | | }
|
||||
LL | | }
|
||||
| |_- the item `g` is already defined here
|
||||
|
||||
error: unused import: `self::g`
|
||||
--> $DIR/lint-unused-imports.rs:68:9
|
||||
|
|
||||
LL | use self::g;
|
||||
| ^^^^^^^
|
||||
|
||||
error: the item `foo` is imported redundantly
|
||||
--> $DIR/lint-unused-imports.rs:78:9
|
||||
|
|
||||
LL | use test2::{foo, bar};
|
||||
| --- the item `foo` is already imported here
|
||||
...
|
||||
LL | use test2::foo;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: unused import: `test2::foo`
|
||||
--> $DIR/lint-unused-imports.rs:77:9
|
||||
--> $DIR/lint-unused-imports.rs:78:9
|
||||
|
|
||||
LL | use test2::foo;
|
||||
| ^^^^^^^^^^
|
||||
|
@ -52,5 +74,5 @@ error: unused import: `test::B2`
|
|||
LL | use test::B2;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
|
|
27
src/test/ui/lint/use-redundant.rs
Normal file
27
src/test/ui/lint/use-redundant.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// compile-pass
|
||||
#![warn(unused_imports)]
|
||||
|
||||
use crate::foo::Bar; //~ WARNING first import
|
||||
|
||||
mod foo {
|
||||
pub type Bar = i32;
|
||||
}
|
||||
|
||||
fn baz() -> Bar {
|
||||
3
|
||||
}
|
||||
|
||||
mod m1 { pub struct S {} }
|
||||
mod m2 { pub struct S {} }
|
||||
|
||||
use m1::*;
|
||||
use m2::*;
|
||||
|
||||
fn main() {
|
||||
use crate::foo::Bar; //~ WARNING redundant import
|
||||
let _a: Bar = 3;
|
||||
baz();
|
||||
|
||||
use m1::S; //~ WARNING redundant import
|
||||
let _s = S {};
|
||||
}
|
27
src/test/ui/lint/use-redundant.stderr
Normal file
27
src/test/ui/lint/use-redundant.stderr
Normal file
|
@ -0,0 +1,27 @@
|
|||
warning: unused import: `m1::*`
|
||||
--> $DIR/use-redundant.rs:17:5
|
||||
|
|
||||
LL | use m1::*;
|
||||
| ^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/use-redundant.rs:2:9
|
||||
|
|
||||
LL | #![warn(unused_imports)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
warning: unused import: `m2::*`
|
||||
--> $DIR/use-redundant.rs:18:5
|
||||
|
|
||||
LL | use m2::*;
|
||||
| ^^^^^
|
||||
|
||||
warning: the item `Bar` is imported redundantly
|
||||
--> $DIR/use-redundant.rs:21:9
|
||||
|
|
||||
LL | use crate::foo::Bar;
|
||||
| --------------- the item `Bar` is already imported here
|
||||
...
|
||||
LL | use crate::foo::Bar;
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// edition:2018
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
mod T {
|
||||
pub struct U;
|
||||
|
|
|
@ -1,53 +1,53 @@
|
|||
error: imports cannot refer to type parameters
|
||||
--> $DIR/future-proofing-locals.rs:13:9
|
||||
--> $DIR/future-proofing-locals.rs:14:9
|
||||
|
|
||||
LL | use T as _;
|
||||
| ^
|
||||
|
||||
error: imports cannot refer to type parameters
|
||||
--> $DIR/future-proofing-locals.rs:14:9
|
||||
--> $DIR/future-proofing-locals.rs:15:9
|
||||
|
|
||||
LL | use T::U;
|
||||
| ^
|
||||
|
||||
error: imports cannot refer to type parameters
|
||||
--> $DIR/future-proofing-locals.rs:15:9
|
||||
--> $DIR/future-proofing-locals.rs:16:9
|
||||
|
|
||||
LL | use T::*;
|
||||
| ^
|
||||
|
||||
error: imports cannot refer to type parameters
|
||||
--> $DIR/future-proofing-locals.rs:19:9
|
||||
--> $DIR/future-proofing-locals.rs:20:9
|
||||
|
|
||||
LL | use T;
|
||||
| ^
|
||||
|
||||
error: imports cannot refer to local variables
|
||||
--> $DIR/future-proofing-locals.rs:25:9
|
||||
--> $DIR/future-proofing-locals.rs:26:9
|
||||
|
|
||||
LL | use x as _;
|
||||
| ^
|
||||
|
||||
error: imports cannot refer to local variables
|
||||
--> $DIR/future-proofing-locals.rs:31:9
|
||||
--> $DIR/future-proofing-locals.rs:32:9
|
||||
|
|
||||
LL | use x;
|
||||
| ^
|
||||
|
||||
error: imports cannot refer to local variables
|
||||
--> $DIR/future-proofing-locals.rs:37:17
|
||||
--> $DIR/future-proofing-locals.rs:38:17
|
||||
|
|
||||
LL | use x;
|
||||
| ^
|
||||
|
||||
error: imports cannot refer to type parameters
|
||||
--> $DIR/future-proofing-locals.rs:45:10
|
||||
--> $DIR/future-proofing-locals.rs:46:10
|
||||
|
|
||||
LL | use {T as _, x};
|
||||
| ^
|
||||
|
||||
error: imports cannot refer to local variables
|
||||
--> $DIR/future-proofing-locals.rs:45:18
|
||||
--> $DIR/future-proofing-locals.rs:46:18
|
||||
|
|
||||
LL | use {T as _, x};
|
||||
| ^
|
||||
|
|
Loading…
Reference in a new issue