Add suggestion for duplicated import.
This commit adds a suggestion when a import is duplicated (ie. the same name is used twice trying to import the same thing) to remove the second import.
This commit is contained in:
parent
a21bd75688
commit
1595163356
18 changed files with 570 additions and 111 deletions
|
@ -238,12 +238,14 @@ impl<'a> Resolver<'a> {
|
|||
macro_ns: Cell::new(None),
|
||||
},
|
||||
type_ns_only,
|
||||
nested,
|
||||
};
|
||||
self.add_import_directive(
|
||||
module_path,
|
||||
subclass,
|
||||
use_tree.span,
|
||||
id,
|
||||
item,
|
||||
root_span,
|
||||
item.id,
|
||||
vis,
|
||||
|
@ -260,6 +262,7 @@ impl<'a> Resolver<'a> {
|
|||
subclass,
|
||||
use_tree.span,
|
||||
id,
|
||||
item,
|
||||
root_span,
|
||||
item.id,
|
||||
vis,
|
||||
|
@ -379,6 +382,9 @@ impl<'a> Resolver<'a> {
|
|||
source: orig_name,
|
||||
target: ident,
|
||||
},
|
||||
has_attributes: !item.attrs.is_empty(),
|
||||
use_span_with_attributes: item.span_with_attributes(),
|
||||
use_span: item.span,
|
||||
root_span: item.span,
|
||||
span: item.span,
|
||||
module_path: Vec::new(),
|
||||
|
@ -824,6 +830,9 @@ impl<'a> Resolver<'a> {
|
|||
parent_scope: parent_scope.clone(),
|
||||
imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
|
||||
subclass: ImportDirectiveSubclass::MacroUse,
|
||||
use_span_with_attributes: item.span_with_attributes(),
|
||||
has_attributes: !item.attrs.is_empty(),
|
||||
use_span: item.span,
|
||||
root_span: span,
|
||||
span,
|
||||
module_path: Vec::new(),
|
||||
|
|
|
@ -63,7 +63,7 @@ use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
|
|||
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
|
||||
use syntax::ptr::P;
|
||||
|
||||
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
|
||||
use syntax_pos::{BytePos, Span, DUMMY_SP, MultiSpan};
|
||||
use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
@ -1228,6 +1228,16 @@ enum NameBindingKind<'a> {
|
|||
},
|
||||
}
|
||||
|
||||
impl<'a> NameBindingKind<'a> {
|
||||
/// Is this a name binding of a import?
|
||||
fn is_import(&self) -> bool {
|
||||
match *self {
|
||||
NameBindingKind::Import { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PrivacyError<'a>(Span, Ident, &'a NameBinding<'a>);
|
||||
|
||||
struct UseError<'a> {
|
||||
|
@ -5134,66 +5144,237 @@ impl<'a> Resolver<'a> {
|
|||
);
|
||||
|
||||
// See https://github.com/rust-lang/rust/issues/32354
|
||||
use NameBindingKind::Import;
|
||||
let directive = match (&new_binding.kind, &old_binding.kind) {
|
||||
(NameBindingKind::Import { directive, .. }, _) if !new_binding.span.is_dummy() =>
|
||||
Some((directive, new_binding.span)),
|
||||
(_, NameBindingKind::Import { directive, .. }) if !old_binding.span.is_dummy() =>
|
||||
Some((directive, old_binding.span)),
|
||||
// If there are two imports where one or both have attributes then prefer removing the
|
||||
// import without attributes.
|
||||
(Import { directive: new, .. }, Import { directive: old, .. }) if {
|
||||
!new_binding.span.is_dummy() && !old_binding.span.is_dummy() &&
|
||||
(new.has_attributes || old.has_attributes)
|
||||
} => {
|
||||
if old.has_attributes {
|
||||
Some((new, new_binding.span, true))
|
||||
} else {
|
||||
Some((old, old_binding.span, true))
|
||||
}
|
||||
},
|
||||
// Otherwise prioritize the new binding.
|
||||
(Import { directive, .. }, other) if !new_binding.span.is_dummy() =>
|
||||
Some((directive, new_binding.span, other.is_import())),
|
||||
(other, Import { directive, .. }) if !old_binding.span.is_dummy() =>
|
||||
Some((directive, old_binding.span, other.is_import())),
|
||||
_ => None,
|
||||
};
|
||||
if let Some((directive, binding_span)) = directive {
|
||||
let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
|
||||
format!("Other{}", name)
|
||||
} else {
|
||||
format!("other_{}", name)
|
||||
};
|
||||
|
||||
let mut suggestion = None;
|
||||
match directive.subclass {
|
||||
ImportDirectiveSubclass::SingleImport { type_ns_only: true, .. } =>
|
||||
suggestion = Some(format!("self as {}", suggested_name)),
|
||||
ImportDirectiveSubclass::SingleImport { source, .. } => {
|
||||
if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0)
|
||||
.map(|pos| pos as usize) {
|
||||
if let Ok(snippet) = self.session.source_map()
|
||||
.span_to_snippet(binding_span) {
|
||||
if pos <= snippet.len() {
|
||||
suggestion = Some(format!(
|
||||
"{} as {}{}",
|
||||
&snippet[..pos],
|
||||
suggested_name,
|
||||
if snippet.ends_with(";") { ";" } else { "" }
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImportDirectiveSubclass::ExternCrate { source, target, .. } =>
|
||||
suggestion = Some(format!(
|
||||
"extern crate {} as {};",
|
||||
source.unwrap_or(target.name),
|
||||
suggested_name,
|
||||
)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
// Check if the target of the use for both bindings is the same.
|
||||
let duplicate = new_binding.def().opt_def_id() == old_binding.def().opt_def_id();
|
||||
let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
|
||||
let from_item = self.extern_prelude.get(&ident)
|
||||
.map(|entry| entry.introduced_by_item)
|
||||
.unwrap_or(true);
|
||||
// Only suggest removing an import if both bindings are to the same def, if both spans
|
||||
// aren't dummy spans. Further, if both bindings are imports, then the ident must have
|
||||
// been introduced by a item.
|
||||
let should_remove_import = duplicate && !has_dummy_span &&
|
||||
((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item);
|
||||
|
||||
let rename_msg = "you can use `as` to change the binding name of the import";
|
||||
if let Some(suggestion) = suggestion {
|
||||
match directive {
|
||||
Some((directive, span, true)) if should_remove_import && directive.is_nested() =>
|
||||
self.add_suggestion_for_duplicate_nested_use(&mut err, directive, span),
|
||||
Some((directive, _, true)) if should_remove_import && !directive.is_glob() => {
|
||||
// Simple case - remove the entire import. Due to the above match arm, this can
|
||||
// only be a single use so just remove it entirely.
|
||||
err.span_suggestion(
|
||||
binding_span,
|
||||
rename_msg,
|
||||
suggestion,
|
||||
directive.use_span_with_attributes,
|
||||
"remove unnecessary import",
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_label(binding_span, rename_msg);
|
||||
}
|
||||
},
|
||||
Some((directive, span, _)) =>
|
||||
self.add_suggestion_for_rename_of_use(&mut err, name, directive, span),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
err.emit();
|
||||
self.name_already_seen.insert(name, span);
|
||||
}
|
||||
|
||||
/// This function adds a suggestion to change the binding name of a new import that conflicts
|
||||
/// with an existing import.
|
||||
///
|
||||
/// ```ignore (diagnostic)
|
||||
/// help: you can use `as` to change the binding name of the import
|
||||
/// |
|
||||
/// LL | use foo::bar as other_bar;
|
||||
/// | ^^^^^^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
fn add_suggestion_for_rename_of_use(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
name: Symbol,
|
||||
directive: &ImportDirective<'_>,
|
||||
binding_span: Span,
|
||||
) {
|
||||
let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
|
||||
format!("Other{}", name)
|
||||
} else {
|
||||
format!("other_{}", name)
|
||||
};
|
||||
|
||||
let mut suggestion = None;
|
||||
match directive.subclass {
|
||||
ImportDirectiveSubclass::SingleImport { type_ns_only: true, .. } =>
|
||||
suggestion = Some(format!("self as {}", suggested_name)),
|
||||
ImportDirectiveSubclass::SingleImport { source, .. } => {
|
||||
if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0)
|
||||
.map(|pos| pos as usize) {
|
||||
if let Ok(snippet) = self.session.source_map()
|
||||
.span_to_snippet(binding_span) {
|
||||
if pos <= snippet.len() {
|
||||
suggestion = Some(format!(
|
||||
"{} as {}{}",
|
||||
&snippet[..pos],
|
||||
suggested_name,
|
||||
if snippet.ends_with(";") { ";" } else { "" }
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImportDirectiveSubclass::ExternCrate { source, target, .. } =>
|
||||
suggestion = Some(format!(
|
||||
"extern crate {} as {};",
|
||||
source.unwrap_or(target.name),
|
||||
suggested_name,
|
||||
)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
let rename_msg = "you can use `as` to change the binding name of the import";
|
||||
if let Some(suggestion) = suggestion {
|
||||
err.span_suggestion(
|
||||
binding_span,
|
||||
rename_msg,
|
||||
suggestion,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_label(binding_span, rename_msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// This function adds a suggestion to remove a unnecessary binding from an import that is
|
||||
/// nested. In the following example, this function will be invoked to remove the `a` binding
|
||||
/// in the second use statement:
|
||||
///
|
||||
/// ```ignore (diagnostic)
|
||||
/// use issue_52891::a;
|
||||
/// use issue_52891::{d, a, e};
|
||||
/// ```
|
||||
///
|
||||
/// The following suggestion will be added:
|
||||
///
|
||||
/// ```ignore (diagnostic)
|
||||
/// use issue_52891::{d, a, e};
|
||||
/// ^-- help: remove unnecessary import
|
||||
/// ```
|
||||
///
|
||||
/// If the nested use contains only one import then the suggestion will remove the entire
|
||||
/// line.
|
||||
///
|
||||
/// It is expected that the directive provided is a nested import - this isn't checked by the
|
||||
/// function. If this invariant is not upheld, this function's behaviour will be unexpected
|
||||
/// as characters expected by span manipulations won't be present.
|
||||
fn add_suggestion_for_duplicate_nested_use(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
directive: &ImportDirective<'_>,
|
||||
binding_span: Span,
|
||||
) {
|
||||
assert!(directive.is_nested());
|
||||
let message = "remove unnecessary import";
|
||||
let source_map = self.session.source_map();
|
||||
|
||||
// Two examples will be used to illustrate the span manipulations we're doing:
|
||||
//
|
||||
// - Given `use issue_52891::{d, a, e};` where `a` is a duplicate then `binding_span` is
|
||||
// `a` and `directive.use_span` is `issue_52891::{d, a, e};`.
|
||||
// - Given `use issue_52891::{d, e, a};` where `a` is a duplicate then `binding_span` is
|
||||
// `a` and `directive.use_span` is `issue_52891::{d, e, a};`.
|
||||
|
||||
// Find the span of everything after the binding.
|
||||
// ie. `a, e};` or `a};`
|
||||
let binding_until_end = binding_span.with_hi(directive.use_span.hi());
|
||||
|
||||
// Find everything after the binding but not including the binding.
|
||||
// ie. `, e};` or `};`
|
||||
let after_binding_until_end = binding_until_end.with_lo(binding_span.hi());
|
||||
|
||||
// Keep characters in the span until we encounter something that isn't a comma or
|
||||
// whitespace.
|
||||
// ie. `, ` or ``.
|
||||
//
|
||||
// Also note whether a closing brace character was encountered. If there
|
||||
// was, then later go backwards to remove any trailing commas that are left.
|
||||
let mut found_closing_brace = false;
|
||||
let after_binding_until_next_binding = source_map.span_take_while(
|
||||
after_binding_until_end,
|
||||
|&ch| {
|
||||
if ch == '}' { found_closing_brace = true; }
|
||||
ch == ' ' || ch == ','
|
||||
}
|
||||
);
|
||||
|
||||
// Combine the two spans.
|
||||
// ie. `a, ` or `a`.
|
||||
//
|
||||
// Removing these would leave `issue_52891::{d, e};` or `issue_52891::{d, e, };`
|
||||
let span = binding_span.with_hi(after_binding_until_next_binding.hi());
|
||||
|
||||
// If there was a closing brace then identify the span to remove any trailing commas from
|
||||
// previous imports.
|
||||
if found_closing_brace {
|
||||
if let Ok(prev_source) = source_map.span_to_prev_source(span) {
|
||||
// `prev_source` will contain all of the source that came before the span.
|
||||
// Then split based on a command and take the first (ie. closest to our span)
|
||||
// snippet. In the example, this is a space.
|
||||
let prev_comma = prev_source.rsplit(',').collect::<Vec<_>>();
|
||||
let prev_starting_brace = prev_source.rsplit('{').collect::<Vec<_>>();
|
||||
if prev_comma.len() > 1 && prev_starting_brace.len() > 1 {
|
||||
let prev_comma = prev_comma.first().unwrap();
|
||||
let prev_starting_brace = prev_starting_brace.first().unwrap();
|
||||
|
||||
// If the amount of source code before the comma is greater than
|
||||
// the amount of source code before the starting brace then we've only
|
||||
// got one item in the nested item (eg. `issue_52891::{self}`).
|
||||
if prev_comma.len() > prev_starting_brace.len() {
|
||||
// So just remove the entire line...
|
||||
err.span_suggestion(
|
||||
directive.use_span_with_attributes,
|
||||
message,
|
||||
String::new(),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let span = span.with_lo(BytePos(
|
||||
// Take away the number of bytes for the characters we've found and an
|
||||
// extra for the comma.
|
||||
span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1
|
||||
));
|
||||
err.span_suggestion(
|
||||
span, message, String::new(), Applicability::MaybeIncorrect,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err.span_suggestion(span, message, String::new(), Applicability::MachineApplicable);
|
||||
}
|
||||
|
||||
fn extern_prelude_get(&mut self, ident: Ident, speculative: bool)
|
||||
-> Option<&'a NameBinding<'a>> {
|
||||
if ident.is_path_segment_keyword() {
|
||||
|
|
|
@ -18,7 +18,7 @@ use rustc::hir::def::*;
|
|||
use rustc::session::DiagnosticMessageId;
|
||||
use rustc::util::nodemap::FxHashSet;
|
||||
|
||||
use syntax::ast::{Ident, Name, NodeId, CRATE_NODE_ID};
|
||||
use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID};
|
||||
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
|
||||
use syntax::ext::hygiene::Mark;
|
||||
use syntax::symbol::keywords;
|
||||
|
@ -42,6 +42,8 @@ pub enum ImportDirectiveSubclass<'a> {
|
|||
target_bindings: PerNS<Cell<Option<&'a NameBinding<'a>>>>,
|
||||
/// `true` for `...::{self [as target]}` imports, `false` otherwise.
|
||||
type_ns_only: bool,
|
||||
/// Did this import result from a nested import? ie. `use foo::{bar, baz};`
|
||||
nested: bool,
|
||||
},
|
||||
GlobImport {
|
||||
is_prelude: bool,
|
||||
|
@ -78,6 +80,15 @@ crate struct ImportDirective<'a> {
|
|||
/// `UseTree` node.
|
||||
pub root_id: NodeId,
|
||||
|
||||
/// Span of the entire use statement.
|
||||
pub use_span: Span,
|
||||
|
||||
/// Span of the entire use statement with attributes.
|
||||
pub use_span_with_attributes: Span,
|
||||
|
||||
/// Did the use statement have any attributes?
|
||||
pub has_attributes: bool,
|
||||
|
||||
/// Span of this use tree.
|
||||
pub span: Span,
|
||||
|
||||
|
@ -98,6 +109,13 @@ impl<'a> ImportDirective<'a> {
|
|||
match self.subclass { ImportDirectiveSubclass::GlobImport { .. } => true, _ => false }
|
||||
}
|
||||
|
||||
pub fn is_nested(&self) -> bool {
|
||||
match self.subclass {
|
||||
ImportDirectiveSubclass::SingleImport { nested, .. } => nested,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
crate fn crate_lint(&self) -> CrateLint {
|
||||
CrateLint::UsePath { root_id: self.root_id, root_span: self.root_span }
|
||||
}
|
||||
|
@ -390,6 +408,7 @@ impl<'a> Resolver<'a> {
|
|||
subclass: ImportDirectiveSubclass<'a>,
|
||||
span: Span,
|
||||
id: NodeId,
|
||||
item: &ast::Item,
|
||||
root_span: Span,
|
||||
root_id: NodeId,
|
||||
vis: ty::Visibility,
|
||||
|
@ -402,6 +421,9 @@ impl<'a> Resolver<'a> {
|
|||
subclass,
|
||||
span,
|
||||
id,
|
||||
use_span: item.span,
|
||||
use_span_with_attributes: item.span_with_attributes(),
|
||||
has_attributes: !item.attrs.is_empty(),
|
||||
root_span,
|
||||
root_id,
|
||||
vis: Cell::new(vis),
|
||||
|
@ -787,7 +809,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
|||
let (source, target, source_bindings, target_bindings, type_ns_only) =
|
||||
match directive.subclass {
|
||||
SingleImport { source, target, ref source_bindings,
|
||||
ref target_bindings, type_ns_only } =>
|
||||
ref target_bindings, type_ns_only, .. } =>
|
||||
(source, target, source_bindings, target_bindings, type_ns_only),
|
||||
GlobImport { .. } => {
|
||||
self.resolve_glob_import(directive);
|
||||
|
@ -908,7 +930,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
|||
let (ident, target, source_bindings, target_bindings, type_ns_only) =
|
||||
match directive.subclass {
|
||||
SingleImport { source, target, ref source_bindings,
|
||||
ref target_bindings, type_ns_only } =>
|
||||
ref target_bindings, type_ns_only, .. } =>
|
||||
(source, target, source_bindings, target_bindings, type_ns_only),
|
||||
GlobImport { is_prelude, ref max_vis } => {
|
||||
if directive.module_path.len() <= 1 {
|
||||
|
|
|
@ -2164,6 +2164,13 @@ pub struct Item {
|
|||
pub tokens: Option<TokenStream>,
|
||||
}
|
||||
|
||||
impl Item {
|
||||
/// Return the span that encompasses the attributes.
|
||||
pub fn span_with_attributes(&self) -> Span {
|
||||
self.attrs.iter().fold(self.span, |acc, attr| acc.to(attr.span()))
|
||||
}
|
||||
}
|
||||
|
||||
/// A function header.
|
||||
///
|
||||
/// All the information between the visibility and the name of the function is
|
||||
|
|
|
@ -4,13 +4,12 @@ error[E0252]: the name `X` is defined multiple times
|
|||
LL | pub use self::bar::X;
|
||||
| ------------ previous import of the type `X` here
|
||||
LL | use self::bar::X;
|
||||
| ^^^^^^^^^^^^ `X` reimported here
|
||||
| ----^^^^^^^^^^^^-
|
||||
| | |
|
||||
| | `X` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `X` must be defined only once in the type namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | use self::bar::X as OtherX;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -10,15 +10,13 @@ error[E0252]: the name `fmt` is defined multiple times
|
|||
--> $DIR/E0430.rs:1:22
|
||||
|
|
||||
LL | use std::fmt::{self, self}; //~ ERROR E0430
|
||||
| ---- ^^^^ `fmt` reimported here
|
||||
| |
|
||||
| ------^^^^
|
||||
| | | |
|
||||
| | | `fmt` reimported here
|
||||
| | help: remove unnecessary import
|
||||
| previous import of the module `fmt` here
|
||||
|
|
||||
= note: `fmt` must be defined only once in the type namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | use std::fmt::{self, self as other_fmt}; //~ ERROR E0430
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -4,13 +4,12 @@ error[E0252]: the name `foo` is defined multiple times
|
|||
LL | use a::foo;
|
||||
| ------ previous import of the value `foo` here
|
||||
LL | use a::foo; //~ ERROR the name `foo` is defined multiple times
|
||||
| ^^^^^^ `foo` reimported here
|
||||
| ----^^^^^^-
|
||||
| | |
|
||||
| | `foo` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `foo` must be defined only once in the value namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | use a::foo as other_foo; //~ ERROR the name `foo` is defined multiple times
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
|
||||
--> $DIR/duplicate.rs:46:15
|
||||
|
|
33
src/test/ui/issues/auxiliary/issue-52891.rs
Normal file
33
src/test/ui/issues/auxiliary/issue-52891.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
pub mod a {
|
||||
pub mod inner {
|
||||
}
|
||||
}
|
||||
|
||||
pub mod b {
|
||||
pub mod inner {
|
||||
}
|
||||
}
|
||||
|
||||
pub mod c {}
|
||||
|
||||
pub mod d {}
|
||||
|
||||
pub mod e {}
|
||||
|
||||
pub mod f {}
|
||||
|
||||
pub mod g {}
|
||||
|
||||
pub mod h {}
|
||||
|
||||
pub mod i {}
|
||||
|
||||
pub mod j {}
|
||||
|
||||
pub mod k {}
|
||||
|
||||
pub mod l {}
|
||||
|
||||
pub mod m {}
|
||||
|
||||
pub mod n {}
|
|
@ -4,13 +4,12 @@ error[E0252]: the name `Arc` is defined multiple times
|
|||
LL | use std::sync::{self, Arc};
|
||||
| --- previous import of the type `Arc` here
|
||||
LL | use std::sync::Arc; //~ ERROR the name `Arc` is defined multiple times
|
||||
| ^^^^^^^^^^^^^^ `Arc` reimported here
|
||||
| ----^^^^^^^^^^^^^^-
|
||||
| | |
|
||||
| | `Arc` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `Arc` must be defined only once in the type namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | use std::sync::Arc as OtherArc; //~ ERROR the name `Arc` is defined multiple times
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0252]: the name `sync` is defined multiple times
|
||||
--> $DIR/issue-26886.rs:4:5
|
||||
|
@ -19,13 +18,12 @@ LL | use std::sync::{self, Arc};
|
|||
| ---- previous import of the module `sync` here
|
||||
...
|
||||
LL | use std::sync; //~ ERROR the name `sync` is defined multiple times
|
||||
| ^^^^^^^^^ `sync` reimported here
|
||||
| ----^^^^^^^^^-
|
||||
| | |
|
||||
| | `sync` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `sync` must be defined only once in the type namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | use std::sync as other_sync; //~ ERROR the name `sync` is defined multiple times
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -2,15 +2,13 @@ error[E0252]: the name `A` is defined multiple times
|
|||
--> $DIR/import-twice.rs:6:14
|
||||
|
|
||||
LL | use foo::{A, A};
|
||||
| - ^ `A` reimported here
|
||||
| |
|
||||
| ---^
|
||||
| || |
|
||||
| || `A` reimported here
|
||||
| |help: remove unnecessary import
|
||||
| previous import of the type `A` here
|
||||
|
|
||||
= note: `A` must be defined only once in the type namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | use foo::{A, A as OtherA};
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
37
src/test/ui/issues/issue-52891.fixed
Normal file
37
src/test/ui/issues/issue-52891.fixed
Normal file
|
@ -0,0 +1,37 @@
|
|||
// aux-build:issue-52891.rs
|
||||
// run-rustfix
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
extern crate issue_52891;
|
||||
|
||||
// Check that we don't suggest renaming duplicate imports but instead
|
||||
// suggest removing one.
|
||||
|
||||
use issue_52891::a;
|
||||
//~ ERROR `a` is defined multiple times
|
||||
|
||||
use issue_52891::{b, c}; //~ ERROR `a` is defined multiple times
|
||||
use issue_52891::{d, e}; //~ ERROR `a` is defined multiple times
|
||||
use issue_52891::{f, g}; //~ ERROR `a` is defined multiple times
|
||||
|
||||
use issue_52891::{//~ ERROR `a` is defined multiple times
|
||||
h,
|
||||
i};
|
||||
use issue_52891::{j,
|
||||
//~ ERROR `a` is defined multiple times
|
||||
k};
|
||||
use issue_52891::{l,
|
||||
m}; //~ ERROR `a` is defined multiple times
|
||||
|
||||
use issue_52891::a::inner;
|
||||
use issue_52891::b::inner as other_inner; //~ ERROR `inner` is defined multiple times
|
||||
|
||||
|
||||
//~^ ERROR `issue_52891` is defined multiple times
|
||||
|
||||
|
||||
#[macro_use]
|
||||
use issue_52891::n; //~ ERROR `n` is defined multiple times
|
||||
|
||||
fn main() {}
|
38
src/test/ui/issues/issue-52891.rs
Normal file
38
src/test/ui/issues/issue-52891.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
// aux-build:issue-52891.rs
|
||||
// run-rustfix
|
||||
|
||||
#![allow(warnings)]
|
||||
|
||||
extern crate issue_52891;
|
||||
|
||||
// Check that we don't suggest renaming duplicate imports but instead
|
||||
// suggest removing one.
|
||||
|
||||
use issue_52891::a;
|
||||
use issue_52891::a; //~ ERROR `a` is defined multiple times
|
||||
|
||||
use issue_52891::{a, b, c}; //~ ERROR `a` is defined multiple times
|
||||
use issue_52891::{d, a, e}; //~ ERROR `a` is defined multiple times
|
||||
use issue_52891::{f, g, a}; //~ ERROR `a` is defined multiple times
|
||||
|
||||
use issue_52891::{a, //~ ERROR `a` is defined multiple times
|
||||
h,
|
||||
i};
|
||||
use issue_52891::{j,
|
||||
a, //~ ERROR `a` is defined multiple times
|
||||
k};
|
||||
use issue_52891::{l,
|
||||
m,
|
||||
a}; //~ ERROR `a` is defined multiple times
|
||||
|
||||
use issue_52891::a::inner;
|
||||
use issue_52891::b::inner; //~ ERROR `inner` is defined multiple times
|
||||
|
||||
use issue_52891::{self};
|
||||
//~^ ERROR `issue_52891` is defined multiple times
|
||||
|
||||
use issue_52891::n;
|
||||
#[macro_use]
|
||||
use issue_52891::n; //~ ERROR `n` is defined multiple times
|
||||
|
||||
fn main() {}
|
145
src/test/ui/issues/issue-52891.stderr
Normal file
145
src/test/ui/issues/issue-52891.stderr
Normal file
|
@ -0,0 +1,145 @@
|
|||
error[E0252]: the name `a` is defined multiple times
|
||||
--> $DIR/issue-52891.rs:12:5
|
||||
|
|
||||
LL | use issue_52891::a;
|
||||
| -------------- previous import of the module `a` here
|
||||
LL | use issue_52891::a; //~ ERROR `a` is defined multiple times
|
||||
| ----^^^^^^^^^^^^^^-
|
||||
| | |
|
||||
| | `a` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `a` must be defined only once in the type namespace of this module
|
||||
|
||||
error[E0252]: the name `a` is defined multiple times
|
||||
--> $DIR/issue-52891.rs:14:19
|
||||
|
|
||||
LL | use issue_52891::a;
|
||||
| -------------- previous import of the module `a` here
|
||||
...
|
||||
LL | use issue_52891::{a, b, c}; //~ ERROR `a` is defined multiple times
|
||||
| ^--
|
||||
| |
|
||||
| `a` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `a` must be defined only once in the type namespace of this module
|
||||
|
||||
error[E0252]: the name `a` is defined multiple times
|
||||
--> $DIR/issue-52891.rs:15:22
|
||||
|
|
||||
LL | use issue_52891::a;
|
||||
| -------------- previous import of the module `a` here
|
||||
...
|
||||
LL | use issue_52891::{d, a, e}; //~ ERROR `a` is defined multiple times
|
||||
| ^--
|
||||
| |
|
||||
| `a` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `a` must be defined only once in the type namespace of this module
|
||||
|
||||
error[E0252]: the name `a` is defined multiple times
|
||||
--> $DIR/issue-52891.rs:16:25
|
||||
|
|
||||
LL | use issue_52891::a;
|
||||
| -------------- previous import of the module `a` here
|
||||
...
|
||||
LL | use issue_52891::{f, g, a}; //~ ERROR `a` is defined multiple times
|
||||
| --^
|
||||
| | |
|
||||
| | `a` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `a` must be defined only once in the type namespace of this module
|
||||
|
||||
error[E0252]: the name `a` is defined multiple times
|
||||
--> $DIR/issue-52891.rs:18:19
|
||||
|
|
||||
LL | use issue_52891::a;
|
||||
| -------------- previous import of the module `a` here
|
||||
...
|
||||
LL | use issue_52891::{a, //~ ERROR `a` is defined multiple times
|
||||
| ^--
|
||||
| |
|
||||
| `a` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `a` must be defined only once in the type namespace of this module
|
||||
|
||||
error[E0252]: the name `a` is defined multiple times
|
||||
--> $DIR/issue-52891.rs:22:5
|
||||
|
|
||||
LL | use issue_52891::a;
|
||||
| -------------- previous import of the module `a` here
|
||||
...
|
||||
LL | a, //~ ERROR `a` is defined multiple times
|
||||
| ^--
|
||||
| |
|
||||
| `a` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `a` must be defined only once in the type namespace of this module
|
||||
|
||||
error[E0252]: the name `a` is defined multiple times
|
||||
--> $DIR/issue-52891.rs:26:5
|
||||
|
|
||||
LL | use issue_52891::a;
|
||||
| -------------- previous import of the module `a` here
|
||||
...
|
||||
LL | m,
|
||||
| ______-
|
||||
LL | | a}; //~ ERROR `a` is defined multiple times
|
||||
| | -
|
||||
| | |
|
||||
| |_____`a` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `a` must be defined only once in the type namespace of this module
|
||||
|
||||
error[E0252]: the name `inner` is defined multiple times
|
||||
--> $DIR/issue-52891.rs:29:5
|
||||
|
|
||||
LL | use issue_52891::a::inner;
|
||||
| --------------------- previous import of the module `inner` here
|
||||
LL | use issue_52891::b::inner; //~ ERROR `inner` is defined multiple times
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ `inner` reimported here
|
||||
|
|
||||
= note: `inner` must be defined only once in the type namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | use issue_52891::b::inner as other_inner; //~ ERROR `inner` is defined multiple times
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0254]: the name `issue_52891` is defined multiple times
|
||||
--> $DIR/issue-52891.rs:31:19
|
||||
|
|
||||
LL | extern crate issue_52891;
|
||||
| ------------------------- previous import of the extern crate `issue_52891` here
|
||||
...
|
||||
LL | use issue_52891::{self};
|
||||
| ------------------^^^^--
|
||||
| | |
|
||||
| | `issue_52891` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `issue_52891` must be defined only once in the type namespace of this module
|
||||
|
||||
error[E0252]: the name `n` is defined multiple times
|
||||
--> $DIR/issue-52891.rs:36:5
|
||||
|
|
||||
LL | use issue_52891::n;
|
||||
| -------------------
|
||||
| | |
|
||||
| | previous import of the module `n` here
|
||||
| help: remove unnecessary import
|
||||
LL | #[macro_use]
|
||||
LL | use issue_52891::n; //~ ERROR `n` is defined multiple times
|
||||
| ^^^^^^^^^^^^^^ `n` reimported here
|
||||
|
|
||||
= note: `n` must be defined only once in the type namespace of this module
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
|
||||
Some errors occurred: E0252, E0254.
|
||||
For more information about an error, try `rustc --explain E0252`.
|
|
@ -1,17 +1,16 @@
|
|||
error[E0259]: the name `derive_a` is defined multiple times
|
||||
--> $DIR/shadow.rs:6:1
|
||||
|
|
||||
LL | extern crate derive_a;
|
||||
| ---------------------- previous import of the extern crate `derive_a` here
|
||||
LL | #[macro_use]
|
||||
LL | extern crate derive_a; //~ ERROR the name `derive_a` is defined multiple times
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ `derive_a` reimported here
|
||||
LL | extern crate derive_a;
|
||||
| ---------------------- previous import of the extern crate `derive_a` here
|
||||
LL | / #[macro_use]
|
||||
LL | | extern crate derive_a; //~ ERROR the name `derive_a` is defined multiple times
|
||||
| | ^^^^^^^^^^^^^^^^^^^^^-
|
||||
| |_|____________________|
|
||||
| | help: remove unnecessary import
|
||||
| `derive_a` reimported here
|
||||
|
|
||||
= note: `derive_a` must be defined only once in the type namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | extern crate derive_a as other_derive_a; //~ ERROR the name `derive_a` is defined multiple times
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -4,13 +4,12 @@ error[E0252]: the name `transmute` is defined multiple times
|
|||
LL | use std::mem::transmute;
|
||||
| ------------------- previous import of the value `transmute` here
|
||||
LL | use std::mem::transmute;
|
||||
| ^^^^^^^^^^^^^^^^^^^ `transmute` reimported here
|
||||
| ----^^^^^^^^^^^^^^^^^^^-
|
||||
| | |
|
||||
| | `transmute` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `transmute` must be defined only once in the value namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | use std::mem::transmute as other_transmute;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -4,13 +4,12 @@ error[E0254]: the name `core` is defined multiple times
|
|||
LL | extern crate core;
|
||||
| ------------------ previous import of the extern crate `core` here
|
||||
LL | use core;
|
||||
| ^^^^ `core` reimported here
|
||||
| ----^^^^-
|
||||
| | |
|
||||
| | `core` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `core` must be defined only once in the type namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | use core as other_core;
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -20,13 +20,12 @@ LL | self,
|
|||
| ---- previous import of the module `bar` here
|
||||
...
|
||||
LL | self
|
||||
| ^^^^ `bar` reimported here
|
||||
| ^^^^
|
||||
| |
|
||||
| `bar` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `bar` must be defined only once in the type namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | self as other_bar
|
||||
|
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
@ -4,13 +4,12 @@ error[E0252]: the name `mem` is defined multiple times
|
|||
LL | use std::{mem, ptr};
|
||||
| --- previous import of the module `mem` here
|
||||
LL | use std::mem; //~ ERROR the name `mem` is defined multiple times
|
||||
| ^^^^^^^^ `mem` reimported here
|
||||
| ----^^^^^^^^-
|
||||
| | |
|
||||
| | `mem` reimported here
|
||||
| help: remove unnecessary import
|
||||
|
|
||||
= note: `mem` must be defined only once in the type namespace of this module
|
||||
help: you can use `as` to change the binding name of the import
|
||||
|
|
||||
LL | use std::mem as other_mem; //~ ERROR the name `mem` is defined multiple times
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue