Fix and improve internal lint checking for match_type usages

* Check for `const`s and `static`s from external crates
* Check for `LangItem`s
* Handle inherent functions which have the same name as a field
* Also check the following functions:
    * `match_trait_method`
    * `match_def_path`
    * `is_expr_path_def_path`
    * `is_qpath_def_path`
* Handle checking for a constructor to a diagnostic item or `LangItem`
This commit is contained in:
Jason Newcomb 2021-11-11 14:15:01 -05:00
parent 8e7af6b429
commit 162aa19793
26 changed files with 539 additions and 181 deletions

View File

@ -6,7 +6,7 @@ use rustc_hir::{def::Res, AsyncGeneratorKind, Body, BodyId, GeneratorKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::GeneratorInteriorTypeCause;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
use rustc_span::{sym, Span};
use crate::utils::conf::DisallowedType;
@ -276,9 +276,9 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedTy
}
fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
match_def_path(cx, def_id, &paths::MUTEX_GUARD)
|| match_def_path(cx, def_id, &paths::RWLOCK_READ_GUARD)
|| match_def_path(cx, def_id, &paths::RWLOCK_WRITE_GUARD)
cx.tcx.is_diagnostic_item(sym::MutexGuard, def_id)
|| cx.tcx.is_diagnostic_item(sym::RwLockReadGuard, def_id)
|| cx.tcx.is_diagnostic_item(sym::RwLockWriteGuard, def_id)
|| match_def_path(cx, def_id, &paths::PARKING_LOT_MUTEX_GUARD)
|| match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_READ_GUARD)
|| match_def_path(cx, def_id, &paths::PARKING_LOT_RWLOCK_WRITE_GUARD)

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::higher;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{higher, match_def_path, path_def_id, paths};
use rustc_hir::{BorrowKind, Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -168,9 +168,16 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
},
ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e),
ExprKind::Call(path, _) => path_def_id(cx, path)
.map_or(false, |id| match_def_path(cx, id, &paths::ITER_REPEAT))
.into(),
ExprKind::Call(path, _) => {
if let ExprKind::Path(ref qpath) = path.kind {
cx.qpath_res(qpath, path.hir_id)
.opt_def_id()
.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::iter_repeat, id))
.into()
} else {
Finite
}
},
ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(),
_ => Finite,
}

View File

@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method};
use clippy_utils::{return_ty, trait_ref_of_method};
use if_chain::if_chain;
use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind};
use rustc_lint::{LateContext, LateLintPass};
@ -118,7 +118,10 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
}
fn show_lint(cx: &LateContext<'_>, item: &ImplItem<'_>) {
let display_trait_id = get_trait_def_id(cx, &paths::DISPLAY_TRAIT).expect("Failed to get trait ID of `Display`!");
let display_trait_id = cx
.tcx
.get_diagnostic_item(sym::Display)
.expect("Failed to get trait ID of `Display`!");
// Get the real type of 'self'
let self_type = cx.tcx.fn_sig(item.def_id).input(0);

View File

@ -13,10 +13,10 @@ store.register_group(true, "clippy::internal", Some("clippy_internal"), vec![
LintId::of(utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE),
LintId::of(utils::internal_lints::INVALID_PATHS),
LintId::of(utils::internal_lints::LINT_WITHOUT_LINT_PASS),
LintId::of(utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM),
LintId::of(utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE),
LintId::of(utils::internal_lints::MISSING_MSRV_ATTR_IMPL),
LintId::of(utils::internal_lints::OUTER_EXPN_EXPN_DATA),
LintId::of(utils::internal_lints::PRODUCE_ICE),
LintId::of(utils::internal_lints::UNNECESSARY_DEF_PATH),
LintId::of(utils::internal_lints::UNNECESSARY_SYMBOL_STR),
])

View File

@ -24,8 +24,6 @@ store.register_lints(&[
#[cfg(feature = "internal")]
utils::internal_lints::LINT_WITHOUT_LINT_PASS,
#[cfg(feature = "internal")]
utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
#[cfg(feature = "internal")]
utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE,
#[cfg(feature = "internal")]
utils::internal_lints::MISSING_MSRV_ATTR_IMPL,
@ -34,6 +32,8 @@ store.register_lints(&[
#[cfg(feature = "internal")]
utils::internal_lints::PRODUCE_ICE,
#[cfg(feature = "internal")]
utils::internal_lints::UNNECESSARY_DEF_PATH,
#[cfg(feature = "internal")]
utils::internal_lints::UNNECESSARY_SYMBOL_STR,
almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE,
approx_const::APPROX_CONSTANT,

View File

@ -535,7 +535,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(utils::internal_lints::InvalidPaths));
store.register_late_pass(|_| Box::<utils::internal_lints::InterningDefinedSymbol>::default());
store.register_late_pass(|_| Box::<utils::internal_lints::LintWithoutLintPass>::default());
store.register_late_pass(|_| Box::new(utils::internal_lints::MatchTypeOnDiagItem));
store.register_late_pass(|_| Box::new(utils::internal_lints::UnnecessaryDefPath));
store.register_late_pass(|_| Box::new(utils::internal_lints::OuterExpnDataPass));
store.register_late_pass(|_| Box::new(utils::internal_lints::MsrvAttrImpl));
}

View File

@ -92,7 +92,7 @@ fn check_into_iter(
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
&& let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind
&& let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
&& match_def_path(cx, into_iter_def_id, &paths::CORE_ITER_INTO_ITER)
&& cx.tcx.lang_items().require(hir::LangItem::IntoIterIntoIter).ok() == Some(into_iter_def_id)
&& match_acceptable_type(cx, left_expr, msrv)
&& SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) {
suggest(cx, parent_expr, left_expr, target_expr);

View File

@ -1,17 +1,18 @@
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::match_type;
use clippy_utils::{get_parent_expr, paths};
use clippy_utils::get_parent_expr;
use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::source_map::Span;
use rustc_span::sym;
use super::FILETYPE_IS_FILE;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
let ty = cx.typeck_results().expr_ty(recv);
if !match_type(cx, ty, &paths::FILE_TYPE) {
if !is_type_diagnostic_item(cx, ty, sym::FileType) {
return;
}

View File

@ -65,7 +65,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
}
if let ty::Adt(adt, substs) = ty.kind() {
match_def_path(cx, adt.did(), &paths::COW) && substs.type_at(1).is_str()
cx.tcx.is_diagnostic_item(sym::Cow, adt.did()) && substs.type_at(1).is_str()
} else {
false
}

View File

@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_path_diagnostic_item;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
use clippy_utils::{is_expr_path_def_path, paths};
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use if_chain::if_chain;
use rustc_ast::LitKind;
use rustc_errors::Applicability;
@ -38,7 +38,7 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
let ty = cx.typeck_results().expr_ty(e);
if is_type_diagnostic_item(cx, ty, sym::String)
|| (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, Ty::is_str))
|| (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, Ty::is_str))
|| (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).map_or(false, Ty::is_str))
{
Some(RepeatKind::String)
} else {
@ -57,7 +57,7 @@ pub(super) fn check(
) {
if_chain! {
if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT);
if is_path_diagnostic_item(cx, repeat_fn, sym::iter_repeat);
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::String);
if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);

View File

@ -1,11 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::walk_ptrs_ty_depth;
use clippy_utils::{get_parent_expr, match_trait_method, paths};
use clippy_utils::{get_parent_expr, is_trait_method};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;
use super::USELESS_ASREF;
@ -13,7 +14,7 @@ use super::USELESS_ASREF;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, recvr: &hir::Expr<'_>) {
// when we get here, we've already checked that the call name is "as_ref" or "as_mut"
// check if the call is to the actual `AsRef` or `AsMut` trait
if match_trait_method(cx, expr, &paths::ASREF_TRAIT) || match_trait_method(cx, expr, &paths::ASMUT_TRAIT) {
if is_trait_method(cx, expr, sym::AsRef) || is_trait_method(cx, expr, sym::AsMut) {
// check if the type after `as_ref` or `as_mut` is the same as before
let rcv_ty = cx.typeck_results().expr_ty(recvr);
let res_ty = cx.typeck_results().expr_ty(expr);

View File

@ -1,6 +1,6 @@
use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::{match_trait_method, paths};
use clippy_utils::is_trait_method;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -83,7 +83,7 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
}
},
ExprKind::MethodCall(path, receiver, args @ [_], _) => {
if cx.typeck_results().expr_ty(receiver).is_floating_point() || match_trait_method(cx, expr, &paths::ORD) {
if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) {
if path.ident.name == sym!(max) {
fetch_const(cx, Some(receiver), args, MinMax::Max)
} else if path.ident.name == sym!(min) {

View File

@ -1,12 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
use clippy_utils::ty::match_type;
use clippy_utils::ty::{is_type_diagnostic_item, match_type};
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@ -49,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
if_chain! {
if (path.ident.name == sym!(mode)
&& (match_type(cx, obj_ty, &paths::OPEN_OPTIONS)
|| match_type(cx, obj_ty, &paths::DIR_BUILDER)))
|| is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder)))
|| (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS));
if let ExprKind::Lit(_) = param.kind;

View File

@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{
get_enclosing_block, is_expr_path_def_path, is_integer_literal, path_to_local, path_to_local_id, paths, SpanlessEq,
get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, SpanlessEq,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
@ -254,7 +254,7 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool {
if_chain! {
if let ExprKind::Call(fn_expr, [repeat_arg]) = expr.kind;
if is_expr_path_def_path(self.cx, fn_expr, &paths::ITER_REPEAT);
if is_path_diagnostic_item(self.cx, fn_expr, sym::iter_repeat);
if is_integer_literal(repeat_arg, 0);
then {
true

View File

@ -3,7 +3,7 @@ use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryOwnedEmptyStrings {
);
} else {
if_chain! {
if match_def_path(cx, fun_def_id, &paths::FROM_FROM);
if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(fun_def_id);
if let [.., last_arg] = args;
if let ExprKind::Lit(spanned) = &last_arg.kind;
if let LitKind::Str(symbol, _) = spanned.node;

View File

@ -1,8 +1,9 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::{is_try, match_trait_method, paths};
use clippy_utils::{is_trait_method, is_try, match_trait_method, paths};
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@ -116,13 +117,13 @@ fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Exp
match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT)
|| match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT)
} else {
match_trait_method(cx, call, &paths::IO_READ)
is_trait_method(cx, call, sym::IoRead)
};
let write_trait = if is_await {
match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT)
|| match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT)
} else {
match_trait_method(cx, call, &paths::IO_WRITE)
is_trait_method(cx, call, sym::IoWrite)
};
match (read_trait, write_trait, symbol, is_await) {

View File

@ -5,7 +5,7 @@ use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
use rustc_hir::{Expr, ExprKind, HirId, LangItem, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
}
if_chain! {
if match_def_path(cx, def_id, &paths::FROM_FROM);
if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(def_id);
if same_type_and_consts(a, b);
then {

View File

@ -2,11 +2,11 @@ use crate::utils::internal_lints::metadata_collector::is_deprecated_lint;
use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::source::snippet;
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::ty::match_type;
use clippy_utils::{
def_path_res, higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path,
method_calls, paths, peel_blocks_with_stmt, SpanlessEq,
def_path_res, higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_any_def_paths,
match_def_path, method_calls, paths, peel_blocks_with_stmt, peel_hir_expr_refs, SpanlessEq,
};
use if_chain::if_chain;
use rustc_ast as ast;
@ -20,21 +20,24 @@ use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{
BinOpKind, Block, Closure, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty,
BinOpKind, Block, Closure, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind,
TyKind, UnOp,
};
use rustc_hir_analysis::hir_ty_to_ty;
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_middle::hir::nested_filter;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::{self, fast_reject::SimplifiedTypeGen, subst::GenericArgKind, FloatTy};
use rustc_middle::mir::interpret::{Allocation, ConstValue, GlobalAlloc};
use rustc_middle::ty::{
self, fast_reject::SimplifiedTypeGen, subst::GenericArgKind, AssocKind, DefIdTree, FloatTy, Ty,
};
use rustc_semver::RustcVersion;
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Symbol;
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::{sym, BytePos, Span};
use std::borrow::{Borrow, Cow};
use std::str;
#[cfg(feature = "internal")]
pub mod metadata_collector;
@ -226,11 +229,11 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
/// Checks for calls to `utils::match_type()` on a type diagnostic item
/// and suggests to use `utils::is_type_diagnostic_item()` instead.
/// Checks for usages of def paths when a diagnostic item or a `LangItem` could be used.
///
/// ### Why is this bad?
/// `utils::is_type_diagnostic_item()` does not require hardcoded paths.
/// The path for an item is subject to change and is less efficient to look up than a
/// diagnostic item or a `LangItem`.
///
/// ### Example
/// ```rust,ignore
@ -241,9 +244,9 @@ declare_clippy_lint! {
/// ```rust,ignore
/// utils::is_type_diagnostic_item(cx, ty, sym::Vec)
/// ```
pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
pub UNNECESSARY_DEF_PATH,
internal,
"using `utils::match_type()` instead of `utils::is_type_diagnostic_item()`"
"using a def path when a diagnostic item or a `LangItem` is available"
}
declare_clippy_lint! {
@ -537,7 +540,7 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
}
}
fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &Ty<'_>) -> bool {
fn is_lint_ref_type<'tcx>(cx: &LateContext<'tcx>, ty: &hir::Ty<'_>) -> bool {
if let TyKind::Rptr(
_,
MutTy {
@ -888,89 +891,225 @@ fn suggest_note(
);
}
declare_lint_pass!(MatchTypeOnDiagItem => [MATCH_TYPE_ON_DIAGNOSTIC_ITEM]);
declare_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]);
impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
#[allow(clippy::too_many_lines)]
impl<'tcx> LateLintPass<'tcx> for UnnecessaryDefPath {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
if is_lint_allowed(cx, MATCH_TYPE_ON_DIAGNOSTIC_ITEM, expr.hir_id) {
enum Item {
LangItem(Symbol),
DiagnosticItem(Symbol),
}
static PATHS: &[&[&str]] = &[
&["clippy_utils", "match_def_path"],
&["clippy_utils", "match_trait_method"],
&["clippy_utils", "ty", "match_type"],
&["clippy_utils", "is_expr_path_def_path"],
];
if is_lint_allowed(cx, UNNECESSARY_DEF_PATH, expr.hir_id) {
return;
}
if_chain! {
// Check if this is a call to utils::match_type()
if let ExprKind::Call(fn_path, [context, ty, ty_path]) = expr.kind;
if is_expr_path_def_path(cx, fn_path, &["clippy_utils", "ty", "match_type"]);
if let ExprKind::Call(func, [cx_arg, def_arg, args@..]) = expr.kind;
if let ExprKind::Path(path) = &func.kind;
if let Some(id) = cx.qpath_res(path, func.hir_id).opt_def_id();
if let Some(which_path) = match_any_def_paths(cx, id, PATHS);
let item_arg = if which_path == 4 { &args[1] } else { &args[0] };
// Extract the path to the matched type
if let Some(segments) = path_to_matched_type(cx, ty_path);
let segments: Vec<&str> = segments.iter().map(Symbol::as_str).collect();
if let Some(ty_did) = def_path_res(cx, &segments[..]).opt_def_id();
// Check if the matched type is a diagnostic item
if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did);
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) = def_path_res(cx, &segments[..]).opt_def_id();
then {
// TODO: check paths constants from external crates.
let cx_snippet = snippet(cx, context.span, "_");
let ty_snippet = snippet(cx, ty.span, "_");
// def_path_res will match field names before anything else, but for this we want to match
// inherent functions first.
let 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
};
span_lint_and_sugg(
// Check if the target item is a diagnostic item or LangItem.
let (msg, item) = if let Some(item_name)
= cx.tcx.diagnostic_items(def_id.krate).id_to_name.get(&def_id)
{
(
"use of a def path to a diagnostic item",
Item::DiagnosticItem(*item_name),
)
} else 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"]).def_id();
let item_name = cx.tcx.adt_def(lang_items).variants().iter().nth(lang_item).unwrap().name;
(
"use of a def path to a `LangItem`",
Item::LangItem(item_name),
)
} else {
return;
};
let has_ctor = match cx.tcx.def_kind(def_id) {
DefKind::Struct => {
let variant = cx.tcx.adt_def(def_id).non_enum_variant();
variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
}
DefKind::Variant => {
let variant = cx.tcx.adt_def(cx.tcx.parent(def_id)).variant_with_id(def_id);
variant.ctor_def_id.is_some() && variant.fields.iter().all(|f| f.vis.is_public())
}
_ => false,
};
let mut app = Applicability::MachineApplicable;
let cx_snip = snippet_with_applicability(cx, cx_arg.span, "..", &mut app);
let def_snip = snippet_with_applicability(cx, def_arg.span, "..", &mut app);
let (sugg, with_note) = match (which_path, item) {
// match_def_path
(0, Item::DiagnosticItem(item)) =>
(format!("{cx_snip}.tcx.is_diagnostic_item(sym::{item}, {def_snip})"), has_ctor),
(0, Item::LangItem(item)) => (
format!("{cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some({def_snip})"),
has_ctor
),
// match_trait_method
(1, Item::DiagnosticItem(item)) =>
(format!("is_trait_method({cx_snip}, {def_snip}, sym::{item})"), false),
// match_type
(2, Item::DiagnosticItem(item)) =>
(format!("is_type_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), false),
(2, Item::LangItem(item)) =>
(format!("is_type_lang_item({cx_snip}, {def_snip}, LangItem::{item})"), false),
// is_expr_path_def_path
(3, Item::DiagnosticItem(item)) if has_ctor => (
format!(
"is_res_diag_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), sym::{item})",
),
false,
),
(3, Item::LangItem(item)) if has_ctor => (
format!(
"is_res_lang_ctor({cx_snip}, path_res({cx_snip}, {def_snip}), LangItem::{item})",
),
false,
),
(3, Item::DiagnosticItem(item)) =>
(format!("is_path_diagnostic_item({cx_snip}, {def_snip}, sym::{item})"), false),
(3, Item::LangItem(item)) => (
format!(
"path_res({cx_snip}, {def_snip}).opt_def_id()\
.map_or(false, |id| {cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some(id))",
),
false,
),
_ => return,
};
span_lint_and_then(
cx,
MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
UNNECESSARY_DEF_PATH,
expr.span,
"usage of `clippy_utils::ty::match_type()` on a type diagnostic item",
"try",
format!("clippy_utils::ty::is_type_diagnostic_item({cx_snippet}, {ty_snippet}, sym::{item_name})"),
Applicability::MaybeIncorrect,
msg,
|diag| {
diag.span_suggestion(expr.span, "try", sugg, app);
if with_note {
diag.help(
"if this `DefId` came from a constructor expression or pattern then the \
parent `DefId` should be used instead"
);
}
},
);
}
}
}
}
fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<Symbol>> {
use rustc_hir::ItemKind;
match &expr.kind {
ExprKind::AddrOf(.., expr) => return path_to_matched_type(cx, expr),
ExprKind::Path(qpath) => match cx.qpath_res(qpath, expr.hir_id) {
fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Vec<String>> {
match peel_hir_expr_refs(expr).0.kind {
ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
Res::Local(hir_id) => {
let parent_id = cx.tcx.hir().get_parent_node(hir_id);
if let Some(Node::Local(local)) = cx.tcx.hir().find(parent_id) {
if let Some(init) = local.init {
return path_to_matched_type(cx, init);
}
}
},
Res::Def(DefKind::Const | DefKind::Static(..), def_id) => {
if let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(def_id) {
if let ItemKind::Const(.., body_id) | ItemKind::Static(.., body_id) = item.kind {
let body = cx.tcx.hir().body(body_id);
return path_to_matched_type(cx, body.value);
}
}
},
_ => {},
},
ExprKind::Array(exprs) => {
let segments: Vec<Symbol> = exprs
.iter()
.filter_map(|expr| {
if let ExprKind::Lit(lit) = &expr.kind {
if let LitKind::Str(sym, _) = lit.node {
return Some(sym);
}
}
if let Some(Node::Local(Local { init: Some(init), .. })) = cx.tcx.hir().find(parent_id) {
path_to_matched_type(cx, init)
} else {
None
})
.collect();
if segments.len() == exprs.len() {
return Some(segments);
}
}
},
Res::Def(DefKind::Static(_), def_id) => read_mir_alloc_def_path(
cx,
cx.tcx.eval_static_initializer(def_id).ok()?.inner(),
cx.tcx.type_of(def_id),
),
Res::Def(DefKind::Const, def_id) => match cx.tcx.const_eval_poly(def_id).ok()? {
ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => {
read_mir_alloc_def_path(cx, alloc.inner(), cx.tcx.type_of(def_id))
},
_ => None,
},
_ => None,
},
_ => {},
}
ExprKind::Array(exprs) => exprs
.iter()
.map(|expr| {
if let ExprKind::Lit(lit) = &expr.kind {
if let LitKind::Str(sym, _) = lit.node {
return Some((*sym.as_str()).to_owned());
}
}
None
None
})
.collect(),
_ => None,
}
}
fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation, ty: Ty<'_>) -> Option<Vec<String>> {
let (alloc, ty) = if let ty::Ref(_, ty, Mutability::Not) = *ty.kind() {
let &alloc = alloc.provenance().values().next()?;
if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
(alloc.inner(), ty)
} else {
return None;
}
} else {
(alloc, ty)
};
if let ty::Array(ty, _) | ty::Slice(ty) = *ty.kind()
&& let ty::Ref(_, ty, Mutability::Not) = *ty.kind()
&& ty.is_str()
{
alloc
.provenance()
.values()
.map(|&alloc| {
if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
let alloc = alloc.inner();
str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()))
.ok().map(ToOwned::to_owned)
} else {
None
}
})
.collect()
} else {
None
}
}
// This is not a complete resolver for paths. It works on all the paths currently used in the paths

View File

@ -261,6 +261,46 @@ pub fn is_res_diagnostic_ctor(cx: &LateContext<'_>, res: Res, diag_item: Symbol)
}
}
/// Checks if a `QPath` resolves to a constructor of a diagnostic item.
pub fn is_diagnostic_ctor(cx: &LateContext<'_>, qpath: &QPath<'_>, diagnostic_item: Symbol) -> bool {
if let QPath::Resolved(_, path) = qpath {
if let Res::Def(DefKind::Ctor(..), ctor_id) = path.res {
return cx.tcx.is_diagnostic_item(diagnostic_item, cx.tcx.parent(ctor_id));
}
}
false
}
/// Checks if the `DefId` matches the given diagnostic item or it's constructor.
pub fn is_diagnostic_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: Symbol) -> bool {
let did = match cx.tcx.def_kind(did) {
DefKind::Ctor(..) => cx.tcx.parent(did),
// Constructors for types in external crates seem to have `DefKind::Variant`
DefKind::Variant => match cx.tcx.opt_parent(did) {
Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,
_ => did,
},
_ => did,
};
cx.tcx.is_diagnostic_item(item, did)
}
/// Checks if the `DefId` matches the given `LangItem` or it's constructor.
pub fn is_lang_item_or_ctor(cx: &LateContext<'_>, did: DefId, item: LangItem) -> bool {
let did = match cx.tcx.def_kind(did) {
DefKind::Ctor(..) => cx.tcx.parent(did),
// Constructors for types in external crates seem to have `DefKind::Variant`
DefKind::Variant => match cx.tcx.opt_parent(did) {
Some(did) if matches!(cx.tcx.def_kind(did), DefKind::Variant) => did,
_ => did,
},
_ => did,
};
cx.tcx.lang_items().require(item).map_or(false, |id| id == did)
}
pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
matches!(
expr.kind,
@ -496,6 +536,13 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
.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,
}
}

View File

@ -34,7 +34,6 @@ pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "defa
pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
/// Preferably use the diagnostic item `sym::deref_method` where possible
pub const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
pub const DIR_BUILDER: [&str; 3] = ["std", "fs", "DirBuilder"];
pub const DISPLAY_TRAIT: [&str; 3] = ["core", "fmt", "Display"];
#[cfg(feature = "internal")]
pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
@ -64,8 +63,6 @@ pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
pub const IO_READ: [&str; 3] = ["std", "io", "Read"];
pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"];
pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"];
pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"];

View File

@ -0,0 +1,2 @@
pub static OPTION: [&str; 3] = ["core", "option", "Option"];
pub const RESULT: &[&str] = &["core", "result", "Result"];

View File

@ -1,39 +0,0 @@
#![deny(clippy::internal)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
extern crate clippy_utils;
extern crate rustc_hir;
extern crate rustc_lint;
extern crate rustc_middle;
#[macro_use]
extern crate rustc_session;
use clippy_utils::{paths, ty::match_type};
use rustc_hir::Expr;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
declare_lint! {
pub TEST_LINT,
Warn,
""
}
declare_lint_pass!(Pass => [TEST_LINT]);
static OPTION: [&str; 3] = ["core", "option", "Option"];
impl<'tcx> LateLintPass<'tcx> for Pass {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr) {
let ty = cx.typeck_results().expr_ty(expr);
let _ = match_type(cx, ty, &OPTION);
let _ = match_type(cx, ty, &["core", "result", "Result"]);
let rc_path = &["alloc", "rc", "Rc"];
let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
}
}
fn main() {}

View File

@ -1,27 +0,0 @@
error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
--> $DIR/match_type_on_diag_item.rs:31:17
|
LL | let _ = match_type(cx, ty, &OPTION);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Option)`
|
note: the lint level is defined here
--> $DIR/match_type_on_diag_item.rs:1:9
|
LL | #![deny(clippy::internal)]
| ^^^^^^^^^^^^^^^^
= note: `#[deny(clippy::match_type_on_diagnostic_item)]` implied by `#[deny(clippy::internal)]`
error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
--> $DIR/match_type_on_diag_item.rs:32:17
|
LL | let _ = match_type(cx, ty, &["core", "result", "Result"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Result)`
error: usage of `clippy_utils::ty::match_type()` on a type diagnostic item
--> $DIR/match_type_on_diag_item.rs:35:17
|
LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clippy_utils::ty::is_type_diagnostic_item(cx, ty, sym::Rc)`
error: aborting due to 3 previous errors

View File

@ -0,0 +1,62 @@
// run-rustfix
// aux-build:paths.rs
#![deny(clippy::internal)]
#![feature(rustc_private)]
extern crate clippy_utils;
extern crate paths;
extern crate rustc_hir;
extern crate rustc_lint;
extern crate rustc_middle;
extern crate rustc_span;
#[allow(unused)]
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
#[allow(unused)]
use clippy_utils::{
is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method,
match_def_path, match_trait_method, path_res,
};
#[allow(unused)]
use rustc_hir::LangItem;
#[allow(unused)]
use rustc_span::sym;
use rustc_hir::def_id::DefId;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::ty::Ty;
#[allow(unused)]
static OPTION: [&str; 3] = ["core", "option", "Option"];
#[allow(unused)]
const RESULT: &[&str] = &["core", "result", "Result"];
fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) {
let _ = is_type_diagnostic_item(cx, ty, sym::Option);
let _ = is_type_diagnostic_item(cx, ty, sym::Result);
let _ = is_type_diagnostic_item(cx, ty, sym::Result);
#[allow(unused)]
let rc_path = &["alloc", "rc", "Rc"];
let _ = is_type_diagnostic_item(cx, ty, sym::Rc);
let _ = is_type_diagnostic_item(cx, ty, sym::Option);
let _ = is_type_diagnostic_item(cx, ty, sym::Result);
let _ = is_type_lang_item(cx, ty, LangItem::OwnedBox);
let _ = is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit);
let _ = cx.tcx.lang_items().require(LangItem::OwnedBox).ok() == Some(did);
let _ = cx.tcx.is_diagnostic_item(sym::Option, did);
let _ = cx.tcx.lang_items().require(LangItem::OptionSome).ok() == Some(did);
let _ = is_trait_method(cx, expr, sym::AsRef);
let _ = is_path_diagnostic_item(cx, expr, sym::Option);
let _ = path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().require(LangItem::IteratorNext).ok() == Some(id));
let _ = is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome);
}
fn main() {}

View File

@ -0,0 +1,62 @@
// run-rustfix
// aux-build:paths.rs
#![deny(clippy::internal)]
#![feature(rustc_private)]
extern crate clippy_utils;
extern crate paths;
extern crate rustc_hir;
extern crate rustc_lint;
extern crate rustc_middle;
extern crate rustc_span;
#[allow(unused)]
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
#[allow(unused)]
use clippy_utils::{
is_expr_path_def_path, is_path_diagnostic_item, is_res_diagnostic_ctor, is_res_lang_ctor, is_trait_method,
match_def_path, match_trait_method, path_res,
};
#[allow(unused)]
use rustc_hir::LangItem;
#[allow(unused)]
use rustc_span::sym;
use rustc_hir::def_id::DefId;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::ty::Ty;
#[allow(unused)]
static OPTION: [&str; 3] = ["core", "option", "Option"];
#[allow(unused)]
const RESULT: &[&str] = &["core", "result", "Result"];
fn _f<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, did: DefId, expr: &Expr<'_>) {
let _ = match_type(cx, ty, &OPTION);
let _ = match_type(cx, ty, RESULT);
let _ = match_type(cx, ty, &["core", "result", "Result"]);
#[allow(unused)]
let rc_path = &["alloc", "rc", "Rc"];
let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
let _ = match_type(cx, ty, &paths::OPTION);
let _ = match_type(cx, ty, paths::RESULT);
let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]);
let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]);
let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]);
let _ = match_def_path(cx, did, &["core", "option", "Option"]);
let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]);
let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]);
let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]);
let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]);
}
fn main() {}

