mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-27 23:20:39 +00:00
Return multiple resolutions from def_path_res
This commit is contained in:
parent
7600535511
commit
1e1ac2b498
15 changed files with 280 additions and 235 deletions
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::{match_def_path, paths};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def::{Namespace, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -189,7 +188,7 @@ impl LateLintPass<'_> for AwaitHolding {
|
|||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for conf in &self.conf_invalid_types {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
|
||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||
self.def_ids.insert(id, conf.clone());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::macros::macro_backtrace;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def::{Namespace, Res};
|
||||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_hir::{Expr, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -89,7 +88,7 @@ impl DisallowedMacros {
|
|||
&format!("use of a disallowed macro `{}`", conf.path()),
|
||||
|diag| {
|
||||
if let Some(reason) = conf.reason() {
|
||||
diag.note(&format!("{reason} (from clippy.toml)"));
|
||||
diag.note(reason);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
@ -104,7 +103,7 @@ impl LateLintPass<'_> for DisallowedMacros {
|
|||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for (index, conf) in self.conf_disallowed.iter().enumerate() {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::MacroNS)) {
|
||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||
self.disallowed.insert(id, index);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
|
||||
|
||||
use rustc_hir::def::{Namespace, Res};
|
||||
use rustc_hir::def_id::DefIdMap;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -79,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
|
|||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for (index, conf) in self.conf_disallowed.iter().enumerate() {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::ValueNS)) {
|
||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||
self.disallowed.insert(id, index);
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
|
|||
let msg = format!("use of a disallowed method `{}`", conf.path());
|
||||
span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
|
||||
if let Some(reason) = conf.reason() {
|
||||
diag.note(&format!("{reason} (from clippy.toml)"));
|
||||
diag.note(reason);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def::{Namespace, Res};
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -53,8 +53,8 @@ declare_clippy_lint! {
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct DisallowedTypes {
|
||||
conf_disallowed: Vec<conf::DisallowedPath>,
|
||||
def_ids: FxHashMap<DefId, Option<String>>,
|
||||
prim_tys: FxHashMap<PrimTy, Option<String>>,
|
||||
def_ids: FxHashMap<DefId, usize>,
|
||||
prim_tys: FxHashMap<PrimTy, usize>,
|
||||
}
|
||||
|
||||
impl DisallowedTypes {
|
||||
|
@ -69,13 +69,13 @@ impl DisallowedTypes {
|
|||
fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
|
||||
match res {
|
||||
Res::Def(_, did) => {
|
||||
if let Some(reason) = self.def_ids.get(did) {
|
||||
emit(cx, &cx.tcx.def_path_str(*did), span, reason.as_deref());
|
||||
if let Some(&index) = self.def_ids.get(did) {
|
||||
emit(cx, &cx.tcx.def_path_str(*did), span, &self.conf_disallowed[index]);
|
||||
}
|
||||
},
|
||||
Res::PrimTy(prim) => {
|
||||
if let Some(reason) = self.prim_tys.get(prim) {
|
||||
emit(cx, prim.name_str(), span, reason.as_deref());
|
||||
if let Some(&index) = self.prim_tys.get(prim) {
|
||||
emit(cx, prim.name_str(), span, &self.conf_disallowed[index]);
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
|
@ -87,17 +87,19 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
|
|||
|
||||
impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for conf in &self.conf_disallowed {
|
||||
for (index, conf) in self.conf_disallowed.iter().enumerate() {
|
||||
let segs: Vec<_> = conf.path().split("::").collect();
|
||||
let reason = conf.reason().map(|reason| format!("{reason} (from clippy.toml)"));
|
||||
match clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
|
||||
Res::Def(_, id) => {
|
||||
self.def_ids.insert(id, reason);
|
||||
},
|
||||
Res::PrimTy(ty) => {
|
||||
self.prim_tys.insert(ty, reason);
|
||||
},
|
||||
_ => {},
|
||||
|
||||
for res in clippy_utils::def_path_res(cx, &segs) {
|
||||
match res {
|
||||
Res::Def(_, id) => {
|
||||
self.def_ids.insert(id, index);
|
||||
},
|
||||
Res::PrimTy(ty) => {
|
||||
self.prim_tys.insert(ty, index);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,14 +121,14 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
|
|||
}
|
||||
}
|
||||
|
||||
fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
|
||||
fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &conf::DisallowedPath) {
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
DISALLOWED_TYPES,
|
||||
span,
|
||||
&format!("`{name}` is not allowed according to config"),
|
||||
|diag| {
|
||||
if let Some(reason) = reason {
|
||||
if let Some(reason) = conf.reason() {
|
||||
diag.note(reason);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -59,7 +59,7 @@ impl LateLintPass<'_> for ImportRename {
|
|||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for Rename { path, rename } in &self.conf_renames {
|
||||
let segs = path.split("::").collect::<Vec<_>>();
|
||||
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, None) {
|
||||
for id in clippy_utils::def_path_def_ids(cx, &segs) {
|
||||
self.renames.insert(id, Symbol::intern(rename));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::{def_path_res, trait_ref_of_method};
|
||||
use clippy_utils::{def_path_def_ids, trait_ref_of_method};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty::TypeVisitable;
|
||||
use rustc_middle::ty::{Adt, Array, Ref, Slice, Tuple, Ty};
|
||||
|
@ -94,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableKeyType {
|
|||
let mut path = Vec::new();
|
||||
for ty in &self.ignore_interior_mutability {
|
||||
path.extend(ty.split("::"));
|
||||
if let Some(id) = def_path_res(cx, &path[..], Some(Namespace::TypeNS)).opt_def_id() {
|
||||
for id in def_path_def_ids(cx, &path[..]) {
|
||||
self.ignore_mut_def_ids.insert(id);
|
||||
}
|
||||
path.clear();
|
||||
|
|
|
@ -53,11 +53,11 @@ impl DisallowedPath {
|
|||
path
|
||||
}
|
||||
|
||||
pub fn reason(&self) -> Option<&str> {
|
||||
pub fn reason(&self) -> Option<String> {
|
||||
match self {
|
||||
Self::WithReason {
|
||||
reason: Some(reason), ..
|
||||
} => Some(reason),
|
||||
} => Some(format!("{reason} (from clippy.toml)")),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use clippy_utils::consts::{constant_simple, Constant};
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::match_type;
|
||||
use clippy_utils::{def_path_res, is_expn_of, match_def_path, paths};
|
||||
use clippy_utils::{def_path_def_ids, is_expn_of, match_def_path, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::Applicability;
|
||||
|
@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
|
|||
}
|
||||
|
||||
for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
|
||||
if let Some(def_id) = def_path_res(cx, module, None).opt_def_id() {
|
||||
for def_id in def_path_def_ids(cx, module) {
|
||||
for item in cx.tcx.module_children(def_id).iter() {
|
||||
if_chain! {
|
||||
if let Res::Def(DefKind::Const, item_def_id) = item.res;
|
||||
|
|
|
@ -3,7 +3,7 @@ use clippy_utils::def_path_res;
|
|||
use clippy_utils::diagnostics::span_lint;
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::Item;
|
||||
use rustc_hir_analysis::hir_ty_to_ty;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
|
@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidPaths {
|
|||
// This is not a complete resolver for paths. It works on all the paths currently used in the paths
|
||||
// module. That's all it does and all it needs to do.
|
||||
pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
|
||||
if def_path_res(cx, path, None) != Res::Err {
|
||||
if !def_path_res(cx, path).is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{def_path_res, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
|
||||
use clippy_utils::{def_path_def_ids, is_lint_allowed, match_any_def_paths, peel_hir_expr_refs};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Namespace, Res};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Expr, ExprKind, Local, Mutability, Node};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::mir::interpret::{Allocation, ConstValue, GlobalAlloc};
|
||||
use rustc_middle::ty::{self, AssocKind, DefIdTree, Ty};
|
||||
use rustc_middle::ty::{self, DefIdTree, Ty};
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::symbol::{Ident, Symbol};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::str;
|
||||
|
@ -110,7 +110,7 @@ impl UnnecessaryDefPath {
|
|||
// Extract the path to the matched type
|
||||
if let Some(segments) = path_to_matched_type(cx, item_arg);
|
||||
let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
|
||||
if let Some(def_id) = inherent_def_path_res(cx, &segments[..]);
|
||||
if let Some(def_id) = def_path_def_ids(cx, &segments[..]).next();
|
||||
then {
|
||||
// Check if the target item is a diagnostic item or LangItem.
|
||||
#[rustfmt::skip]
|
||||
|
@ -209,7 +209,7 @@ impl UnnecessaryDefPath {
|
|||
fn check_array(&mut self, cx: &LateContext<'_>, elements: &[Expr<'_>], span: Span) {
|
||||
let Some(path) = path_from_array(elements) else { return };
|
||||
|
||||
if let Some(def_id) = inherent_def_path_res(cx, &path.iter().map(AsRef::as_ref).collect::<Vec<_>>()) {
|
||||
for def_id in def_path_def_ids(cx, &path.iter().map(AsRef::as_ref).collect::<Vec<_>>()) {
|
||||
self.array_def_ids.insert((def_id, span));
|
||||
}
|
||||
}
|
||||
|
@ -293,41 +293,11 @@ fn path_from_array(exprs: &[Expr<'_>]) -> Option<Vec<String>> {
|
|||
.collect()
|
||||
}
|
||||
|
||||
// def_path_res will match field names before anything else, but for this we want to match
|
||||
// inherent functions first.
|
||||
fn inherent_def_path_res(cx: &LateContext<'_>, segments: &[&str]) -> Option<DefId> {
|
||||
def_path_res(cx, segments, None).opt_def_id().map(|def_id| {
|
||||
if cx.tcx.def_kind(def_id) == DefKind::Field {
|
||||
let method_name = *segments.last().unwrap();
|
||||
cx.tcx
|
||||
.def_key(def_id)
|
||||
.parent
|
||||
.and_then(|parent_idx| {
|
||||
cx.tcx
|
||||
.inherent_impls(DefId {
|
||||
index: parent_idx,
|
||||
krate: def_id.krate,
|
||||
})
|
||||
.iter()
|
||||
.find_map(|impl_id| {
|
||||
cx.tcx.associated_items(*impl_id).find_by_name_and_kind(
|
||||
cx.tcx,
|
||||
Ident::from_str(method_name),
|
||||
AssocKind::Fn,
|
||||
*impl_id,
|
||||
)
|
||||
})
|
||||
})
|
||||
.map_or(def_id, |item| item.def_id)
|
||||
} else {
|
||||
def_id
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_lang_item_name(cx: &LateContext<'_>, def_id: DefId) -> Option<Symbol> {
|
||||
if let Some(lang_item) = cx.tcx.lang_items().items().iter().position(|id| *id == Some(def_id)) {
|
||||
let lang_items = def_path_res(cx, &["rustc_hir", "lang_items", "LangItem"], Some(Namespace::TypeNS)).def_id();
|
||||
let lang_items = def_path_def_ids(cx, &["rustc_hir", "lang_items", "LangItem"])
|
||||
.next()
|
||||
.unwrap();
|
||||
let item_name = cx
|
||||
.tcx
|
||||
.adt_def(lang_items)
|
||||
|
|
|
@ -80,17 +80,16 @@ use rustc_ast::ast::{self, LitKind};
|
|||
use rustc_ast::Attribute;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::unhash::UnhashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Namespace, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
|
||||
use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
|
||||
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
|
||||
use rustc_hir::{
|
||||
def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination, Expr,
|
||||
ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource,
|
||||
Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
|
||||
TraitRef, TyKind, UnOp,
|
||||
self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination,
|
||||
Expr, ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local,
|
||||
MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
|
||||
TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp,
|
||||
};
|
||||
use rustc_lexer::{tokenize, TokenKind};
|
||||
use rustc_lint::{LateContext, Level, Lint, LintContext};
|
||||
|
@ -112,7 +111,7 @@ use rustc_span::hygiene::{ExpnKind, MacroKind};
|
|||
use rustc_span::source_map::original_sp;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::sym;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::symbol::{kw, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::Integer;
|
||||
|
||||
|
@ -525,165 +524,177 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
|
|||
path_res(cx, maybe_path).opt_def_id()
|
||||
}
|
||||
|
||||
fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
|
||||
let single = |ty| tcx.incoherent_impls(ty).iter().copied();
|
||||
let empty = || [].iter().copied();
|
||||
match name {
|
||||
"bool" => single(BoolSimplifiedType),
|
||||
"char" => single(CharSimplifiedType),
|
||||
"str" => single(StrSimplifiedType),
|
||||
"array" => single(ArraySimplifiedType),
|
||||
"slice" => single(SliceSimplifiedType),
|
||||
fn find_primitive_impls<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx {
|
||||
let ty = match name {
|
||||
"bool" => BoolSimplifiedType,
|
||||
"char" => CharSimplifiedType,
|
||||
"str" => StrSimplifiedType,
|
||||
"array" => ArraySimplifiedType,
|
||||
"slice" => SliceSimplifiedType,
|
||||
// FIXME: rustdoc documents these two using just `pointer`.
|
||||
//
|
||||
// Maybe this is something we should do here too.
|
||||
"const_ptr" => single(PtrSimplifiedType(Mutability::Not)),
|
||||
"mut_ptr" => single(PtrSimplifiedType(Mutability::Mut)),
|
||||
"isize" => single(IntSimplifiedType(IntTy::Isize)),
|
||||
"i8" => single(IntSimplifiedType(IntTy::I8)),
|
||||
"i16" => single(IntSimplifiedType(IntTy::I16)),
|
||||
"i32" => single(IntSimplifiedType(IntTy::I32)),
|
||||
"i64" => single(IntSimplifiedType(IntTy::I64)),
|
||||
"i128" => single(IntSimplifiedType(IntTy::I128)),
|
||||
"usize" => single(UintSimplifiedType(UintTy::Usize)),
|
||||
"u8" => single(UintSimplifiedType(UintTy::U8)),
|
||||
"u16" => single(UintSimplifiedType(UintTy::U16)),
|
||||
"u32" => single(UintSimplifiedType(UintTy::U32)),
|
||||
"u64" => single(UintSimplifiedType(UintTy::U64)),
|
||||
"u128" => single(UintSimplifiedType(UintTy::U128)),
|
||||
"f32" => single(FloatSimplifiedType(FloatTy::F32)),
|
||||
"f64" => single(FloatSimplifiedType(FloatTy::F64)),
|
||||
_ => empty(),
|
||||
"const_ptr" => PtrSimplifiedType(Mutability::Not),
|
||||
"mut_ptr" => PtrSimplifiedType(Mutability::Mut),
|
||||
"isize" => IntSimplifiedType(IntTy::Isize),
|
||||
"i8" => IntSimplifiedType(IntTy::I8),
|
||||
"i16" => IntSimplifiedType(IntTy::I16),
|
||||
"i32" => IntSimplifiedType(IntTy::I32),
|
||||
"i64" => IntSimplifiedType(IntTy::I64),
|
||||
"i128" => IntSimplifiedType(IntTy::I128),
|
||||
"usize" => UintSimplifiedType(UintTy::Usize),
|
||||
"u8" => UintSimplifiedType(UintTy::U8),
|
||||
"u16" => UintSimplifiedType(UintTy::U16),
|
||||
"u32" => UintSimplifiedType(UintTy::U32),
|
||||
"u64" => UintSimplifiedType(UintTy::U64),
|
||||
"u128" => UintSimplifiedType(UintTy::U128),
|
||||
"f32" => FloatSimplifiedType(FloatTy::F32),
|
||||
"f64" => FloatSimplifiedType(FloatTy::F64),
|
||||
_ => return [].iter().copied(),
|
||||
};
|
||||
|
||||
tcx.incoherent_impls(ty).iter().copied()
|
||||
}
|
||||
|
||||
fn non_local_item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
|
||||
.module_children(def_id)
|
||||
.iter()
|
||||
.filter(|item| item.ident.name == name)
|
||||
.map(|child| child.res.expect_non_local())
|
||||
.collect(),
|
||||
DefKind::Impl => tcx
|
||||
.associated_item_def_ids(def_id)
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|assoc_def_id| tcx.item_name(*assoc_def_id) == name)
|
||||
.map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id))
|
||||
.collect(),
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves a def path like `std::vec::Vec`. `namespace_hint` can be supplied to disambiguate
|
||||
/// between `std::vec` the module and `std::vec` the macro
|
||||
fn local_item_children_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, name: Symbol) -> Vec<Res> {
|
||||
let hir = tcx.hir();
|
||||
|
||||
let root_mod;
|
||||
let item_kind = match hir.find_by_def_id(local_id) {
|
||||
Some(Node::Crate(r#mod)) => {
|
||||
root_mod = ItemKind::Mod(r#mod);
|
||||
&root_mod
|
||||
},
|
||||
Some(Node::Item(item)) => &item.kind,
|
||||
_ => return Vec::new(),
|
||||
};
|
||||
|
||||
let res = |ident: Ident, owner_id: OwnerId| {
|
||||
if ident.name == name {
|
||||
let def_id = owner_id.to_def_id();
|
||||
Some(Res::Def(tcx.def_kind(def_id), def_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
match item_kind {
|
||||
ItemKind::Mod(r#mod) => r#mod
|
||||
.item_ids
|
||||
.iter()
|
||||
.filter_map(|&item_id| res(hir.item(item_id).ident, item_id.def_id))
|
||||
.collect(),
|
||||
ItemKind::Impl(r#impl) => r#impl
|
||||
.items
|
||||
.iter()
|
||||
.filter_map(|&ImplItemRef { ident, id, .. }| res(ident, id.def_id))
|
||||
.collect(),
|
||||
ItemKind::Trait(.., trait_item_refs) => trait_item_refs
|
||||
.iter()
|
||||
.filter_map(|&TraitItemRef { ident, id, .. }| res(ident, id.def_id))
|
||||
.collect(),
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Res> {
|
||||
if let Some(local_id) = def_id.as_local() {
|
||||
local_item_children_by_name(tcx, local_id, name)
|
||||
} else {
|
||||
non_local_item_children_by_name(tcx, def_id, name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves a def path like `std::vec::Vec`.
|
||||
///
|
||||
/// Can return multiple resolutions when there are multiple versions of the same crate, e.g.
|
||||
/// `memchr::memchr` could return the functions from both memchr 1.0 and memchr 2.0.
|
||||
///
|
||||
/// Also returns multiple results when there are mulitple paths under the same name e.g. `std::vec`
|
||||
/// would have both a [`DefKind::Mod`] and [`DefKind::Macro`].
|
||||
///
|
||||
/// This function is expensive and should be used sparingly.
|
||||
pub fn def_path_res(cx: &LateContext<'_>, path: &[&str], namespace_hint: Option<Namespace>) -> Res {
|
||||
fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str, matches_ns: impl Fn(Res) -> bool) -> Option<Res> {
|
||||
match tcx.def_kind(def_id) {
|
||||
DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
|
||||
.module_children(def_id)
|
||||
.iter()
|
||||
.find(|item| item.ident.name.as_str() == name && matches_ns(item.res.expect_non_local()))
|
||||
.map(|child| child.res.expect_non_local()),
|
||||
DefKind::Impl => tcx
|
||||
.associated_item_def_ids(def_id)
|
||||
.iter()
|
||||
.copied()
|
||||
.find(|assoc_def_id| tcx.item_name(*assoc_def_id).as_str() == name)
|
||||
.map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id)),
|
||||
DefKind::Struct | DefKind::Union => tcx
|
||||
.adt_def(def_id)
|
||||
.non_enum_variant()
|
||||
.fields
|
||||
.iter()
|
||||
.find(|f| f.name.as_str() == name)
|
||||
.map(|f| Res::Def(DefKind::Field, f.did)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
|
||||
pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Vec<Res> {
|
||||
fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> impl Iterator<Item = DefId> + '_ {
|
||||
tcx.crates(())
|
||||
.iter()
|
||||
.copied()
|
||||
.find(|&num| tcx.crate_name(num).as_str() == name)
|
||||
.filter(move |&num| tcx.crate_name(num) == name)
|
||||
.map(CrateNum::as_def_id)
|
||||
}
|
||||
|
||||
let (base, path) = match *path {
|
||||
[primitive] => {
|
||||
return PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy);
|
||||
},
|
||||
[base, ref path @ ..] => {
|
||||
let crate_name = cx.sess().opts.crate_name.as_deref();
|
||||
if Some(base) == crate_name {
|
||||
return def_path_res_local(cx, path);
|
||||
}
|
||||
(base, path)
|
||||
},
|
||||
_ => return Res::Err,
|
||||
};
|
||||
let tcx = cx.tcx;
|
||||
let starts = find_primitive(tcx, base)
|
||||
.chain(find_crate(tcx, base))
|
||||
|
||||
let (base, mut path) = match *path {
|
||||
[primitive] => {
|
||||
return vec![PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy)];
|
||||
},
|
||||
[base, ref path @ ..] => (base, path),
|
||||
_ => return Vec::new(),
|
||||
};
|
||||
|
||||
let base_sym = Symbol::intern(base);
|
||||
|
||||
let local_crate = if tcx.crate_name(LOCAL_CRATE) == base_sym {
|
||||
Some(LOCAL_CRATE.as_def_id())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let starts = find_primitive_impls(tcx, base)
|
||||
.chain(find_crates(tcx, base_sym))
|
||||
.chain(local_crate)
|
||||
.map(|id| Res::Def(tcx.def_kind(id), id));
|
||||
|
||||
for first in starts {
|
||||
let last = path
|
||||
.iter()
|
||||
.copied()
|
||||
.enumerate()
|
||||
// for each segment, find the child item
|
||||
.try_fold(first, |res, (idx, segment)| {
|
||||
let matches_ns = |res: Res| {
|
||||
// If at the last segment in the path, respect the namespace hint
|
||||
if idx == path.len() - 1 {
|
||||
match namespace_hint {
|
||||
Some(ns) => res.matches_ns(ns),
|
||||
None => true,
|
||||
}
|
||||
} else {
|
||||
res.matches_ns(Namespace::TypeNS)
|
||||
}
|
||||
};
|
||||
let mut resolutions: Vec<Res> = starts.collect();
|
||||
|
||||
let def_id = res.def_id();
|
||||
if let Some(item) = item_child_by_name(tcx, def_id, segment, matches_ns) {
|
||||
Some(item)
|
||||
} else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
|
||||
// it is not a child item so check inherent impl items
|
||||
tcx.inherent_impls(def_id)
|
||||
.iter()
|
||||
.find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment, matches_ns))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
while let [segment, rest @ ..] = path {
|
||||
path = rest;
|
||||
let segment = Symbol::intern(segment);
|
||||
|
||||
if let Some(last) = last {
|
||||
return last;
|
||||
}
|
||||
resolutions = resolutions
|
||||
.into_iter()
|
||||
.filter_map(|res| res.opt_def_id())
|
||||
.flat_map(|def_id| {
|
||||
// When the current def_id is e.g. `struct S`, check the impl items in
|
||||
// `impl S { ... }`
|
||||
let inherent_impl_children = tcx
|
||||
.inherent_impls(def_id)
|
||||
.iter()
|
||||
.flat_map(|&impl_def_id| item_children_by_name(tcx, impl_def_id, segment));
|
||||
|
||||
let direct_children = item_children_by_name(tcx, def_id, segment);
|
||||
|
||||
inherent_impl_children.chain(direct_children)
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
Res::Err
|
||||
|
||||
resolutions
|
||||
}
|
||||
|
||||
fn def_path_res_local(cx: &LateContext<'_>, mut path: &[&str]) -> Res {
|
||||
let map = cx.tcx.hir();
|
||||
let mut ids = map.root_module().item_ids;
|
||||
while let Some(&segment) = path.first() {
|
||||
let mut next_ids = None;
|
||||
for i in ids {
|
||||
if let Some(Node::Item(hir::Item {
|
||||
ident,
|
||||
kind,
|
||||
def_id: item_def_id,
|
||||
..
|
||||
})) = map.find(i.hir_id())
|
||||
{
|
||||
if ident.name.as_str() == segment {
|
||||
path = &path[1..];
|
||||
if path.is_empty() {
|
||||
let def_id = item_def_id.to_def_id();
|
||||
return Res::Def(cx.tcx.def_kind(def_id), def_id);
|
||||
}
|
||||
if let ItemKind::Mod(m) = kind {
|
||||
next_ids = Some(m.item_ids);
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(next_ids) = next_ids {
|
||||
ids = next_ids;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Res::Err
|
||||
/// Resolves a def path like `std::vec::Vec` to its [`DefId`]s, see [`def_path_res`].
|
||||
pub fn def_path_def_ids(cx: &LateContext<'_>, path: &[&str]) -> impl Iterator<Item = DefId> {
|
||||
def_path_res(cx, path).into_iter().filter_map(|res| res.opt_def_id())
|
||||
}
|
||||
|
||||
/// Convenience function to get the `DefId` of a trait by path.
|
||||
|
@ -691,10 +702,10 @@ fn def_path_res_local(cx: &LateContext<'_>, mut path: &[&str]) -> Res {
|
|||
///
|
||||
/// This function is expensive and should be used sparingly.
|
||||
pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
|
||||
match def_path_res(cx, path, Some(Namespace::TypeNS)) {
|
||||
def_path_res(cx, path).into_iter().find_map(|res| match res {
|
||||
Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Gets the `hir::TraitRef` of the trait the given method is implemented for.
|
||||
|
|
|
@ -4,7 +4,7 @@ error: `std::string::String` may not be held across an `await` point per `clippy
|
|||
LL | let _x = String::from("hello");
|
||||
| ^^
|
||||
|
|
||||
= note: strings are bad
|
||||
= note: strings are bad (from clippy.toml)
|
||||
= note: `-D clippy::await-holding-invalid-type` implied by `-D warnings`
|
||||
|
||||
error: `std::net::Ipv4Addr` may not be held across an `await` point per `clippy.toml`
|
||||
|
@ -19,7 +19,7 @@ error: `std::string::String` may not be held across an `await` point per `clippy
|
|||
LL | let _x = String::from("hi!");
|
||||
| ^^
|
||||
|
|
||||
= note: strings are bad
|
||||
= note: strings are bad (from clippy.toml)
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
|
|
@ -8,4 +8,10 @@ disallowed-methods = [
|
|||
{ path = "regex::Regex::is_match", reason = "no matching allowed" },
|
||||
# can use an inline table but omit reason
|
||||
{ path = "regex::Regex::new" },
|
||||
# local paths
|
||||
"conf_disallowed_methods::local_fn",
|
||||
"conf_disallowed_methods::local_mod::f",
|
||||
"conf_disallowed_methods::Struct::method",
|
||||
"conf_disallowed_methods::Trait::provided_method",
|
||||
"conf_disallowed_methods::Trait::implemented_method",
|
||||
]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// compile-flags: --crate-name conf_disallowed_methods
|
||||
|
||||
#![warn(clippy::disallowed_methods)]
|
||||
|
||||
extern crate futures;
|
||||
|
@ -6,6 +8,27 @@ extern crate regex;
|
|||
use futures::stream::{empty, select_all};
|
||||
use regex::Regex;
|
||||
|
||||
fn local_fn() {}
|
||||
|
||||
struct Struct;
|
||||
|
||||
impl Struct {
|
||||
fn method(&self) {}
|
||||
}
|
||||
|
||||
trait Trait {
|
||||
fn provided_method(&self) {}
|
||||
fn implemented_method(&self);
|
||||
}
|
||||
|
||||
impl Trait for Struct {
|
||||
fn implemented_method(&self) {}
|
||||
}
|
||||
|
||||
mod local_mod {
|
||||
pub fn f() {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let re = Regex::new(r"ab.*c").unwrap();
|
||||
re.is_match("abc");
|
||||
|
@ -26,4 +49,11 @@ fn main() {
|
|||
|
||||
// resolve ambiguity between `futures::stream::select_all` the module and the function
|
||||
let same_name_as_module = select_all(vec![empty::<()>()]);
|
||||
|
||||
local_fn();
|
||||
local_mod::f();
|
||||
let s = Struct;
|
||||
s.method();
|
||||
s.provided_method();
|
||||
s.implemented_method();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
error: use of a disallowed method `regex::Regex::new`
|
||||
--> $DIR/conf_disallowed_methods.rs:10:14
|
||||
--> $DIR/conf_disallowed_methods.rs:33:14
|
||||
|
|
||||
LL | let re = Regex::new(r"ab.*c").unwrap();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -7,7 +7,7 @@ LL | let re = Regex::new(r"ab.*c").unwrap();
|
|||
= note: `-D clippy::disallowed-methods` implied by `-D warnings`
|
||||
|
||||
error: use of a disallowed method `regex::Regex::is_match`
|
||||
--> $DIR/conf_disallowed_methods.rs:11:5
|
||||
--> $DIR/conf_disallowed_methods.rs:34:5
|
||||
|
|
||||
LL | re.is_match("abc");
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
@ -15,46 +15,76 @@ LL | re.is_match("abc");
|
|||
= note: no matching allowed (from clippy.toml)
|
||||
|
||||
error: use of a disallowed method `std::iter::Iterator::sum`
|
||||
--> $DIR/conf_disallowed_methods.rs:14:5
|
||||
--> $DIR/conf_disallowed_methods.rs:37:5
|
||||
|
|
||||
LL | a.iter().sum::<i32>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of a disallowed method `slice::sort_unstable`
|
||||
--> $DIR/conf_disallowed_methods.rs:16:5
|
||||
--> $DIR/conf_disallowed_methods.rs:39:5
|
||||
|
|
||||
LL | a.sort_unstable();
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of a disallowed method `f32::clamp`
|
||||
--> $DIR/conf_disallowed_methods.rs:18:13
|
||||
--> $DIR/conf_disallowed_methods.rs:41:13
|
||||
|
|
||||
LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of a disallowed method `regex::Regex::new`
|
||||
--> $DIR/conf_disallowed_methods.rs:21:61
|
||||
--> $DIR/conf_disallowed_methods.rs:44:61
|
||||
|
|
||||
LL | let indirect: fn(&str) -> Result<Regex, regex::Error> = Regex::new;
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: use of a disallowed method `f32::clamp`
|
||||
--> $DIR/conf_disallowed_methods.rs:24:28
|
||||
--> $DIR/conf_disallowed_methods.rs:47:28
|
||||
|
|
||||
LL | let in_call = Box::new(f32::clamp);
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: use of a disallowed method `regex::Regex::new`
|
||||
--> $DIR/conf_disallowed_methods.rs:25:53
|
||||
--> $DIR/conf_disallowed_methods.rs:48:53
|
||||
|
|
||||
LL | let in_method_call = ["^", "$"].into_iter().map(Regex::new);
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: use of a disallowed method `futures::stream::select_all`
|
||||
--> $DIR/conf_disallowed_methods.rs:28:31
|
||||
--> $DIR/conf_disallowed_methods.rs:51:31
|
||||
|
|
||||
LL | let same_name_as_module = select_all(vec![empty::<()>()]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
error: use of a disallowed method `conf_disallowed_methods::local_fn`
|
||||
--> $DIR/conf_disallowed_methods.rs:53:5
|
||||
|
|
||||
LL | local_fn();
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: use of a disallowed method `conf_disallowed_methods::local_mod::f`
|
||||
--> $DIR/conf_disallowed_methods.rs:54:5
|
||||
|
|
||||
LL | local_mod::f();
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: use of a disallowed method `conf_disallowed_methods::Struct::method`
|
||||
--> $DIR/conf_disallowed_methods.rs:56:5
|
||||
|
|
||||
LL | s.method();
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method`
|
||||
--> $DIR/conf_disallowed_methods.rs:57:5
|
||||
|
|
||||
LL | s.provided_method();
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method`
|
||||
--> $DIR/conf_disallowed_methods.rs:58:5
|
||||
|
|
||||
LL | s.implemented_method();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 14 previous errors
|
||||
|
||||
|
|
Loading…
Reference in a new issue