By tracking import use types to check whether it is scope uses or the other situations like module-relative uses, we can do more accurate redundant import checking.

fixes #117448

For example unnecessary imports in std::prelude that can be eliminated:

```rust
use std::option::Option::Some;//~ WARNING the item `Some` is imported redundantly
use std::option::Option::None; //~ WARNING the item `None` is imported redundantly
```
This commit is contained in:
surechen 2023-11-10 10:11:24 +08:00
parent d3df8ff851
commit a61126cef6
52 changed files with 283 additions and 167 deletions

View File

@ -4,7 +4,7 @@ use crate::sync::Lrc;
// Use our fake Send/Sync traits when on not parallel compiler, // Use our fake Send/Sync traits when on not parallel compiler,
// so that `OwnedSlice` only implements/requires Send/Sync // so that `OwnedSlice` only implements/requires Send/Sync
// for parallel compiler builds. // for parallel compiler builds.
use crate::sync::{Send, Sync}; use crate::sync;
/// An owned slice. /// An owned slice.
/// ///
@ -33,7 +33,7 @@ pub struct OwnedSlice {
// \/ // \/
// ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770) // ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770)
#[expect(dead_code)] #[expect(dead_code)]
owner: Lrc<dyn Send + Sync>, owner: Lrc<dyn sync::Send + sync::Sync>,
} }
/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function. /// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function.
@ -60,7 +60,7 @@ pub struct OwnedSlice {
/// ``` /// ```
pub fn slice_owned<O, F>(owner: O, slicer: F) -> OwnedSlice pub fn slice_owned<O, F>(owner: O, slicer: F) -> OwnedSlice
where where
O: Send + Sync + 'static, O: sync::Send + sync::Sync + 'static,
F: FnOnce(&O) -> &[u8], F: FnOnce(&O) -> &[u8],
{ {
try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok() try_slice_owned(owner, |x| Ok::<_, !>(slicer(x))).into_ok()
@ -71,7 +71,7 @@ where
/// See [`slice_owned`] for the infallible version. /// See [`slice_owned`] for the infallible version.
pub fn try_slice_owned<O, F, E>(owner: O, slicer: F) -> Result<OwnedSlice, E> pub fn try_slice_owned<O, F, E>(owner: O, slicer: F) -> Result<OwnedSlice, E>
where where
O: Send + Sync + 'static, O: sync::Send + sync::Sync + 'static,
F: FnOnce(&O) -> Result<&[u8], E>, F: FnOnce(&O) -> Result<&[u8], E>,
{ {
// We wrap the owner of the bytes in, so it doesn't move. // We wrap the owner of the bytes in, so it doesn't move.
@ -139,11 +139,11 @@ impl Borrow<[u8]> for OwnedSlice {
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send` // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send`
#[cfg(parallel_compiler)] #[cfg(parallel_compiler)]
unsafe impl Send for OwnedSlice {} unsafe impl sync::Send for OwnedSlice {}
// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync` // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync`
#[cfg(parallel_compiler)] #[cfg(parallel_compiler)]
unsafe impl Sync for OwnedSlice {} unsafe impl sync::Sync for OwnedSlice {}
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;

View File

@ -5,10 +5,9 @@ use super::compare_impl_item::check_type_bounds;
use super::compare_impl_item::{compare_impl_method, compare_impl_ty}; use super::compare_impl_item::{compare_impl_method, compare_impl_ty};
use super::*; use super::*;
use rustc_attr as attr; use rustc_attr as attr;
use rustc_errors::{codes::*, ErrorGuaranteed, MultiSpan}; use rustc_errors::{codes::*, MultiSpan};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::Node; use rustc_hir::Node;
use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::{Obligation, TraitEngineExt as _}; use rustc_infer::traits::{Obligation, TraitEngineExt as _};

View File

@ -1,5 +1,5 @@
use crate::{errors, structured_errors::StructuredDiagnostic}; use crate::{errors, structured_errors::StructuredDiagnostic};
use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode}; use rustc_errors::{codes::*, DiagnosticBuilder};
use rustc_middle::ty::{Ty, TypeVisitableExt}; use rustc_middle::ty::{Ty, TypeVisitableExt};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::Span; use rustc_span::Span;

View File

@ -1,5 +1,5 @@
use crate::{errors, structured_errors::StructuredDiagnostic}; use crate::{errors, structured_errors::StructuredDiagnostic};
use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode}; use rustc_errors::{codes::*, DiagnosticBuilder};
use rustc_middle::ty::{Ty, TypeVisitableExt}; use rustc_middle::ty::{Ty, TypeVisitableExt};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::Span; use rustc_span::Span;

View File

@ -1,7 +1,5 @@
use crate::structured_errors::StructuredDiagnostic; use crate::structured_errors::StructuredDiagnostic;
use rustc_errors::{ use rustc_errors::{codes::*, pluralize, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan};
codes::*, pluralize, Applicability, Diagnostic, DiagnosticBuilder, ErrCode, MultiSpan,
};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt}; use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
use rustc_session::Session; use rustc_session::Session;

View File

@ -27,7 +27,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_data_structures::unord::UnordMap; use rustc_data_structures::unord::UnordMap;
use rustc_errors::{ use rustc_errors::{
codes::*, pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic, codes::*, pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic,
DiagnosticBuilder, ErrCode, ErrorGuaranteed, StashKey, DiagnosticBuilder, ErrorGuaranteed, StashKey,
}; };
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def::{CtorKind, DefKind, Res};

View File

@ -13,7 +13,7 @@ use itertools::Itertools;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{ use rustc_errors::{
codes::*, pluralize, Applicability, Diagnostic, ErrCode, ErrorGuaranteed, MultiSpan, StashKey, codes::*, pluralize, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey,
}; };
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def::{CtorOf, DefKind, Res};

View File

@ -53,7 +53,7 @@ use crate::expectation::Expectation;
use crate::fn_ctxt::LoweredTy; use crate::fn_ctxt::LoweredTy;
use crate::gather_locals::GatherLocalsVisitor; use crate::gather_locals::GatherLocalsVisitor;
use rustc_data_structures::unord::UnordSet; use rustc_data_structures::unord::UnordSet;
use rustc_errors::{codes::*, struct_span_code_err, ErrCode, ErrorGuaranteed}; use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::Visitor; use rustc_hir::intravisit::Visitor;

View File

@ -5,7 +5,7 @@ use crate::errors::{
use crate::infer::error_reporting::TypeErrCtxt; use crate::infer::error_reporting::TypeErrCtxt;
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::InferCtxt; use crate::infer::InferCtxt;
use rustc_errors::{codes::*, DiagnosticBuilder, ErrCode, IntoDiagnosticArg}; use rustc_errors::{codes::*, DiagnosticBuilder, IntoDiagnosticArg};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def::{CtorOf, DefKind, Namespace};

View File

@ -13,7 +13,7 @@ use rustc_data_structures::unhash::UnhashMap;
use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro};
use rustc_hir::def::Res; use rustc_hir::def::Res;
use rustc_hir::def_id::{DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefPath, DefPathData}; use rustc_hir::definitions::{DefPath, DefPathData};
use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_index::Idx; use rustc_index::Idx;

View File

@ -15,7 +15,7 @@ use crate::ty::{Region, UserTypeAnnotationIndex};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_data_structures::packed::Pu128; use rustc_data_structures::packed::Pu128;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::{self, CoroutineKind}; use rustc_hir::CoroutineKind;
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::abi::{FieldIdx, VariantIdx};

View File

@ -8,11 +8,11 @@
use crate::def_collector::collect_definitions; use crate::def_collector::collect_definitions;
use crate::imports::{ImportData, ImportKind}; use crate::imports::{ImportData, ImportKind};
use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
use crate::Namespace::{self, MacroNS, TypeNS, ValueNS}; use crate::Namespace::{MacroNS, TypeNS, ValueNS};
use crate::{errors, BindingKey, MacroData, NameBindingData}; use crate::{errors, BindingKey, MacroData, NameBindingData};
use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot};
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError};
use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError}; use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError};
use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind}; use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
@ -362,7 +362,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
root_span, root_span,
root_id, root_id,
vis: Cell::new(Some(vis)), vis: Cell::new(Some(vis)),
used: Cell::new(false), used: Default::default(),
}); });
self.r.indeterminate_imports.push(import); self.r.indeterminate_imports.push(import);
@ -885,7 +885,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
span: item.span, span: item.span,
module_path: Vec::new(), module_path: Vec::new(),
vis: Cell::new(Some(vis)), vis: Cell::new(Some(vis)),
used: Cell::new(used), used: Cell::new(used.then_some(Used::Other)),
}); });
self.r.potentially_unused_imports.push(import); self.r.potentially_unused_imports.push(import);
let imported_binding = self.r.import(binding, import); let imported_binding = self.r.import(binding, import);
@ -1090,7 +1090,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
span, span,
module_path: Vec::new(), module_path: Vec::new(),
vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))), vis: Cell::new(Some(ty::Visibility::Restricted(CRATE_DEF_ID))),
used: Cell::new(false), used: Default::default(),
}) })
}; };
@ -1261,7 +1261,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
span, span,
module_path: Vec::new(), module_path: Vec::new(),
vis: Cell::new(Some(vis)), vis: Cell::new(Some(vis)),
used: Cell::new(true), used: Cell::new(Some(Used::Other)),
}); });
let import_binding = self.r.import(binding, import); let import_binding = self.r.import(binding, import);
self.r.define(self.r.graph_root, ident, MacroNS, import_binding); self.r.define(self.r.graph_root, ident, MacroNS, import_binding);

View File

@ -27,9 +27,10 @@ use crate::imports::ImportKind;
use crate::module_to_string; use crate::module_to_string;
use crate::Resolver; use crate::Resolver;
use crate::NameBindingKind;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::visit::{self, Visitor}; use rustc_ast::visit::{self, Visitor};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
use rustc_data_structures::unord::UnordSet; use rustc_data_structures::unord::UnordSet;
use rustc_errors::{pluralize, MultiSpan}; use rustc_errors::{pluralize, MultiSpan};
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
@ -38,14 +39,14 @@ use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::symbol::{kw, Ident}; use rustc_span::symbol::{kw, Ident};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
struct UnusedImport<'a> { struct UnusedImport {
use_tree: &'a ast::UseTree, use_tree: ast::UseTree,
use_tree_id: ast::NodeId, use_tree_id: ast::NodeId,
item_span: Span, item_span: Span,
unused: UnordSet<ast::NodeId>, unused: UnordSet<ast::NodeId>,
} }
impl<'a> UnusedImport<'a> { impl UnusedImport {
fn add(&mut self, id: ast::NodeId) { fn add(&mut self, id: ast::NodeId) {
self.unused.insert(id); self.unused.insert(id);
} }
@ -54,7 +55,7 @@ impl<'a> UnusedImport<'a> {
struct UnusedImportCheckVisitor<'a, 'b, 'tcx> { struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
r: &'a mut Resolver<'b, 'tcx>, r: &'a mut Resolver<'b, 'tcx>,
/// All the (so far) unused imports, grouped path list /// All the (so far) unused imports, grouped path list
unused_imports: FxIndexMap<ast::NodeId, UnusedImport<'a>>, unused_imports: FxIndexMap<ast::NodeId, UnusedImport>,
extern_crate_items: Vec<ExternCrateToLint>, extern_crate_items: Vec<ExternCrateToLint>,
base_use_tree: Option<&'a ast::UseTree>, base_use_tree: Option<&'a ast::UseTree>,
base_id: ast::NodeId, base_id: ast::NodeId,
@ -100,9 +101,9 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
} }
} }
fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport<'a> { fn unused_import(&mut self, id: ast::NodeId) -> &mut UnusedImport {
let use_tree_id = self.base_id; let use_tree_id = self.base_id;
let use_tree = self.base_use_tree.unwrap(); let use_tree = self.base_use_tree.unwrap().clone();
let item_span = self.item_span; let item_span = self.item_span;
self.unused_imports.entry(id).or_insert_with(|| UnusedImport { self.unused_imports.entry(id).or_insert_with(|| UnusedImport {
@ -197,7 +198,7 @@ enum UnusedSpanResult {
} }
fn calc_unused_spans( fn calc_unused_spans(
unused_import: &UnusedImport<'_>, unused_import: &UnusedImport,
use_tree: &ast::UseTree, use_tree: &ast::UseTree,
use_tree_id: ast::NodeId, use_tree_id: ast::NodeId,
) -> UnusedSpanResult { ) -> UnusedSpanResult {
@ -287,7 +288,7 @@ impl Resolver<'_, '_> {
for import in self.potentially_unused_imports.iter() { for import in self.potentially_unused_imports.iter() {
match import.kind { match import.kind {
_ if import.used.get() _ if import.used.get().is_some()
|| import.expect_vis().is_public() || import.expect_vis().is_public()
|| import.span.is_dummy() => || import.span.is_dummy() =>
{ {
@ -336,7 +337,7 @@ impl Resolver<'_, '_> {
for unused in visitor.unused_imports.values() { for unused in visitor.unused_imports.values() {
let mut fixes = Vec::new(); let mut fixes = Vec::new();
let spans = match calc_unused_spans(unused, unused.use_tree, unused.use_tree_id) { let spans = match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) {
UnusedSpanResult::Used => continue, UnusedSpanResult::Used => continue,
UnusedSpanResult::FlatUnused(span, remove) => { UnusedSpanResult::FlatUnused(span, remove) => {
fixes.push((remove, String::new())); fixes.push((remove, String::new()));
@ -483,5 +484,30 @@ impl Resolver<'_, '_> {
BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span }, BuiltinLintDiagnostics::ExternCrateNotIdiomatic { vis_span, ident_span },
); );
} }
let unused_imports = visitor.unused_imports;
let mut check_redundant_imports = FxIndexSet::default();
for module in self.arenas.local_modules().iter() {
for (_key, resolution) in self.resolutions(*module).borrow().iter() {
let resolution = resolution.borrow();
if let Some(binding) = resolution.binding
&& let NameBindingKind::Import { import, .. } = binding.kind
&& let ImportKind::Single { id, .. } = import.kind
{
if let Some(unused_import) = unused_imports.get(&import.root_id)
&& unused_import.unused.contains(&id)
{
continue;
}
check_redundant_imports.insert(import);
}
}
}
for import in check_redundant_imports {
self.check_for_redundant_imports(import);
}
} }
} }

View File

@ -1,5 +1,5 @@
use crate::{ImplTraitContext, Resolver}; use crate::{ImplTraitContext, Resolver};
use rustc_ast::visit::{self, FnKind}; use rustc_ast::visit::FnKind;
use rustc_ast::*; use rustc_ast::*;
use rustc_expand::expand::AstFragment; use rustc_expand::expand::AstFragment;
use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def::{CtorKind, CtorOf, DefKind};

View File

@ -33,8 +33,8 @@ use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSugge
use crate::errors::{ConsiderAddingADerive, ExplicitUnsafeTraits, MaybeMissingMacroRulesName}; use crate::errors::{ConsiderAddingADerive, ExplicitUnsafeTraits, MaybeMissingMacroRulesName};
use crate::imports::{Import, ImportKind}; use crate::imports::{Import, ImportKind};
use crate::late::{PatternSource, Rib}; use crate::late::{PatternSource, Rib};
use crate::path_names_to_string;
use crate::{errors as errs, BindingKey}; use crate::{errors as errs, BindingKey};
use crate::{path_names_to_string, Used};
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize}; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize};
use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot};
use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError}; use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
@ -1503,7 +1503,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
); );
// Silence the 'unused import' warning we might get, // Silence the 'unused import' warning we might get,
// since this diagnostic already covers that import. // since this diagnostic already covers that import.
self.record_use(ident, binding, false); self.record_use(ident, binding, Used::Other);
return; return;
} }
} }

View File

@ -12,8 +12,8 @@ use rustc_span::Span;
use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind}; use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::macros::{sub_namespace_match, MacroRulesScope};
use crate::BindingKey;
use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
use crate::{BindingKey, Used};
use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res};
use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak}; use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak};
@ -339,7 +339,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ident, ident,
ns, ns,
parent_scope, parent_scope,
finalize, finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
ignore_binding, ignore_binding,
); );
if let Ok(binding) = item { if let Ok(binding) = item {
@ -506,7 +506,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ns, ns,
adjusted_parent_scope, adjusted_parent_scope,
!matches!(scope_set, ScopeSet::Late(..)), !matches!(scope_set, ScopeSet::Late(..)),
finalize, finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
ignore_binding, ignore_binding,
); );
match binding { match binding {
@ -857,7 +857,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
.into_iter() .into_iter()
.find_map(|binding| if binding == ignore_binding { None } else { binding }); .find_map(|binding| if binding == ignore_binding { None } else { binding });
if let Some(Finalize { path_span, report_private, .. }) = finalize { if let Some(Finalize { path_span, report_private, used, .. }) = finalize {
let Some(binding) = binding else { let Some(binding) = binding else {
return Err((Determined, Weak::No)); return Err((Determined, Weak::No));
}; };
@ -901,7 +901,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
} }
self.record_use(ident, binding, restricted_shadowing); self.record_use(ident, binding, used);
return Ok(binding); return Ok(binding);
} }

View File

@ -10,9 +10,9 @@ use crate::errors::{
use crate::Determinacy::{self, *}; use crate::Determinacy::{self, *};
use crate::Namespace::*; use crate::Namespace::*;
use crate::{module_to_string, names_to_string, ImportSuggestion}; use crate::{module_to_string, names_to_string, ImportSuggestion};
use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment}; use crate::{AmbiguityKind, BindingKey, ResolutionError, Resolver, Segment};
use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet}; use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult}; use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult, Used};
use rustc_ast::NodeId; use rustc_ast::NodeId;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
@ -173,7 +173,7 @@ pub(crate) struct ImportData<'a> {
/// The resolution of `module_path`. /// The resolution of `module_path`.
pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>, pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
pub vis: Cell<Option<ty::Visibility>>, pub vis: Cell<Option<ty::Visibility>>,
pub used: Cell<bool>, pub used: Cell<Option<Used>>,
} }
/// All imports are unique and allocated on a same arena, /// All imports are unique and allocated on a same arena,
@ -286,7 +286,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
self.arenas.alloc_name_binding(NameBindingData { self.arenas.alloc_name_binding(NameBindingData {
kind: NameBindingKind::Import { binding, import, used: Cell::new(false) }, kind: NameBindingKind::Import { binding, import },
ambiguity: None, ambiguity: None,
warn_ambiguity: false, warn_ambiguity: false,
span: import.span, span: import.span,
@ -485,9 +485,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
resolution.single_imports.remove(&import); resolution.single_imports.remove(&import);
}) })
}); });
self.record_use(target, dummy_binding, false); self.record_use(target, dummy_binding, Used::Other);
} else if import.imported_module.get().is_none() { } else if import.imported_module.get().is_none() {
import.used.set(true); import.used.set(Some(Used::Other));
if let Some(id) = import.id() { if let Some(id) = import.id() {
self.used_imports.insert(id); self.used_imports.insert(id);
} }
@ -1056,11 +1056,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
&& initial_binding.is_extern_crate() && initial_binding.is_extern_crate()
&& !initial_binding.is_import() && !initial_binding.is_import()
{ {
this.record_use( let used = if import.module_path.is_empty() {
ident, Used::Scope
target_binding, } else {
import.module_path.is_empty(), Used::Other
); };
this.record_use(ident, target_binding, used);
} }
} }
initial_binding.res() initial_binding.res()
@ -1299,22 +1300,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} }
}); });
self.check_for_redundant_imports(ident, import, source_bindings, target_bindings, target);
debug!("(resolving single import) successfully resolved import"); debug!("(resolving single import) successfully resolved import");
None None
} }
fn check_for_redundant_imports( pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'a>) {
&mut self,
ident: Ident,
import: Import<'a>,
source_bindings: &PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>,
target_bindings: &PerNS<Cell<Option<NameBinding<'a>>>>,
target: Ident,
) {
// This function is only called for single imports. // This function is only called for single imports.
let ImportKind::Single { id, .. } = import.kind else { unreachable!() }; let ImportKind::Single {
source, target, ref source_bindings, ref target_bindings, id, ..
} = import.kind
else {
unreachable!()
};
// Skip if the import is of the form `use source as target` and source != target.
if source != target {
return;
}
// Skip if the import was produced by a macro. // Skip if the import was produced by a macro.
if import.parent_scope.expansion != LocalExpnId::ROOT { if import.parent_scope.expansion != LocalExpnId::ROOT {
@ -1323,16 +1325,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// Skip if we are inside a named module (in contrast to an anonymous // Skip if we are inside a named module (in contrast to an anonymous
// module defined by a block). // module defined by a block).
if let ModuleKind::Def(..) = import.parent_scope.module.kind { // Skip if the import is public or was used through non scope-based resolution,
// e.g. through a module-relative path.
if import.used.get() == Some(Used::Other)
|| self.effective_visibilities.is_exported(self.local_def_id(id))
{
return; return;
} }
let mut is_redundant = PerNS { value_ns: None, type_ns: None, macro_ns: None }; let mut is_redundant = true;
let mut redundant_span = 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| { self.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() { if is_redundant && let Ok(binding) = source_bindings[ns].get() {
if binding.res() == Res::Err { if binding.res() == Res::Err {
return; return;
} }
@ -1346,18 +1352,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
target_bindings[ns].get(), target_bindings[ns].get(),
) { ) {
Ok(other_binding) => { Ok(other_binding) => {
is_redundant[ns] = Some( is_redundant =
binding.res() == other_binding.res() && !other_binding.is_ambiguity(), binding.res() == other_binding.res() && !other_binding.is_ambiguity();
); if is_redundant {
redundant_span[ns] = Some((other_binding.span, other_binding.is_import())); redundant_span[ns] =
Some((other_binding.span, other_binding.is_import()));
}
} }
Err(_) => is_redundant[ns] = Some(false), Err(_) => is_redundant = false,
} }
} }
}); });
if !is_redundant.is_empty() && is_redundant.present_items().all(|is_redundant| is_redundant) if is_redundant && !redundant_span.is_empty() {
{
let mut redundant_spans: Vec<_> = redundant_span.present_items().collect(); let mut redundant_spans: Vec<_> = redundant_span.present_items().collect();
redundant_spans.sort(); redundant_spans.sort();
redundant_spans.dedup(); redundant_spans.dedup();
@ -1365,8 +1372,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
UNUSED_IMPORTS, UNUSED_IMPORTS,
id, id,
import.span, import.span,
format!("the item `{ident}` is imported redundantly"), format!("the item `{source}` is imported redundantly"),
BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident), BuiltinLintDiagnostics::RedundantImport(redundant_spans, source),
); );
} }
} }

View File

@ -7,23 +7,22 @@
//! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`. //! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`.
use crate::errors::ImportsCannotReferTo; use crate::errors::ImportsCannotReferTo;
use crate::BindingKey;
use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding}; use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding};
use crate::{BindingKey, Used};
use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
use crate::{ResolutionError, Resolver, Segment, UseError}; use crate::{ResolutionError, Resolver, Segment, UseError};
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::visit::{self, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor};
use rustc_ast::*; use rustc_ast::*;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::{ use rustc_errors::{
codes::*, struct_span_code_err, Applicability, DiagnosticArgValue, ErrCode, IntoDiagnosticArg, codes::*, struct_span_code_err, Applicability, DiagnosticArgValue, IntoDiagnosticArg, StashKey,
StashKey,
}; };
use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS}; use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate}; use rustc_hir::{PrimTy, TraitCandidate};
use rustc_metadata::creader::CStore; use rustc_metadata::creader::CStore;
use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::middle::resolve_bound_vars::Set1;
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
@ -3623,7 +3622,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// whether they can be shadowed by fresh bindings or not, so force an error. // whether they can be shadowed by fresh bindings or not, so force an error.
// issues/33118#issuecomment-233962221 (see below) still applies here, // issues/33118#issuecomment-233962221 (see below) still applies here,
// but we have to ignore it for backward compatibility. // but we have to ignore it for backward compatibility.
self.r.record_use(ident, binding, false); self.r.record_use(ident, binding, Used::Other);
return None; return None;
} }
LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)), LexicalScopeBinding::Item(binding) => (binding.res(), Some(binding)),
@ -3638,7 +3637,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
) if is_syntactic_ambiguity => { ) if is_syntactic_ambiguity => {
// Disambiguate in favor of a unit struct/variant or constant pattern. // Disambiguate in favor of a unit struct/variant or constant pattern.
if let Some(binding) = binding { if let Some(binding) = binding {
self.r.record_use(ident, binding, false); self.r.record_use(ident, binding, Used::Other);
} }
Some(res) Some(res)
} }

View File

@ -175,6 +175,23 @@ enum ImplTraitContext {
Universal, Universal,
} }
/// Used for tracking import use types which will be used for redundant import checking.
/// ### Used::Scope Example
/// ```rust,compile_fail
/// #![deny(unused_imports)]
/// use std::mem::drop;
/// fn main() {
/// let s = Box::new(32);
/// drop(s);
/// }
/// ```
/// Used::Other is for other situations like module-relative uses.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
enum Used {
Scope,
Other,
}
#[derive(Debug)] #[derive(Debug)]
struct BindingError { struct BindingError {
name: Symbol, name: Symbol,
@ -695,7 +712,7 @@ impl<'a> ToNameBinding<'a> for NameBinding<'a> {
enum NameBindingKind<'a> { enum NameBindingKind<'a> {
Res(Res), Res(Res),
Module(Module<'a>), Module(Module<'a>),
Import { binding: NameBinding<'a>, import: Import<'a>, used: Cell<bool> }, Import { binding: NameBinding<'a>, import: Import<'a> },
} }
impl<'a> NameBindingKind<'a> { impl<'a> NameBindingKind<'a> {
@ -1784,15 +1801,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
false false
} }
fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, is_lexical_scope: bool) { fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, used: Used) {
self.record_use_inner(ident, used_binding, is_lexical_scope, used_binding.warn_ambiguity); self.record_use_inner(ident, used_binding, used, used_binding.warn_ambiguity);
} }
fn record_use_inner( fn record_use_inner(
&mut self, &mut self,
ident: Ident, ident: Ident,
used_binding: NameBinding<'a>, used_binding: NameBinding<'a>,
is_lexical_scope: bool, used: Used,
warn_ambiguity: bool, warn_ambiguity: bool,
) { ) {
if let Some((b2, kind)) = used_binding.ambiguity { if let Some((b2, kind)) = used_binding.ambiguity {
@ -1810,27 +1827,35 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
self.ambiguity_errors.push(ambiguity_error); self.ambiguity_errors.push(ambiguity_error);
} }
} }
if let NameBindingKind::Import { import, binding, ref used } = used_binding.kind { if let NameBindingKind::Import { import, binding } = used_binding.kind {
if let ImportKind::MacroUse { warn_private: true } = import.kind { if let ImportKind::MacroUse { warn_private: true } = import.kind {
let msg = format!("macro `{ident}` is private"); let msg = format!("macro `{ident}` is private");
self.lint_buffer().buffer_lint(PRIVATE_MACRO_USE, import.root_id, ident.span, msg); self.lint_buffer().buffer_lint(PRIVATE_MACRO_USE, import.root_id, ident.span, msg);
} }
// Avoid marking `extern crate` items that refer to a name from extern prelude, // Avoid marking `extern crate` items that refer to a name from extern prelude,
// but not introduce it, as used if they are accessed from lexical scope. // but not introduce it, as used if they are accessed from lexical scope.
if is_lexical_scope { if used == Used::Scope {
if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) { if let Some(entry) = self.extern_prelude.get(&ident.normalize_to_macros_2_0()) {
if !entry.introduced_by_item && entry.binding == Some(used_binding) { if !entry.introduced_by_item && entry.binding == Some(used_binding) {
return; return;
} }
} }
} }
used.set(true); let old_used = import.used.get();
import.used.set(true); let new_used = Some(used);
if new_used > old_used {
import.used.set(new_used);
}
if let Some(id) = import.id() { if let Some(id) = import.id() {
self.used_imports.insert(id); self.used_imports.insert(id);
} }
self.add_to_glob_map(import, ident); self.add_to_glob_map(import, ident);
self.record_use_inner(ident, binding, false, warn_ambiguity || binding.warn_ambiguity); self.record_use_inner(
ident,
binding,
Used::Other,
warn_ambiguity || binding.warn_ambiguity,
);
} }
} }
@ -1985,7 +2010,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if !entry.is_import() { if !entry.is_import() {
self.crate_loader(|c| c.process_path_extern(ident.name, ident.span)); self.crate_loader(|c| c.process_path_extern(ident.name, ident.span));
} else if entry.introduced_by_item { } else if entry.introduced_by_item {
self.record_use(ident, binding, false); self.record_use(ident, binding, Used::Other);
} }
} }
binding binding
@ -2115,7 +2140,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let is_import = name_binding.is_import(); let is_import = name_binding.is_import();
let span = name_binding.span; let span = name_binding.span;
if let Res::Def(DefKind::Fn, _) = res { if let Res::Def(DefKind::Fn, _) = res {
self.record_use(ident, name_binding, false); self.record_use(ident, name_binding, Used::Other);
} }
self.main_def = Some(MainDefinition { res, is_import, span }); self.main_def = Some(MainDefinition { res, is_import, span });
} }
@ -2176,6 +2201,8 @@ struct Finalize {
/// Whether to report privacy errors or silently return "no resolution" for them, /// Whether to report privacy errors or silently return "no resolution" for them,
/// similarly to speculative resolution. /// similarly to speculative resolution.
report_private: bool, report_private: bool,
/// Tracks whether an item is used in scope or used relatively to a module.
used: Used,
} }
impl Finalize { impl Finalize {
@ -2184,7 +2211,7 @@ impl Finalize {
} }
fn with_root_span(node_id: NodeId, path_span: Span, root_span: Span) -> Finalize { fn with_root_span(node_id: NodeId, path_span: Span, root_span: Span) -> Finalize {
Finalize { node_id, path_span, root_span, report_private: true } Finalize { node_id, path_span, root_span, report_private: true, used: Used::Other }
} }
} }

View File

@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution;
use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope}; use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive}; use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
use crate::Namespace::*; use crate::Namespace::*;
use crate::{BuiltinMacroState, Determinacy, MacroData}; use crate::{BuiltinMacroState, Determinacy, MacroData, Used};
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
use rustc_ast::expand::StrippedCfgItem; use rustc_ast::expand::StrippedCfgItem;
@ -794,7 +794,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
) { ) {
Ok(binding) => { Ok(binding) => {
let initial_res = initial_binding.map(|initial_binding| { let initial_res = initial_binding.map(|initial_binding| {
self.record_use(ident, initial_binding, false); self.record_use(ident, initial_binding, Used::Other);
initial_binding.res() initial_binding.res()
}); });
let res = binding.res(); let res = binding.res();

View File

@ -22,7 +22,7 @@ use rustc_errors::emitter::{DynEmitter, HumanEmitter, HumanReadableErrorType};
use rustc_errors::json::JsonEmitter; use rustc_errors::json::JsonEmitter;
use rustc_errors::registry::Registry; use rustc_errors::registry::Registry;
use rustc_errors::{ use rustc_errors::{
codes::*, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrCode, codes::*, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticMessage,
ErrorGuaranteed, FatalAbort, FluentBundle, IntoDiagnostic, LazyFallbackBundle, TerminalUrl, ErrorGuaranteed, FatalAbort, FluentBundle, IntoDiagnostic, LazyFallbackBundle, TerminalUrl,
}; };
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;

View File

@ -1,7 +1,5 @@
use super::*; use super::*;
use rustc_data_structures::sync::FreezeLock;
fn init_source_map() -> SourceMap { fn init_source_map() -> SourceMap {
let sm = SourceMap::new(FilePathMapping::empty()); let sm = SourceMap::new(FilePathMapping::empty());
sm.new_source_file(PathBuf::from("blork.rs").into(), "first line.\nsecond line".to_string()); sm.new_source_file(PathBuf::from("blork.rs").into(), "first line.\nsecond line".to_string());

View File

@ -397,7 +397,6 @@ pub trait OpenOptionsExt {
/// ///
/// ```no_run /// ```no_run
/// # #![feature(rustc_private)] /// # #![feature(rustc_private)]
/// use libc;
/// use std::fs::OpenOptions; /// use std::fs::OpenOptions;
/// use std::os::unix::fs::OpenOptionsExt; /// use std::os::unix::fs::OpenOptionsExt;
/// ///

View File

@ -28,7 +28,6 @@ use std::fs::read_to_string;
use std::ops::Deref; use std::ops::Deref;
use std::path::Path; use std::path::Path;
use std::process::exit; use std::process::exit;
use std::string::ToString;
use anstream::println; use anstream::println;

View File

@ -6,7 +6,7 @@ use itertools::Itertools;
use crate::{ use crate::{
hir::{ hir::{
Array, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Literal, LiteralOrConst, Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst,
Movability, Statement, Movability, Statement,
}, },
pretty::{print_generic_args, print_path, print_type_ref}, pretty::{print_generic_args, print_path, print_type_ref},

View File

@ -3,7 +3,7 @@
use std::{fmt, hash::BuildHasherDefault}; use std::{fmt, hash::BuildHasherDefault};
use base_db::CrateId; use base_db::CrateId;
use fst::{self, raw::IndexedValue, Automaton, Streamer}; use fst::{raw::IndexedValue, Automaton, Streamer};
use hir_expand::name::Name; use hir_expand::name::Name;
use indexmap::IndexMap; use indexmap::IndexMap;
use itertools::Itertools; use itertools::Itertools;

View File

@ -2,12 +2,12 @@
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use hir_expand::{ast_id_map::AstIdMap, span_map::SpanMapRef, HirFileId}; use hir_expand::{ast_id_map::AstIdMap, span_map::SpanMapRef};
use syntax::ast::{self, HasModuleItem, HasTypeBounds, IsString}; use syntax::ast::{HasModuleItem, HasTypeBounds, IsString};
use crate::{ use crate::{
generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance}, generics::{GenericParamsCollector, TypeParamData, TypeParamProvenance},
type_ref::{LifetimeRef, TraitBoundModifier, TraitRef}, type_ref::{LifetimeRef, TraitBoundModifier},
LocalLifetimeParamId, LocalTypeOrConstParamId, LocalLifetimeParamId, LocalTypeOrConstParamId,
}; };

View File

@ -1,13 +1,12 @@
//! `ItemTree` debug printer. //! `ItemTree` debug printer.
use std::fmt::{self, Write}; use std::fmt::Write;
use span::ErasedFileAstId; use span::ErasedFileAstId;
use crate::{ use crate::{
generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget}, generics::{WherePredicate, WherePredicateTypeTarget},
pretty::{print_path, print_type_bounds, print_type_ref}, pretty::{print_path, print_type_bounds, print_type_ref},
visibility::RawVisibility,
}; };
use super::*; use super::*;

View File

@ -57,7 +57,7 @@ pub mod proc_macro;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
use std::{cmp::Ord, ops::Deref}; use std::ops::Deref;
use base_db::{CrateId, Edition, FileId}; use base_db::{CrateId, Edition, FileId};
use hir_expand::{ use hir_expand::{

View File

@ -2,7 +2,7 @@
//! //!
//! Originates from `rustc_hir::pat_util` //! Originates from `rustc_hir::pat_util`
use std::iter::{Enumerate, ExactSizeIterator}; use std::iter::Enumerate;
pub(crate) struct EnumerateAndAdjust<I> { pub(crate) struct EnumerateAndAdjust<I> {
enumerate: Enumerate<I>, enumerate: Enumerate<I>,

View File

@ -4,11 +4,7 @@
use std::cmp; use std::cmp;
use chalk_ir::TyKind; use chalk_ir::TyKind;
use hir_def::{ use hir_def::builtin_type::{BuiltinInt, BuiltinUint};
builtin_type::{BuiltinInt, BuiltinUint},
resolver::HasResolver,
};
use hir_expand::mod_path::ModPath;
use super::*; use super::*;

View File

@ -1,6 +1,6 @@
//! This module generates a polymorphic MIR from a hir body //! This module generates a polymorphic MIR from a hir body
use std::{fmt::Write, iter, mem}; use std::{fmt::Write, mem};
use base_db::{salsa::Cycle, FileId}; use base_db::{salsa::Cycle, FileId};
use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind}; use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
@ -14,23 +14,19 @@ use hir_def::{
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
path::Path, path::Path,
resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs}, resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs},
AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId, AdtId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
Lookup, TraitId, TupleId, TypeOrConstParamId, Lookup, TraitId, TupleId, TypeOrConstParamId,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use la_arena::ArenaMap;
use rustc_hash::FxHashMap;
use syntax::TextRange; use syntax::TextRange;
use triomphe::Arc; use triomphe::Arc;
use crate::{ use crate::{
consteval::ConstEvalError, consteval::ConstEvalError,
db::{HirDatabase, InternedClosure}, db::InternedClosure,
display::HirDisplay,
infer::{CaptureKind, CapturedItem, TypeMismatch}, infer::{CaptureKind, CapturedItem, TypeMismatch},
inhabitedness::is_ty_uninhabited_from, inhabitedness::is_ty_uninhabited_from,
layout::LayoutError, layout::LayoutError,
mapping::ToChalk,
static_lifetime, static_lifetime,
traits::FnTrait, traits::FnTrait,
utils::{generics, ClosureSubst}, utils::{generics, ClosureSubst},

View File

@ -1,6 +1,6 @@
//! MIR lowering for patterns //! MIR lowering for patterns
use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId}; use hir_def::AssocItemId;
use crate::BindingMode; use crate::BindingMode;

View File

@ -1,4 +1,4 @@
use hir::{self, HasCrate, HasVisibility}; use hir::{HasCrate, HasVisibility};
use ide_db::{path_transform::PathTransform, FxHashSet}; use ide_db::{path_transform::PathTransform, FxHashSet};
use syntax::{ use syntax::{
ast::{ ast::{

View File

@ -31,7 +31,7 @@
//! } //! }
//! ``` //! ```
use hir::{self, HasAttrs}; use hir::HasAttrs;
use ide_db::{ use ide_db::{
documentation::HasDocs, path_transform::PathTransform, documentation::HasDocs, path_transform::PathTransform,
syntax_helpers::insert_whitespace_into_node, traits::get_missing_assoc_items, SymbolKind, syntax_helpers::insert_whitespace_into_node, traits::get_missing_assoc_items, SymbolKind,

View File

@ -31,7 +31,7 @@ use base_db::{
salsa::{self, ParallelDatabase}, salsa::{self, ParallelDatabase},
SourceDatabaseExt, SourceRootId, Upcast, SourceDatabaseExt, SourceRootId, Upcast,
}; };
use fst::{self, raw::IndexedValue, Automaton, Streamer}; use fst::{raw::IndexedValue, Automaton, Streamer};
use hir::{ use hir::{
db::HirDatabase, db::HirDatabase,
import_map::{AssocSearchMode, SearchMode}, import_map::{AssocSearchMode, SearchMode},

View File

@ -4,7 +4,7 @@ use std::mem;
use cfg::{CfgAtom, CfgExpr}; use cfg::{CfgAtom, CfgExpr};
use ide::{Cancellable, CrateId, FileId, RunnableKind, TestId}; use ide::{Cancellable, CrateId, FileId, RunnableKind, TestId};
use project_model::{self, CargoFeatures, ManifestPath, TargetKind}; use project_model::{CargoFeatures, ManifestPath, TargetKind};
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use vfs::AbsPathBuf; use vfs::AbsPathBuf;

View File

@ -13,7 +13,7 @@ use ide_db::{
LineIndexDatabase, LineIndexDatabase,
}; };
use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice}; use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
use lsp_types::{self, lsif}; use lsp_types::lsif;
use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource}; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use vfs::{AbsPathBuf, Vfs}; use vfs::{AbsPathBuf, Vfs};

View File

@ -1,5 +1,4 @@
//! //!
use std::{convert::TryFrom, iter::FromIterator};
use crate::parenthesized::Parenthesized; use crate::parenthesized::Parenthesized;
use heck::ToUpperCamelCase; use heck::ToUpperCamelCase;

View File

@ -5,7 +5,6 @@ use crate::durability::Durability;
use crate::plumbing::QueryStorageOps; use crate::plumbing::QueryStorageOps;
use crate::Query; use crate::Query;
use crate::QueryTable; use crate::QueryTable;
use std::iter::FromIterator;
/// Additional methods on queries that can be used to "peek into" /// Additional methods on queries that can be used to "peek into"
/// their current state. These methods are meant for debugging and /// their current state. These methods are meant for debugging and

View File

@ -13,7 +13,6 @@ use crate::Runtime;
use crate::{Database, DatabaseKeyIndex, QueryDb, Revision}; use crate::{Database, DatabaseKeyIndex, QueryDb, Revision};
use parking_lot::RwLock; use parking_lot::RwLock;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::convert::TryFrom;
use std::hash::Hash; use std::hash::Hash;
use std::marker::PhantomData; use std::marker::PhantomData;
use triomphe::Arc; use triomphe::Arc;

View File

@ -14,7 +14,6 @@ use crate::Runtime;
use crate::{DatabaseKeyIndex, QueryDb}; use crate::{DatabaseKeyIndex, QueryDb};
use indexmap::map::Entry; use indexmap::map::Entry;
use parking_lot::RwLock; use parking_lot::RwLock;
use std::convert::TryFrom;
use std::iter; use std::iter;
use tracing::debug; use tracing::debug;

View File

@ -13,7 +13,6 @@ use crate::{Database, DatabaseKeyIndex, QueryDb};
use parking_lot::RwLock; use parking_lot::RwLock;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::convert::From;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
use triomphe::Arc; use triomphe::Arc;

View File

@ -66,7 +66,6 @@ pub mod bar {
fn g() { fn g() {
use self::g; //~ ERROR unused import: `self::g` use self::g; //~ ERROR unused import: `self::g`
//~^ ERROR the item `g` is imported redundantly
fn f() { fn f() {
self::g(); self::g();
} }
@ -76,7 +75,6 @@ fn g() {
#[allow(unused_variables)] #[allow(unused_variables)]
fn h() { fn h() {
use test2::foo; //~ ERROR unused import: `test2::foo` use test2::foo; //~ ERROR unused import: `test2::foo`
//~^ ERROR the item `foo` is imported redundantly
let foo = 0; let foo = 0;
} }

View File

@ -34,36 +34,14 @@ error: unused import: `foo::Square`
LL | use 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` error: unused import: `self::g`
--> $DIR/lint-unused-imports.rs:68:9 --> $DIR/lint-unused-imports.rs:68:9
| |
LL | use self::g; 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` error: unused import: `test2::foo`
--> $DIR/lint-unused-imports.rs:78:9 --> $DIR/lint-unused-imports.rs:77:9
| |
LL | use test2::foo; LL | use test2::foo;
| ^^^^^^^^^^ | ^^^^^^^^^^
@ -74,5 +52,5 @@ error: unused import: `test::B2`
LL | use test::B2; LL | use test::B2;
| ^^^^^^^^ | ^^^^^^^^
error: aborting due to 10 previous errors error: aborting due to 8 previous errors

View File

@ -0,0 +1,19 @@
//@ check-pass
#![warn(unused_imports)]
use std::option::Option::Some;//~ WARNING the item `Some` is imported redundantly
use std::option::Option::None; //~ WARNING the item `None` is imported redundantly
use std::result::Result::Ok;//~ WARNING the item `Ok` is imported redundantly
use std::result::Result::Err;//~ WARNING the item `Err` is imported redundantly
use std::convert::{TryFrom, TryInto};
fn main() {
let _a: Option<i32> = Some(1);
let _b: Option<i32> = None;
let _c: Result<i32, String> = Ok(1);
let _d: Result<i32, &str> = Err("error");
let _e: Result<i32, _> = 8u8.try_into();
let _f: Result<i32, _> = i32::try_from(8u8);
}

View File

@ -0,0 +1,44 @@
warning: the item `Some` is imported redundantly
--> $DIR/use-redundant-prelude-rust-2015.rs:5:5
|
LL | use std::option::Option::Some;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
|
= note: the item `Some` is already defined here
|
note: the lint level is defined here
--> $DIR/use-redundant-prelude-rust-2015.rs:2:9
|
LL | #![warn(unused_imports)]
| ^^^^^^^^^^^^^^
warning: the item `None` is imported redundantly
--> $DIR/use-redundant-prelude-rust-2015.rs:6:5
|
LL | use std::option::Option::None;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
|
= note: the item `None` is already defined here
warning: the item `Ok` is imported redundantly
--> $DIR/use-redundant-prelude-rust-2015.rs:8:5
|
LL | use std::result::Result::Ok;
| ^^^^^^^^^^^^^^^^^^^^^^^
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
|
= note: the item `Ok` is already defined here
warning: the item `Err` is imported redundantly
--> $DIR/use-redundant-prelude-rust-2015.rs:9:5
|
LL | use std::result::Result::Err;
| ^^^^^^^^^^^^^^^^^^^^^^^^
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
|
= note: the item `Err` is already defined here
warning: 4 warnings emitted

View File

@ -0,0 +1,11 @@
//@ check-pass
//@ edition:2021
#![warn(unused_imports)]
use std::convert::TryFrom;//~ WARNING the item `TryFrom` is imported redundantly
use std::convert::TryInto;//~ WARNING the item `TryInto` is imported redundantly
fn main() {
let _e: Result<i32, _> = 8u8.try_into();
let _f: Result<i32, _> = i32::try_from(8u8);
}

View File

@ -0,0 +1,26 @@
warning: the item `TryFrom` is imported redundantly
--> $DIR/use-redundant-prelude-rust-2021.rs:5:5
|
LL | use std::convert::TryFrom;
| ^^^^^^^^^^^^^^^^^^^^^
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
|
= note: the item `TryFrom` is already defined here
|
note: the lint level is defined here
--> $DIR/use-redundant-prelude-rust-2021.rs:3:9
|
LL | #![warn(unused_imports)]
| ^^^^^^^^^^^^^^
warning: the item `TryInto` is imported redundantly
--> $DIR/use-redundant-prelude-rust-2021.rs:6:5
|
LL | use std::convert::TryInto;
| ^^^^^^^^^^^^^^^^^^^^^
--> $SRC_DIR/std/src/prelude/mod.rs:LL:COL
|
= note: the item `TryInto` is already defined here
warning: 2 warnings emitted

View File

@ -6,6 +6,7 @@
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
#![allow(dropping_copy_types)] #![allow(dropping_copy_types)]
#![allow(unused_imports)]
//~ WARNING unused extern crate //~ WARNING unused extern crate
// Shouldn't suggest changing to `use`, as `another_name` // Shouldn't suggest changing to `use`, as `another_name`

View File

@ -6,6 +6,7 @@
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
#![allow(dropping_copy_types)] #![allow(dropping_copy_types)]
#![allow(unused_imports)]
extern crate core; //~ WARNING unused extern crate extern crate core; //~ WARNING unused extern crate
// Shouldn't suggest changing to `use`, as `another_name` // Shouldn't suggest changing to `use`, as `another_name`

View File

@ -1,5 +1,5 @@
warning: unused extern crate warning: unused extern crate
--> $DIR/remove-extern-crate.rs:10:1 --> $DIR/remove-extern-crate.rs:11:1
| |
LL | extern crate core; LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ help: remove it | ^^^^^^^^^^^^^^^^^^ help: remove it
@ -12,7 +12,7 @@ LL | #![warn(rust_2018_idioms)]
= note: `#[warn(unused_extern_crates)]` implied by `#[warn(rust_2018_idioms)]` = note: `#[warn(unused_extern_crates)]` implied by `#[warn(rust_2018_idioms)]`
warning: `extern crate` is not idiomatic in the new edition warning: `extern crate` is not idiomatic in the new edition
--> $DIR/remove-extern-crate.rs:34:5 --> $DIR/remove-extern-crate.rs:35:5
| |
LL | extern crate core; LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
@ -23,7 +23,7 @@ LL | use core;
| ~~~ | ~~~
warning: `extern crate` is not idiomatic in the new edition warning: `extern crate` is not idiomatic in the new edition
--> $DIR/remove-extern-crate.rs:44:5 --> $DIR/remove-extern-crate.rs:45:5
| |
LL | pub extern crate core; LL | pub extern crate core;
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^