Move lookup_path and similar into clippy_utils::paths

This commit is contained in:
Alex Macleod 2025-05-04 17:07:20 +00:00
parent b768fbe4bc
commit f23772ce8c
15 changed files with 243 additions and 236 deletions

View file

@ -1,4 +1,4 @@
use clippy_utils::PathNS;
use clippy_utils::paths::{PathNS, find_crates, lookup_path};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diag};
use rustc_hir::PrimTy;
@ -148,7 +148,7 @@ pub fn create_disallowed_map<const REPLACEMENT_ALLOWED: bool>(
for disallowed_path in disallowed_paths {
let path = disallowed_path.path();
let sym_path: Vec<Symbol> = path.split("::").map(Symbol::intern).collect();
let mut resolutions = clippy_utils::lookup_path(tcx, ns, &sym_path);
let mut resolutions = lookup_path(tcx, ns, &sym_path);
resolutions.retain(|&def_id| def_kind_predicate(tcx.def_kind(def_id)));
let (prim_ty, found_prim_ty) = if let &[name] = sym_path.as_slice()
@ -164,10 +164,10 @@ pub fn create_disallowed_map<const REPLACEMENT_ALLOWED: bool>(
&& !disallowed_path.allow_invalid
// Don't warn about unloaded crates:
// https://github.com/rust-lang/rust-clippy/pull/14397#issuecomment-2848328221
&& (sym_path.len() < 2 || !clippy_utils::find_crates(tcx, sym_path[0]).is_empty())
&& (sym_path.len() < 2 || !find_crates(tcx, sym_path[0]).is_empty())
{
// Relookup the path in an arbitrary namespace to get a good `expected, found` message
let found_def_ids = clippy_utils::lookup_path(tcx, PathNS::Arbitrary, &sym_path);
let found_def_ids = lookup_path(tcx, PathNS::Arbitrary, &sym_path);
let message = if let Some(&def_id) = found_def_ids.first() {
let (article, description) = tcx.article_and_description(def_id);
format!("expected a {predicate_description}, found {article} {description}")

View file

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_config::types::{DisallowedPathWithoutReplacement, create_disallowed_map};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{PathNS, paths};
use clippy_utils::paths::{self, PathNS};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, DefIdMap};
use rustc_lint::{LateContext, LateLintPass};

View file

@ -1,8 +1,8 @@
use clippy_config::Conf;
use clippy_config::types::{DisallowedPath, create_disallowed_map};
use clippy_utils::PathNS;
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::macros::macro_backtrace;
use clippy_utils::paths::PathNS;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefIdMap;

View file

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_config::types::{DisallowedPath, create_disallowed_map};
use clippy_utils::PathNS;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::paths::PathNS;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{Expr, ExprKind};

View file

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_config::types::{DisallowedPath, create_disallowed_map};
use clippy_utils::PathNS;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::paths::PathNS;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefIdMap;

View file

@ -10,7 +10,7 @@ mod too_many_lines;
use clippy_config::Conf;
use clippy_utils::msrvs::Msrv;
use clippy_utils::{PathNS, lookup_path_str};
use clippy_utils::paths::{PathNS, lookup_path_str};
use rustc_hir as hir;
use rustc_hir::intravisit;
use rustc_lint::{LateContext, LateLintPass};

View file

@ -1,7 +1,7 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::paths::{PathNS, lookup_path_str};
use clippy_utils::source::SpanRangeExt;
use clippy_utils::{PathNS, lookup_path_str};
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefIdMap;

View file

@ -1,8 +1,9 @@
use clippy_config::Conf;
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::paths::{self, PathNS, find_crates, lookup_path_str};
use clippy_utils::visitors::for_each_expr;
use clippy_utils::{PathNS, find_crates, fn_def_id, is_no_std_crate, lookup_path_str, path_def_id, paths, sym};
use clippy_utils::{fn_def_id, is_no_std_crate, path_def_id, sym};
use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};

View file

@ -1,5 +1,5 @@
use clippy_utils::paths::PathLookup;
use clippy_utils::{PathNS, sym, type_path, value_path};
use clippy_utils::paths::{PathLookup, PathNS};
use clippy_utils::{sym, type_path, value_path};
// Paths inside rustc
pub static EARLY_LINT_PASS: PathLookup = type_path!(rustc_lint::passes::EarlyLintPass);

View file

@ -1,6 +1,7 @@
use crate::internal_paths;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{PathNS, lookup_path, path_def_id, peel_ref_operators};
use clippy_utils::paths::{PathNS, lookup_path};
use clippy_utils::{path_def_id, peel_ref_operators};
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};

View file

@ -96,30 +96,29 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::packed::Pu128;
use rustc_data_structures::unhash::UnhashMap;
use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
use rustc_hir::def::Namespace::{MacroNS, TypeNS, ValueNS};
use rustc_hir::def::{DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId, LocalModDefId};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::definitions::{DefPath, DefPathData};
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
use rustc_hir::{
self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext,
CoroutineDesugaring, CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg,
GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource,
Mutability, Node, OwnerId, OwnerNode, Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt,
StmtKind, TraitFn, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def,
self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, CoroutineDesugaring,
CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl,
ImplItem, ImplItemKind, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode,
Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem,
TraitItemKind, TraitRef, TyKind, UnOp, def,
};
use rustc_lexer::{TokenKind, tokenize};
use rustc_lint::{LateContext, Level, Lint, LintContext};
use rustc_middle::hir::nested_filter;
use rustc_middle::hir::place::PlaceBase;
use rustc_middle::lint::LevelAndSource;
use rustc_middle::mir::{AggregateKind, Operand, RETURN_PLACE, Rvalue, StatementKind, TerminatorKind};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{
self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgKind, GenericArgsRef, IntTy, Ty,
TyCtxt, TypeFlags, TypeVisitableExt, UintTy, UpvarCapture,
self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, GenericArgKind, GenericArgsRef, IntTy, Ty, TyCtxt,
TypeFlags, TypeVisitableExt, UintTy, UpvarCapture,
};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::source_map::SourceMap;
@ -132,7 +131,6 @@ use crate::consts::{ConstEvalCtxt, Constant, mir_to_const};
use crate::higher::Range;
use crate::ty::{adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type};
use crate::visitors::for_each_expr_without_closures;
use rustc_middle::hir::nested_filter;
#[macro_export]
macro_rules! extract_msrv_attr {
@ -240,7 +238,7 @@ pub fn is_in_const_context(cx: &LateContext<'_>) -> bool {
/// * const blocks (or inline consts)
/// * associated constants
pub fn is_inside_always_const_context(tcx: TyCtxt<'_>, hir_id: HirId) -> bool {
use ConstContext::{Const, ConstFn, Static};
use rustc_hir::ConstContext::{Const, ConstFn, Static};
let Some(ctx) = tcx.hir_body_const_context(tcx.hir_enclosing_body_owner(hir_id)) else {
return false;
};
@ -513,207 +511,6 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
path_res(cx, maybe_path).opt_def_id()
}
fn find_primitive_impls(tcx: TyCtxt<'_>, name: Symbol) -> &[DefId] {
let ty = match name {
sym::bool => SimplifiedType::Bool,
sym::char => SimplifiedType::Char,
sym::str => SimplifiedType::Str,
sym::array => SimplifiedType::Array,
sym::slice => SimplifiedType::Slice,
// FIXME: rustdoc documents these two using just `pointer`.
//
// Maybe this is something we should do here too.
sym::const_ptr => SimplifiedType::Ptr(Mutability::Not),
sym::mut_ptr => SimplifiedType::Ptr(Mutability::Mut),
sym::isize => SimplifiedType::Int(IntTy::Isize),
sym::i8 => SimplifiedType::Int(IntTy::I8),
sym::i16 => SimplifiedType::Int(IntTy::I16),
sym::i32 => SimplifiedType::Int(IntTy::I32),
sym::i64 => SimplifiedType::Int(IntTy::I64),
sym::i128 => SimplifiedType::Int(IntTy::I128),
sym::usize => SimplifiedType::Uint(UintTy::Usize),
sym::u8 => SimplifiedType::Uint(UintTy::U8),
sym::u16 => SimplifiedType::Uint(UintTy::U16),
sym::u32 => SimplifiedType::Uint(UintTy::U32),
sym::u64 => SimplifiedType::Uint(UintTy::U64),
sym::u128 => SimplifiedType::Uint(UintTy::U128),
sym::f32 => SimplifiedType::Float(FloatTy::F32),
sym::f64 => SimplifiedType::Float(FloatTy::F64),
_ => return &[],
};
tcx.incoherent_impls(ty)
}
fn non_local_item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, ns: PathNS, name: Symbol) -> Option<DefId> {
match tcx.def_kind(def_id) {
DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx.module_children(def_id).iter().find_map(|child| {
if child.ident.name == name && ns.matches(child.res.ns()) {
child.res.opt_def_id()
} else {
None
}
}),
DefKind::Impl { .. } => tcx
.associated_item_def_ids(def_id)
.iter()
.copied()
.find(|assoc_def_id| tcx.item_name(*assoc_def_id) == name && ns.matches(tcx.def_kind(assoc_def_id).ns())),
_ => None,
}
}
fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, name: Symbol) -> Option<DefId> {
let root_mod;
let item_kind = match tcx.hir_node_by_def_id(local_id) {
Node::Crate(r#mod) => {
root_mod = ItemKind::Mod(Ident::dummy(), r#mod);
&root_mod
},
Node::Item(item) => &item.kind,
_ => return None,
};
let res = |ident: Ident, owner_id: OwnerId| {
if ident.name == name && ns.matches(tcx.def_kind(owner_id).ns()) {
Some(owner_id.to_def_id())
} else {
None
}
};
match item_kind {
ItemKind::Mod(_, r#mod) => r#mod.item_ids.iter().find_map(|&item_id| {
let ident = tcx.hir_item(item_id).kind.ident()?;
res(ident, item_id.owner_id)
}),
ItemKind::Impl(r#impl) => r#impl
.items
.iter()
.find_map(|&ImplItemRef { ident, id, .. }| res(ident, id.owner_id)),
ItemKind::Trait(.., trait_item_refs) => trait_item_refs
.iter()
.find_map(|&TraitItemRef { ident, id, .. }| res(ident, id.owner_id)),
_ => None,
}
}
fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, ns: PathNS, name: Symbol) -> Option<DefId> {
if let Some(local_id) = def_id.as_local() {
local_item_child_by_name(tcx, local_id, ns, name)
} else {
non_local_item_child_by_name(tcx, def_id, ns, name)
}
}
/// Finds the crates called `name`, may be multiple due to multiple major versions.
pub fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> &'static [DefId] {
static BY_NAME: OnceLock<FxHashMap<Symbol, Vec<DefId>>> = OnceLock::new();
let map = BY_NAME.get_or_init(|| {
let mut map = FxHashMap::default();
map.insert(tcx.crate_name(LOCAL_CRATE), vec![LOCAL_CRATE.as_def_id()]);
for &num in tcx.crates(()) {
map.entry(tcx.crate_name(num)).or_default().push(num.as_def_id());
}
map
});
match map.get(&name) {
Some(def_ids) => def_ids,
None => &[],
}
}
/// Specifies whether to resolve a path in the [`TypeNS`], [`ValueNS`], [`MacroNS`] or in an
/// arbitrary namespace
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum PathNS {
Type,
Value,
Macro,
/// Resolves to the name in the first available namespace, e.g. for `std::vec` this would return
/// either the macro or the module but **not** both
///
/// Must only be used when the specific resolution is unimportant such as in
/// `missing_enforced_import_renames`
Arbitrary,
}
impl PathNS {
fn matches(self, ns: Option<Namespace>) -> bool {
let required = match self {
PathNS::Type => TypeNS,
PathNS::Value => ValueNS,
PathNS::Macro => MacroNS,
PathNS::Arbitrary => return true,
};
ns == Some(required)
}
}
/// Resolves a def path like `std::vec::Vec`.
///
/// Typically it will return one [`DefId`] or none, but in some situations there can be multiple:
/// - `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0
/// - `alloc::boxed::Box::downcast` would return a function for each of the different inherent impls
/// ([1], [2], [3])
///
/// This function is expensive and should be used sparingly.
///
/// [1]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast
/// [2]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-1
/// [3]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-2
pub fn lookup_path(tcx: TyCtxt<'_>, ns: PathNS, path: &[Symbol]) -> Vec<DefId> {
let (root, rest) = match *path {
[] | [_] => return Vec::new(),
[root, ref rest @ ..] => (root, rest),
};
let mut out = Vec::new();
for &base in find_crates(tcx, root).iter().chain(find_primitive_impls(tcx, root)) {
lookup_path_with_base(tcx, base, ns, rest, &mut out);
}
out
}
/// Resolves a def path like `vec::Vec` with the base `std`.
fn lookup_path_with_base(tcx: TyCtxt<'_>, mut base: DefId, ns: PathNS, mut path: &[Symbol], out: &mut Vec<DefId>) {
loop {
match *path {
[segment] => {
out.extend(item_child_by_name(tcx, base, ns, segment));
// When the current def_id is e.g. `struct S`, check the impl items in
// `impl S { ... }`
let inherent_impl_children = tcx
.inherent_impls(base)
.iter()
.filter_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, ns, segment));
out.extend(inherent_impl_children);
return;
},
[segment, ref rest @ ..] => {
path = rest;
let Some(child) = item_child_by_name(tcx, base, PathNS::Type, segment) else {
return;
};
base = child;
},
[] => unreachable!(),
}
}
}
/// Equivalent to a [`lookup_path`] after splitting the input string on `::`
///
/// This function is expensive and should be used sparingly.
pub fn lookup_path_str(tcx: TyCtxt<'_>, ns: PathNS, path: &str) -> Vec<DefId> {
let path: Vec<Symbol> = path.split("::").map(Symbol::intern).collect();
lookup_path(tcx, ns, &path)
}
/// Gets the `hir::TraitRef` of the trait the given method is implemented for.
///
/// Use this if you want to find the `TraitRef` of the `Add` trait in this example:

View file

@ -4,13 +4,48 @@
//! Whenever possible, please consider diagnostic items over hardcoded paths.
//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
use crate::{MaybePath, PathNS, lookup_path, path_def_id, sym};
use rustc_hir::def_id::DefId;
use crate::{MaybePath, path_def_id, sym};
use rustc_ast::Mutability;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::Namespace::{MacroNS, TypeNS, ValueNS};
use rustc_hir::def::{DefKind, Namespace};
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::{ImplItemRef, ItemKind, Node, OwnerId, TraitItemRef};
use rustc_lint::LateContext;
use rustc_middle::ty::Ty;
use rustc_span::{STDLIB_STABLE_CRATES, Symbol};
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::{FloatTy, IntTy, Ty, TyCtxt, UintTy};
use rustc_span::{Ident, STDLIB_STABLE_CRATES, Symbol};
use std::sync::OnceLock;
/// Specifies whether to resolve a path in the [`TypeNS`], [`ValueNS`], [`MacroNS`] or in an
/// arbitrary namespace
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum PathNS {
Type,
Value,
Macro,
/// Resolves to the name in the first available namespace, e.g. for `std::vec` this would return
/// either the macro or the module but **not** both
///
/// Must only be used when the specific resolution is unimportant such as in
/// `missing_enforced_import_renames`
Arbitrary,
}
impl PathNS {
fn matches(self, ns: Option<Namespace>) -> bool {
let required = match self {
PathNS::Type => TypeNS,
PathNS::Value => ValueNS,
PathNS::Macro => MacroNS,
PathNS::Arbitrary => return true,
};
ns == Some(required)
}
}
/// Lazily resolves a path into a list of [`DefId`]s using [`lookup_path`].
///
/// Typically it will contain one [`DefId`] or none, but in some situations there can be multiple:
@ -126,3 +161,175 @@ pub static ONCE_CELL_SYNC_LAZY: PathLookup = type_path!(once_cell::sync::Lazy);
pub static ONCE_CELL_SYNC_LAZY_NEW: PathLookup = value_path!(once_cell::sync::Lazy::new);
// Paths for internal lints go in `clippy_lints_internal/src/internal_paths.rs`
/// Equivalent to a [`lookup_path`] after splitting the input string on `::`
///
/// This function is expensive and should be used sparingly.
pub fn lookup_path_str(tcx: TyCtxt<'_>, ns: PathNS, path: &str) -> Vec<DefId> {
let path: Vec<Symbol> = path.split("::").map(Symbol::intern).collect();
lookup_path(tcx, ns, &path)
}
/// Resolves a def path like `std::vec::Vec`.
///
/// Typically it will return one [`DefId`] or none, but in some situations there can be multiple:
/// - `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0
/// - `alloc::boxed::Box::downcast` would return a function for each of the different inherent impls
/// ([1], [2], [3])
///
/// This function is expensive and should be used sparingly.
///
/// [1]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast
/// [2]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-1
/// [3]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.downcast-2
pub fn lookup_path(tcx: TyCtxt<'_>, ns: PathNS, path: &[Symbol]) -> Vec<DefId> {
let (root, rest) = match *path {
[] | [_] => return Vec::new(),
[root, ref rest @ ..] => (root, rest),
};
let mut out = Vec::new();
for &base in find_crates(tcx, root).iter().chain(find_primitive_impls(tcx, root)) {
lookup_with_base(tcx, base, ns, rest, &mut out);
}
out
}
/// Finds the crates called `name`, may be multiple due to multiple major versions.
pub fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> &'static [DefId] {
static BY_NAME: OnceLock<FxHashMap<Symbol, Vec<DefId>>> = OnceLock::new();
let map = BY_NAME.get_or_init(|| {
let mut map = FxHashMap::default();
map.insert(tcx.crate_name(LOCAL_CRATE), vec![LOCAL_CRATE.as_def_id()]);
for &num in tcx.crates(()) {
map.entry(tcx.crate_name(num)).or_default().push(num.as_def_id());
}
map
});
match map.get(&name) {
Some(def_ids) => def_ids,
None => &[],
}
}
fn find_primitive_impls(tcx: TyCtxt<'_>, name: Symbol) -> &[DefId] {
let ty = match name {
sym::bool => SimplifiedType::Bool,
sym::char => SimplifiedType::Char,
sym::str => SimplifiedType::Str,
sym::array => SimplifiedType::Array,
sym::slice => SimplifiedType::Slice,
// FIXME: rustdoc documents these two using just `pointer`.
//
// Maybe this is something we should do here too.
sym::const_ptr => SimplifiedType::Ptr(Mutability::Not),
sym::mut_ptr => SimplifiedType::Ptr(Mutability::Mut),
sym::isize => SimplifiedType::Int(IntTy::Isize),
sym::i8 => SimplifiedType::Int(IntTy::I8),
sym::i16 => SimplifiedType::Int(IntTy::I16),
sym::i32 => SimplifiedType::Int(IntTy::I32),
sym::i64 => SimplifiedType::Int(IntTy::I64),
sym::i128 => SimplifiedType::Int(IntTy::I128),
sym::usize => SimplifiedType::Uint(UintTy::Usize),
sym::u8 => SimplifiedType::Uint(UintTy::U8),
sym::u16 => SimplifiedType::Uint(UintTy::U16),
sym::u32 => SimplifiedType::Uint(UintTy::U32),
sym::u64 => SimplifiedType::Uint(UintTy::U64),
sym::u128 => SimplifiedType::Uint(UintTy::U128),
sym::f32 => SimplifiedType::Float(FloatTy::F32),
sym::f64 => SimplifiedType::Float(FloatTy::F64),
_ => return &[],
};
tcx.incoherent_impls(ty)
}
/// Resolves a def path like `vec::Vec` with the base `std`.
fn lookup_with_base(tcx: TyCtxt<'_>, mut base: DefId, ns: PathNS, mut path: &[Symbol], out: &mut Vec<DefId>) {
loop {
match *path {
[segment] => {
out.extend(item_child_by_name(tcx, base, ns, segment));
// When the current def_id is e.g. `struct S`, check the impl items in
// `impl S { ... }`
let inherent_impl_children = tcx
.inherent_impls(base)
.iter()
.filter_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, ns, segment));
out.extend(inherent_impl_children);
return;
},
[segment, ref rest @ ..] => {
path = rest;
let Some(child) = item_child_by_name(tcx, base, PathNS::Type, segment) else {
return;
};
base = child;
},
[] => unreachable!(),
}
}
}
fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, ns: PathNS, name: Symbol) -> Option<DefId> {
if let Some(local_id) = def_id.as_local() {
local_item_child_by_name(tcx, local_id, ns, name)
} else {
non_local_item_child_by_name(tcx, def_id, ns, name)
}
}
fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, name: Symbol) -> Option<DefId> {
let root_mod;
let item_kind = match tcx.hir_node_by_def_id(local_id) {
Node::Crate(r#mod) => {
root_mod = ItemKind::Mod(Ident::dummy(), r#mod);
&root_mod
},
Node::Item(item) => &item.kind,
_ => return None,
};
let res = |ident: Ident, owner_id: OwnerId| {
if ident.name == name && ns.matches(tcx.def_kind(owner_id).ns()) {
Some(owner_id.to_def_id())
} else {
None
}
};
match item_kind {
ItemKind::Mod(_, r#mod) => r#mod.item_ids.iter().find_map(|&item_id| {
let ident = tcx.hir_item(item_id).kind.ident()?;
res(ident, item_id.owner_id)
}),
ItemKind::Impl(r#impl) => r#impl
.items
.iter()
.find_map(|&ImplItemRef { ident, id, .. }| res(ident, id.owner_id)),
ItemKind::Trait(.., trait_item_refs) => trait_item_refs
.iter()
.find_map(|&TraitItemRef { ident, id, .. }| res(ident, id.owner_id)),
_ => None,
}
}
fn non_local_item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, ns: PathNS, name: Symbol) -> Option<DefId> {
match tcx.def_kind(def_id) {
DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx.module_children(def_id).iter().find_map(|child| {
if child.ident.name == name && ns.matches(child.res.ns()) {
child.res.opt_def_id()
} else {
None
}
}),
DefKind::Impl { .. } => tcx
.associated_item_def_ids(def_id)
.iter()
.copied()
.find(|assoc_def_id| tcx.item_name(*assoc_def_id) == name && ns.matches(tcx.def_kind(assoc_def_id).ns())),
_ => None,
}
}

View file

@ -32,7 +32,8 @@ use std::assert_matches::debug_assert_matches;
use std::collections::hash_map::Entry;
use std::iter;
use crate::{PathNS, lookup_path_str, path_res};
use crate::path_res;
use crate::paths::{PathNS, lookup_path_str};
mod type_certainty;
pub use type_certainty::expr_type_is_certain;

View file

@ -11,7 +11,7 @@
//! As a heuristic, `expr_type_is_certain` may produce false negatives, but a false positive should
//! be considered a bug.
use crate::{PathNS, lookup_path};
use crate::paths::{PathNS, lookup_path};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_qpath, walk_ty};

View file

@ -1,7 +1,7 @@
#![feature(rustc_private)]
use clippy_utils::paths::PathLookup;
use clippy_utils::{PathNS, macro_path, sym, type_path, value_path};
use clippy_utils::paths::{PathLookup, PathNS};
use clippy_utils::{macro_path, sym, type_path, value_path};
static OPTION: PathLookup = type_path!(core::option::Option);
//~^ unnecessary_def_path