View File

@ -0,0 +1,101 @@
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:37:13
|
LL | let _ = match_type(cx, ty, &OPTION);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
|
note: the lint level is defined here
--> $DIR/unnecessary_def_path.rs:3:9
|
LL | #![deny(clippy::internal)]
| ^^^^^^^^^^^^^^^^
= note: `#[deny(clippy::unnecessary_def_path)]` implied by `#[deny(clippy::internal)]`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:38:13
|
LL | let _ = match_type(cx, ty, RESULT);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:39:13
|
LL | let _ = match_type(cx, ty, &["core", "result", "Result"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:43:13
|
LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Rc)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:45:13
|
LL | let _ = match_type(cx, ty, &paths::OPTION);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:46:13
|
LL | let _ = match_type(cx, ty, paths::RESULT);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
error: use of a def path to a `LangItem`
--> $DIR/unnecessary_def_path.rs:48:13
|
LL | let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_lang_item(cx, ty, LangItem::OwnedBox)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:49:13
|
LL | let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit)`
error: use of a def path to a `LangItem`
--> $DIR/unnecessary_def_path.rs:51:13
|
LL | let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().require(LangItem::OwnedBox).ok() == Some(did)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:52:13
|
LL | let _ = match_def_path(cx, did, &["core", "option", "Option"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.is_diagnostic_item(sym::Option, did)`
error: use of a def path to a `LangItem`
--> $DIR/unnecessary_def_path.rs:53:13
|
LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().require(LangItem::OptionSome).ok() == Some(did)`
|
= help: if this `DefId` came from a constructor expression or pattern then the parent `DefId` should be used instead
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:55:13
|
LL | let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_trait_method(cx, expr, sym::AsRef)`
error: use of a def path to a diagnostic item
--> $DIR/unnecessary_def_path.rs:57:13
|
LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_path_diagnostic_item(cx, expr, sym::Option)`
error: use of a def path to a `LangItem`
--> $DIR/unnecessary_def_path.rs:58:13
|
LL | let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().require(LangItem::IteratorNext).ok() == Some(id))`
error: use of a def path to a `LangItem`
--> $DIR/unnecessary_def_path.rs:59:13
|
LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome)`
error: aborting due to 15 previous errors