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:
parent
d3df8ff851
commit
a61126cef6
52 changed files with 283 additions and 167 deletions
|
@ -8,11 +8,11 @@
|
|||
use crate::def_collector::collect_definitions;
|
||||
use crate::imports::{ImportData, ImportKind};
|
||||
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::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot};
|
||||
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError};
|
||||
use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError};
|
||||
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError};
|
||||
use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, Used, VisResolutionError};
|
||||
|
||||
use rustc_ast::visit::{self, AssocCtxt, Visitor};
|
||||
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_id,
|
||||
vis: Cell::new(Some(vis)),
|
||||
used: Cell::new(false),
|
||||
used: Default::default(),
|
||||
});
|
||||
|
||||
self.r.indeterminate_imports.push(import);
|
||||
|
@ -885,7 +885,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
|||
span: item.span,
|
||||
module_path: Vec::new(),
|
||||
vis: Cell::new(Some(vis)),
|
||||
used: Cell::new(used),
|
||||
used: Cell::new(used.then_some(Used::Other)),
|
||||
});
|
||||
self.r.potentially_unused_imports.push(import);
|
||||
let imported_binding = self.r.import(binding, import);
|
||||
|
@ -1090,7 +1090,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
|
|||
span,
|
||||
module_path: Vec::new(),
|
||||
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,
|
||||
module_path: Vec::new(),
|
||||
vis: Cell::new(Some(vis)),
|
||||
used: Cell::new(true),
|
||||
used: Cell::new(Some(Used::Other)),
|
||||
});
|
||||
let import_binding = self.r.import(binding, import);
|
||||
self.r.define(self.r.graph_root, ident, MacroNS, import_binding);
|
||||
|
|
|
@ -27,9 +27,10 @@ use crate::imports::ImportKind;
|
|||
use crate::module_to_string;
|
||||
use crate::Resolver;
|
||||
|
||||
use crate::NameBindingKind;
|
||||
use rustc_ast as ast;
|
||||
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_errors::{pluralize, MultiSpan};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
@ -38,14 +39,14 @@ use rustc_session::lint::BuiltinLintDiagnostics;
|
|||
use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
struct UnusedImport<'a> {
|
||||
use_tree: &'a ast::UseTree,
|
||||
struct UnusedImport {
|
||||
use_tree: ast::UseTree,
|
||||
use_tree_id: ast::NodeId,
|
||||
item_span: Span,
|
||||
unused: UnordSet<ast::NodeId>,
|
||||
}
|
||||
|
||||
impl<'a> UnusedImport<'a> {
|
||||
impl UnusedImport {
|
||||
fn add(&mut self, id: ast::NodeId) {
|
||||
self.unused.insert(id);
|
||||
}
|
||||
|
@ -54,7 +55,7 @@ impl<'a> UnusedImport<'a> {
|
|||
struct UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
||||
r: &'a mut Resolver<'b, 'tcx>,
|
||||
/// 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>,
|
||||
base_use_tree: Option<&'a ast::UseTree>,
|
||||
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 = self.base_use_tree.unwrap();
|
||||
let use_tree = self.base_use_tree.unwrap().clone();
|
||||
let item_span = self.item_span;
|
||||
|
||||
self.unused_imports.entry(id).or_insert_with(|| UnusedImport {
|
||||
|
@ -197,7 +198,7 @@ enum UnusedSpanResult {
|
|||
}
|
||||
|
||||
fn calc_unused_spans(
|
||||
unused_import: &UnusedImport<'_>,
|
||||
unused_import: &UnusedImport,
|
||||
use_tree: &ast::UseTree,
|
||||
use_tree_id: ast::NodeId,
|
||||
) -> UnusedSpanResult {
|
||||
|
@ -287,7 +288,7 @@ impl Resolver<'_, '_> {
|
|||
|
||||
for import in self.potentially_unused_imports.iter() {
|
||||
match import.kind {
|
||||
_ if import.used.get()
|
||||
_ if import.used.get().is_some()
|
||||
|| import.expect_vis().is_public()
|
||||
|| import.span.is_dummy() =>
|
||||
{
|
||||
|
@ -336,7 +337,7 @@ impl Resolver<'_, '_> {
|
|||
|
||||
for unused in visitor.unused_imports.values() {
|
||||
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::FlatUnused(span, remove) => {
|
||||
fixes.push((remove, String::new()));
|
||||
|
@ -483,5 +484,30 @@ impl Resolver<'_, '_> {
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{ImplTraitContext, Resolver};
|
||||
use rustc_ast::visit::{self, FnKind};
|
||||
use rustc_ast::visit::FnKind;
|
||||
use rustc_ast::*;
|
||||
use rustc_expand::expand::AstFragment;
|
||||
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
|
||||
|
|
|
@ -33,8 +33,8 @@ use crate::errors::{AddedMacroUse, ChangeImportBinding, ChangeImportBindingSugge
|
|||
use crate::errors::{ConsiderAddingADerive, ExplicitUnsafeTraits, MaybeMissingMacroRulesName};
|
||||
use crate::imports::{Import, ImportKind};
|
||||
use crate::late::{PatternSource, Rib};
|
||||
use crate::path_names_to_string;
|
||||
use crate::{errors as errs, BindingKey};
|
||||
use crate::{path_names_to_string, Used};
|
||||
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize};
|
||||
use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot};
|
||||
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,
|
||||
// since this diagnostic already covers that import.
|
||||
self.record_use(ident, binding, false);
|
||||
self.record_use(ident, binding, Used::Other);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ use rustc_span::Span;
|
|||
use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
|
||||
use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
|
||||
use crate::macros::{sub_namespace_match, MacroRulesScope};
|
||||
use crate::BindingKey;
|
||||
use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
|
||||
use crate::{BindingKey, Used};
|
||||
use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
|
||||
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res};
|
||||
use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak};
|
||||
|
@ -339,7 +339,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
finalize,
|
||||
finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
|
||||
ignore_binding,
|
||||
);
|
||||
if let Ok(binding) = item {
|
||||
|
@ -506,7 +506,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
ns,
|
||||
adjusted_parent_scope,
|
||||
!matches!(scope_set, ScopeSet::Late(..)),
|
||||
finalize,
|
||||
finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }),
|
||||
ignore_binding,
|
||||
);
|
||||
match binding {
|
||||
|
@ -857,7 +857,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
.into_iter()
|
||||
.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 {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@ use crate::errors::{
|
|||
use crate::Determinacy::{self, *};
|
||||
use crate::Namespace::*;
|
||||
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::{NameBinding, NameBindingData, NameBindingKind, PathResult};
|
||||
use crate::{NameBinding, NameBindingData, NameBindingKind, PathResult, Used};
|
||||
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
@ -173,7 +173,7 @@ pub(crate) struct ImportData<'a> {
|
|||
/// The resolution of `module_path`.
|
||||
pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
|
||||
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,
|
||||
|
@ -286,7 +286,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
|
||||
self.arenas.alloc_name_binding(NameBindingData {
|
||||
kind: NameBindingKind::Import { binding, import, used: Cell::new(false) },
|
||||
kind: NameBindingKind::Import { binding, import },
|
||||
ambiguity: None,
|
||||
warn_ambiguity: false,
|
||||
span: import.span,
|
||||
|
@ -485,9 +485,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
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() {
|
||||
import.used.set(true);
|
||||
import.used.set(Some(Used::Other));
|
||||
if let Some(id) = import.id() {
|
||||
self.used_imports.insert(id);
|
||||
}
|
||||
|
@ -1056,11 +1056,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
&& initial_binding.is_extern_crate()
|
||||
&& !initial_binding.is_import()
|
||||
{
|
||||
this.record_use(
|
||||
ident,
|
||||
target_binding,
|
||||
import.module_path.is_empty(),
|
||||
);
|
||||
let used = if import.module_path.is_empty() {
|
||||
Used::Scope
|
||||
} else {
|
||||
Used::Other
|
||||
};
|
||||
this.record_use(ident, target_binding, used);
|
||||
}
|
||||
}
|
||||
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");
|
||||
None
|
||||
}
|
||||
|
||||
fn check_for_redundant_imports(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
import: Import<'a>,
|
||||
source_bindings: &PerNS<Cell<Result<NameBinding<'a>, Determinacy>>>,
|
||||
target_bindings: &PerNS<Cell<Option<NameBinding<'a>>>>,
|
||||
target: Ident,
|
||||
) {
|
||||
pub(crate) fn check_for_redundant_imports(&mut self, import: Import<'a>) {
|
||||
// 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.
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
|
||||
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 };
|
||||
|
||||
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 {
|
||||
return;
|
||||
}
|
||||
|
@ -1346,18 +1352,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
target_bindings[ns].get(),
|
||||
) {
|
||||
Ok(other_binding) => {
|
||||
is_redundant[ns] = Some(
|
||||
binding.res() == other_binding.res() && !other_binding.is_ambiguity(),
|
||||
);
|
||||
redundant_span[ns] = Some((other_binding.span, other_binding.is_import()));
|
||||
is_redundant =
|
||||
binding.res() == other_binding.res() && !other_binding.is_ambiguity();
|
||||
if is_redundant {
|
||||
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();
|
||||
redundant_spans.sort();
|
||||
redundant_spans.dedup();
|
||||
|
@ -1365,8 +1372,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
UNUSED_IMPORTS,
|
||||
id,
|
||||
import.span,
|
||||
format!("the item `{ident}` is imported redundantly"),
|
||||
BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
|
||||
format!("the item `{source}` is imported redundantly"),
|
||||
BuiltinLintDiagnostics::RedundantImport(redundant_spans, source),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,23 +7,22 @@
|
|||
//! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`.
|
||||
|
||||
use crate::errors::ImportsCannotReferTo;
|
||||
use crate::BindingKey;
|
||||
use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding};
|
||||
use crate::{BindingKey, Used};
|
||||
use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
|
||||
use crate::{ResolutionError, Resolver, Segment, UseError};
|
||||
|
||||
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_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
|
||||
use rustc_errors::{
|
||||
codes::*, struct_span_code_err, Applicability, DiagnosticArgValue, ErrCode, IntoDiagnosticArg,
|
||||
StashKey,
|
||||
codes::*, struct_span_code_err, Applicability, DiagnosticArgValue, IntoDiagnosticArg, StashKey,
|
||||
};
|
||||
use rustc_hir::def::Namespace::{self, *};
|
||||
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::{BindingAnnotation, PrimTy, TraitCandidate};
|
||||
use rustc_hir::{PrimTy, TraitCandidate};
|
||||
use rustc_metadata::creader::CStore;
|
||||
use rustc_middle::middle::resolve_bound_vars::Set1;
|
||||
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.
|
||||
// issues/33118#issuecomment-233962221 (see below) still applies here,
|
||||
// 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;
|
||||
}
|
||||
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 => {
|
||||
// Disambiguate in favor of a unit struct/variant or constant pattern.
|
||||
if let Some(binding) = binding {
|
||||
self.r.record_use(ident, binding, false);
|
||||
self.r.record_use(ident, binding, Used::Other);
|
||||
}
|
||||
Some(res)
|
||||
}
|
||||
|
|
|
@ -175,6 +175,23 @@ enum ImplTraitContext {
|
|||
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)]
|
||||
struct BindingError {
|
||||
name: Symbol,
|
||||
|
@ -695,7 +712,7 @@ impl<'a> ToNameBinding<'a> for NameBinding<'a> {
|
|||
enum NameBindingKind<'a> {
|
||||
Res(Res),
|
||||
Module(Module<'a>),
|
||||
Import { binding: NameBinding<'a>, import: Import<'a>, used: Cell<bool> },
|
||||
Import { binding: NameBinding<'a>, import: Import<'a> },
|
||||
}
|
||||
|
||||
impl<'a> NameBindingKind<'a> {
|
||||
|
@ -1784,15 +1801,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
false
|
||||
}
|
||||
|
||||
fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, is_lexical_scope: bool) {
|
||||
self.record_use_inner(ident, used_binding, is_lexical_scope, used_binding.warn_ambiguity);
|
||||
fn record_use(&mut self, ident: Ident, used_binding: NameBinding<'a>, used: Used) {
|
||||
self.record_use_inner(ident, used_binding, used, used_binding.warn_ambiguity);
|
||||
}
|
||||
|
||||
fn record_use_inner(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
used_binding: NameBinding<'a>,
|
||||
is_lexical_scope: bool,
|
||||
used: Used,
|
||||
warn_ambiguity: bool,
|
||||
) {
|
||||
if let Some((b2, kind)) = used_binding.ambiguity {
|
||||
|
@ -1810,27 +1827,35 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
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 {
|
||||
let msg = format!("macro `{ident}` is private");
|
||||
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,
|
||||
// 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 !entry.introduced_by_item && entry.binding == Some(used_binding) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
used.set(true);
|
||||
import.used.set(true);
|
||||
let old_used = import.used.get();
|
||||
let new_used = Some(used);
|
||||
if new_used > old_used {
|
||||
import.used.set(new_used);
|
||||
}
|
||||
if let Some(id) = import.id() {
|
||||
self.used_imports.insert(id);
|
||||
}
|
||||
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() {
|
||||
self.crate_loader(|c| c.process_path_extern(ident.name, ident.span));
|
||||
} else if entry.introduced_by_item {
|
||||
self.record_use(ident, binding, false);
|
||||
self.record_use(ident, binding, Used::Other);
|
||||
}
|
||||
}
|
||||
binding
|
||||
|
@ -2115,7 +2140,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
let is_import = name_binding.is_import();
|
||||
let span = name_binding.span;
|
||||
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 });
|
||||
}
|
||||
|
@ -2176,6 +2201,8 @@ struct Finalize {
|
|||
/// Whether to report privacy errors or silently return "no resolution" for them,
|
||||
/// similarly to speculative resolution.
|
||||
report_private: bool,
|
||||
/// Tracks whether an item is used in scope or used relatively to a module.
|
||||
used: Used,
|
||||
}
|
||||
|
||||
impl Finalize {
|
||||
|
@ -2184,7 +2211,7 @@ impl 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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::errors::CannotDetermineMacroResolution;
|
|||
use crate::errors::{self, AddAsNonDerive, CannotFindIdentInThisScope};
|
||||
use crate::errors::{MacroExpectedFound, RemoveSurroundingDerive};
|
||||
use crate::Namespace::*;
|
||||
use crate::{BuiltinMacroState, Determinacy, MacroData};
|
||||
use crate::{BuiltinMacroState, Determinacy, MacroData, Used};
|
||||
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
|
||||
use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
|
||||
use rustc_ast::expand::StrippedCfgItem;
|
||||
|
@ -794,7 +794,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
) {
|
||||
Ok(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()
|
||||
});
|
||||
let res = binding.res();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue