mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Auto merge of #8305 - camsteffen:util-cleanup, r=flip1995
Factor out several utils, add `path_def_id` changelog: none This is generally an effort to reduce the total number of utils. `path_def_id` is added which I believe is more "cross-cutting" and also complements `path_to_local`. Best reviewed one commit at a time. Added: * `path_def_id` * `path_res` Removed: * `is_qpath_def_path` * `match_any_diagnostic_items` * `expr_path_res` * `single_segment_path` * `differing_macro_contexts` * `is_ty_param_lang_item` * `is_ty_param_diagnostic_item` * `get_qpath_generics` Renamed: * `path_to_res` to `def_path_res` * `get_qpath_generic_tys` to `qpath_generic_tys` CC `@Jarcho` since this relates to some of your work and you may have input.
This commit is contained in:
commit
3d43826e32
@ -1,8 +1,8 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
|
||||
use clippy_utils::get_parent_expr;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet_block_with_applicability;
|
||||
use clippy_utils::ty::implements_trait;
|
||||
use clippy_utils::{differing_macro_contexts, get_parent_expr};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, Visitor};
|
||||
@ -97,7 +97,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
|
||||
if let Some(ex) = &block.expr {
|
||||
// don't dig into the expression here, just suggest that they remove
|
||||
// the block
|
||||
if expr.span.from_expansion() || differing_macro_contexts(expr.span, ex.span) {
|
||||
if expr.span.from_expansion() || ex.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions {
|
||||
}
|
||||
} else {
|
||||
let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
|
||||
if span.from_expansion() || differing_macro_contexts(expr.span, span) {
|
||||
if span.from_expansion() || expr.span.from_expansion() {
|
||||
return;
|
||||
}
|
||||
// move block higher
|
||||
|
@ -77,7 +77,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::path_to_res(cx, &segs) {
|
||||
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) {
|
||||
self.disallowed.insert(id, index);
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
|
||||
),
|
||||
};
|
||||
let segs: Vec<_> = path.split("::").collect();
|
||||
match clippy_utils::path_to_res(cx, &segs) {
|
||||
match clippy_utils::def_path_res(cx, &segs) {
|
||||
Res::Def(_, id) => {
|
||||
self.def_ids.insert(id, reason);
|
||||
},
|
||||
|
@ -1,5 +1,4 @@
|
||||
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
|
||||
use clippy_utils::differing_macro_contexts;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
|
||||
@ -135,7 +134,7 @@ impl EarlyLintPass for Formatting {
|
||||
/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
|
||||
fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if let ExprKind::Assign(ref lhs, ref rhs, _) = expr.kind {
|
||||
if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion() {
|
||||
if !lhs.span.from_expansion() && !rhs.span.from_expansion() {
|
||||
let eq_span = lhs.span.between(rhs.span);
|
||||
if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind {
|
||||
if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
|
||||
@ -165,7 +164,7 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if_chain! {
|
||||
if let ExprKind::Binary(ref binop, ref lhs, ref rhs) = expr.kind;
|
||||
if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion();
|
||||
if !lhs.span.from_expansion() && !rhs.span.from_expansion();
|
||||
// span between BinOp LHS and RHS
|
||||
let binop_span = lhs.span.between(rhs.span);
|
||||
// if RHS is an UnOp
|
||||
@ -206,8 +205,8 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
if_chain! {
|
||||
if let ExprKind::If(_, then, Some(else_)) = &expr.kind;
|
||||
if is_block(else_) || is_if(else_);
|
||||
if !differing_macro_contexts(then.span, else_.span);
|
||||
if !then.span.from_expansion() && !in_external_macro(cx.sess(), expr.span);
|
||||
if !then.span.from_expansion() && !else_.span.from_expansion();
|
||||
if !in_external_macro(cx.sess(), expr.span);
|
||||
|
||||
// workaround for rust-lang/rust#43081
|
||||
if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;
|
||||
@ -268,7 +267,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
for element in array {
|
||||
if_chain! {
|
||||
if let ExprKind::Binary(ref op, ref lhs, _) = element.kind;
|
||||
if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span);
|
||||
if has_unary_equivalent(op.node) && lhs.span.ctxt() == op.span.ctxt();
|
||||
let space_span = lhs.span.between(op.span);
|
||||
if let Some(space_snippet) = snippet_opt(cx, space_span);
|
||||
let lint_span = lhs.span.with_lo(lhs.span.hi());
|
||||
@ -291,8 +290,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
|
||||
|
||||
fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
|
||||
if_chain! {
|
||||
if !differing_macro_contexts(first.span, second.span);
|
||||
if !first.span.from_expansion();
|
||||
if !first.span.from_expansion() && !second.span.from_expansion();
|
||||
if let ExprKind::If(cond_expr, ..) = &first.kind;
|
||||
if is_block(second) || is_if(second);
|
||||
|
||||
|
@ -17,7 +17,6 @@ use rustc_typeck::hir_ty_to_ty;
|
||||
use if_chain::if_chain;
|
||||
|
||||
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
|
||||
use clippy_utils::differing_macro_contexts;
|
||||
use clippy_utils::source::{snippet, snippet_opt};
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
|
||||
@ -123,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
|
||||
vis.visit_ty(impl_.self_ty);
|
||||
|
||||
for target in &vis.found {
|
||||
if differing_macro_contexts(item.span, target.span()) {
|
||||
if item.span.ctxt() != target.span().ctxt() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||
use clippy_utils::{get_trait_def_id, higher, is_qpath_def_path, paths};
|
||||
use clippy_utils::{get_trait_def_id, higher, match_def_path, path_def_id, paths};
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||
@ -167,13 +167,9 @@ 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, _) => {
|
||||
if let ExprKind::Path(ref qpath) = path.kind {
|
||||
is_qpath_def_path(cx, qpath, path.hir_id, &paths::ITER_REPEAT).into()
|
||||
} else {
|
||||
Finite
|
||||
}
|
||||
},
|
||||
ExprKind::Call(path, _) => path_def_id(cx, path)
|
||||
.map_or(false, |id| match_def_path(cx, id, &paths::ITER_REPEAT))
|
||||
.into(),
|
||||
ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(),
|
||||
_ => Finite,
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
use super::SINGLE_ELEMENT_LOOP;
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::single_segment_path;
|
||||
use clippy_utils::source::{indent_of, snippet};
|
||||
use clippy_utils::source::{indent_of, snippet_with_applicability};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, Pat, PatKind};
|
||||
use rustc_hir::{BorrowKind, Expr, ExprKind, Pat};
|
||||
use rustc_lint::LateContext;
|
||||
|
||||
pub(super) fn check<'tcx>(
|
||||
@ -16,24 +15,21 @@ pub(super) fn check<'tcx>(
|
||||
) {
|
||||
let arg_expr = match arg.kind {
|
||||
ExprKind::AddrOf(BorrowKind::Ref, _, ref_arg) => ref_arg,
|
||||
ExprKind::MethodCall(method, args, _) if args.len() == 1 && method.ident.name == rustc_span::sym::iter => {
|
||||
&args[0]
|
||||
},
|
||||
ExprKind::MethodCall(method, [arg], _) if method.ident.name == rustc_span::sym::iter => arg,
|
||||
_ => return,
|
||||
};
|
||||
if_chain! {
|
||||
if let PatKind::Binding(.., target, _) = pat.kind;
|
||||
if let ExprKind::Array([arg_expression]) = arg_expr.kind;
|
||||
if let ExprKind::Path(ref list_item) = arg_expression.kind;
|
||||
if let Some(list_item_name) = single_segment_path(list_item).map(|ps| ps.ident.name);
|
||||
if let ExprKind::Block(block, _) = body.kind;
|
||||
if !block.stmts.is_empty();
|
||||
|
||||
then {
|
||||
let mut block_str = snippet(cx, block.span, "..").into_owned();
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
|
||||
let arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability);
|
||||
let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned();
|
||||
block_str.remove(0);
|
||||
block_str.pop();
|
||||
|
||||
let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0));
|
||||
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
@ -41,8 +37,8 @@ pub(super) fn check<'tcx>(
|
||||
expr.span,
|
||||
"for loop over a single element",
|
||||
"try",
|
||||
format!("{{\n{}let {} = &{};{}}}", " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)), target.name, list_item_name, block_str),
|
||||
Applicability::MachineApplicable
|
||||
format!("{{\n{}let {} = &{};{}}}", indent, pat_snip, arg_snip, block_str),
|
||||
applicability,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1860,22 +1860,22 @@ where
|
||||
mod redundant_pattern_match {
|
||||
use super::REDUNDANT_PATTERN_MATCHING;
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
|
||||
use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths};
|
||||
use clippy_utils::{higher, match_def_path};
|
||||
use clippy_utils::{is_lang_ctor, is_trait_method, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::LitKind;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
|
||||
use rustc_hir::LangItem::{OptionNone, PollPending};
|
||||
use rustc_hir::{
|
||||
intravisit::{walk_expr, Visitor},
|
||||
Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath, UnOp,
|
||||
};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
|
||||
use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty};
|
||||
use rustc_span::sym;
|
||||
|
||||
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||
@ -2051,28 +2051,31 @@ mod redundant_pattern_match {
|
||||
has_else: bool,
|
||||
) {
|
||||
// also look inside refs
|
||||
let mut kind = &let_pat.kind;
|
||||
// if we have &None for example, peel it so we can detect "if let None = x"
|
||||
if let PatKind::Ref(inner, _mutability) = kind {
|
||||
kind = &inner.kind;
|
||||
}
|
||||
let check_pat = match let_pat.kind {
|
||||
PatKind::Ref(inner, _mutability) => inner,
|
||||
_ => let_pat,
|
||||
};
|
||||
let op_ty = cx.typeck_results().expr_ty(let_expr);
|
||||
// Determine which function should be used, and the type contained by the corresponding
|
||||
// variant.
|
||||
let (good_method, inner_ty) = match kind {
|
||||
PatKind::TupleStruct(ref path, [sub_pat], _) => {
|
||||
let (good_method, inner_ty) = match check_pat.kind {
|
||||
PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
|
||||
if let PatKind::Wild = sub_pat.kind {
|
||||
if is_lang_ctor(cx, path, ResultOk) {
|
||||
let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
|
||||
let Some(id) = res.opt_def_id().and_then(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
|
||||
let lang_items = cx.tcx.lang_items();
|
||||
if Some(id) == lang_items.result_ok_variant() {
|
||||
("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
|
||||
} else if is_lang_ctor(cx, path, ResultErr) {
|
||||
} else if Some(id) == lang_items.result_err_variant() {
|
||||
("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty))
|
||||
} else if is_lang_ctor(cx, path, OptionSome) {
|
||||
} else if Some(id) == lang_items.option_some_variant() {
|
||||
("is_some()", op_ty)
|
||||
} else if is_lang_ctor(cx, path, PollReady) {
|
||||
} else if Some(id) == lang_items.poll_ready_variant() {
|
||||
("is_ready()", op_ty)
|
||||
} else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V4) {
|
||||
} else if match_def_path(cx, id, &paths::IPADDR_V4) {
|
||||
("is_ipv4()", op_ty)
|
||||
} else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V6) {
|
||||
} else if match_def_path(cx, id, &paths::IPADDR_V6) {
|
||||
("is_ipv6()", op_ty)
|
||||
} else {
|
||||
return;
|
||||
@ -2272,17 +2275,22 @@ mod redundant_pattern_match {
|
||||
should_be_left: &'a str,
|
||||
should_be_right: &'a str,
|
||||
) -> Option<&'a str> {
|
||||
let body_node_pair = if is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_left)
|
||||
&& is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_right)
|
||||
{
|
||||
(&(*arms[0].body).kind, &(*arms[1].body).kind)
|
||||
} else if is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_left)
|
||||
&& is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_right)
|
||||
{
|
||||
(&(*arms[1].body).kind, &(*arms[0].body).kind)
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
let left_id = cx
|
||||
.typeck_results()
|
||||
.qpath_res(path_left, arms[0].pat.hir_id)
|
||||
.opt_def_id()?;
|
||||
let right_id = cx
|
||||
.typeck_results()
|
||||
.qpath_res(path_right, arms[1].pat.hir_id)
|
||||
.opt_def_id()?;
|
||||
let body_node_pair =
|
||||
if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) {
|
||||
(&(*arms[0].body).kind, &(*arms[1].body).kind)
|
||||
} else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) {
|
||||
(&(*arms[1].body).kind, &(*arms[0].body).kind)
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
match body_node_pair {
|
||||
(ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
|
||||
|
@ -1,13 +1,12 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{method_chain_args, single_segment_path};
|
||||
use clippy_utils::{method_chain_args, path_def_id};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_lint::Lint;
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::sym;
|
||||
use rustc_middle::ty::{self, DefIdTree};
|
||||
|
||||
/// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
|
||||
pub(super) fn check(
|
||||
@ -19,11 +18,9 @@ pub(super) fn check(
|
||||
) -> bool {
|
||||
if_chain! {
|
||||
if let Some(args) = method_chain_args(info.chain, chain_methods);
|
||||
if let hir::ExprKind::Call(fun, arg_char) = info.other.kind;
|
||||
if arg_char.len() == 1;
|
||||
if let hir::ExprKind::Path(ref qpath) = fun.kind;
|
||||
if let Some(segment) = single_segment_path(qpath);
|
||||
if segment.ident.name == sym::Some;
|
||||
if let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind;
|
||||
if let Some(id) = path_def_id(cx, fun).and_then(|ctor_id| cx.tcx.parent(ctor_id));
|
||||
if Some(id) == cx.tcx.lang_items().option_some_variant();
|
||||
then {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
|
||||
@ -42,7 +39,7 @@ pub(super) fn check(
|
||||
if info.eq { "" } else { "!" },
|
||||
snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
|
||||
suggest,
|
||||
snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)),
|
||||
snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
|
||||
applicability,
|
||||
);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::is_qpath_def_path;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{match_def_path, path_def_id};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast;
|
||||
use rustc_errors::Applicability;
|
||||
@ -93,12 +93,12 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option<M
|
||||
let ty_str = ty.to_string();
|
||||
|
||||
// `std::T::MAX` `std::T::MIN` constants
|
||||
if let hir::ExprKind::Path(path) = &expr.kind {
|
||||
if is_qpath_def_path(cx, path, expr.hir_id, &["core", &ty_str, "MAX"][..]) {
|
||||
if let Some(id) = path_def_id(cx, expr) {
|
||||
if match_def_path(cx, id, &["core", &ty_str, "MAX"]) {
|
||||
return Some(MinMax::Max);
|
||||
}
|
||||
|
||||
if is_qpath_def_path(cx, path, expr.hir_id, &["core", &ty_str, "MIN"][..]) {
|
||||
if match_def_path(cx, id, &["core", &ty_str, "MIN"]) {
|
||||
return Some(MinMax::Min);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{is_lang_ctor, single_segment_path};
|
||||
use clippy_utils::{is_lang_ctor, path_def_id};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::LangItem::{OptionNone, OptionSome};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::DefIdTree;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
use super::OPTION_MAP_OR_NONE;
|
||||
@ -76,13 +77,11 @@ pub(super) fn check<'tcx>(
|
||||
if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind;
|
||||
let arg_snippet = snippet(cx, span, "..");
|
||||
let body = cx.tcx.hir().body(id);
|
||||
if let Some((func, arg_char)) = reduce_unit_expression(cx, &body.value);
|
||||
if arg_char.len() == 1;
|
||||
if let hir::ExprKind::Path(ref qpath) = func.kind;
|
||||
if let Some(segment) = single_segment_path(qpath);
|
||||
if segment.ident.name == sym::Some;
|
||||
if let Some((func, [arg_char])) = reduce_unit_expression(cx, &body.value);
|
||||
if let Some(id) = path_def_id(cx, func).and_then(|ctor_id| cx.tcx.parent(ctor_id));
|
||||
if Some(id) == cx.tcx.lang_items().option_some_variant();
|
||||
then {
|
||||
let func_snippet = snippet(cx, arg_char[0].span, "..");
|
||||
let func_snippet = snippet(cx, arg_char.span, "..");
|
||||
let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
|
||||
`map(..)` instead";
|
||||
return span_lint_and_sugg(
|
||||
|
@ -1,5 +1,4 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::differing_macro_contexts;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::ty::is_copy;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
@ -48,7 +47,7 @@ pub(super) fn check<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
if differing_macro_contexts(unwrap_arg.span, map_span) {
|
||||
if unwrap_arg.span.ctxt() != map_span.ctxt() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,8 @@ use rustc_span::symbol::sym;
|
||||
use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{
|
||||
expr_path_res, get_item_name, get_parent_expr, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats,
|
||||
last_path_segment, match_any_def_paths, paths, unsext, SpanlessEq,
|
||||
get_item_name, get_parent_expr, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats,
|
||||
last_path_segment, match_any_def_paths, path_def_id, paths, unsext, SpanlessEq,
|
||||
};
|
||||
|
||||
declare_clippy_lint! {
|
||||
@ -583,8 +583,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left:
|
||||
)
|
||||
},
|
||||
ExprKind::Call(path, [arg]) => {
|
||||
if expr_path_res(cx, path)
|
||||
.opt_def_id()
|
||||
if path_def_id(cx, path)
|
||||
.and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM]))
|
||||
.is_some()
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ impl_lint_pass!(ImportRename => [MISSING_ENFORCED_IMPORT_RENAMES]);
|
||||
impl LateLintPass<'_> for ImportRename {
|
||||
fn check_crate(&mut self, cx: &LateContext<'_>) {
|
||||
for Rename { path, rename } in &self.conf_renames {
|
||||
if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &path.split("::").collect::<Vec<_>>()) {
|
||||
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &path.split("::").collect::<Vec<_>>()) {
|
||||
self.renames.insert(id, Symbol::intern(rename));
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,7 @@
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::ty::expr_sig;
|
||||
use clippy_utils::{
|
||||
expr_path_res, get_expr_use_or_unification_node, is_lint_allowed, match_any_diagnostic_items, path_to_local, paths,
|
||||
};
|
||||
use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -673,8 +671,8 @@ fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutabil
|
||||
|
||||
fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
|
||||
if let ExprKind::Call(pathexp, []) = expr.kind {
|
||||
expr_path_res(cx, pathexp).opt_def_id().map_or(false, |id| {
|
||||
match_any_diagnostic_items(cx, id, &[sym::ptr_null, sym::ptr_null_mut]).is_some()
|
||||
path_def_id(cx, pathexp).map_or(false, |id| {
|
||||
matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut))
|
||||
})
|
||||
} else {
|
||||
false
|
||||
|
@ -2,19 +2,18 @@ use clippy_utils::consts::{constant, Constant};
|
||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, single_segment_path};
|
||||
use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local};
|
||||
use clippy_utils::{higher, SpanlessEq};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast::ast::RangeLimits;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath};
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, PathSegment, QPath};
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_middle::ty;
|
||||
use rustc_semver::RustcVersion;
|
||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||
use rustc_span::source_map::{Span, Spanned};
|
||||
use rustc_span::sym;
|
||||
use rustc_span::symbol::Ident;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
declare_clippy_lint! {
|
||||
@ -220,12 +219,12 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
|
||||
_ => return,
|
||||
};
|
||||
// value, name, order (higher/lower), inclusiveness
|
||||
if let (Some((lval, lname, name_span, lval_span, lord, linc)), Some((rval, rname, _, rval_span, rord, rinc))) =
|
||||
if let (Some((lval, lid, name_span, lval_span, lord, linc)), Some((rval, rid, _, rval_span, rord, rinc))) =
|
||||
(check_range_bounds(cx, l), check_range_bounds(cx, r))
|
||||
{
|
||||
// we only lint comparisons on the same name and with different
|
||||
// direction
|
||||
if lname != rname || lord == rord {
|
||||
if lid != rid || lord == rord {
|
||||
return;
|
||||
}
|
||||
let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l), &lval, &rval);
|
||||
@ -293,7 +292,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
|
||||
}
|
||||
}
|
||||
|
||||
fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, Ident, Span, Span, Ordering, bool)> {
|
||||
fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, HirId, Span, Span, Ordering, bool)> {
|
||||
if let ExprKind::Binary(ref op, l, r) = ex.kind {
|
||||
let (inclusive, ordering) = match op.node {
|
||||
BinOpKind::Gt => (false, Ordering::Greater),
|
||||
@ -302,11 +301,11 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant,
|
||||
BinOpKind::Le => (true, Ordering::Less),
|
||||
_ => return None,
|
||||
};
|
||||
if let Some(id) = match_ident(l) {
|
||||
if let Some(id) = path_to_local(l) {
|
||||
if let Some((c, _)) = constant(cx, cx.typeck_results(), r) {
|
||||
return Some((c, id, l.span, r.span, ordering, inclusive));
|
||||
}
|
||||
} else if let Some(id) = match_ident(r) {
|
||||
} else if let Some(id) = path_to_local(r) {
|
||||
if let Some((c, _)) = constant(cx, cx.typeck_results(), l) {
|
||||
return Some((c, id, r.span, l.span, ordering.reverse(), inclusive));
|
||||
}
|
||||
@ -315,17 +314,6 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant,
|
||||
None
|
||||
}
|
||||
|
||||
fn match_ident(e: &Expr<'_>) -> Option<Ident> {
|
||||
if let ExprKind::Path(ref qpath) = e.kind {
|
||||
if let Some(seg) = single_segment_path(qpath) {
|
||||
if seg.args.is_none() {
|
||||
return Some(seg.ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) {
|
||||
if_chain! {
|
||||
if path.ident.as_str() == "zip";
|
||||
|
@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::sugg::Sugg;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{can_mut_borrow_both, differing_macro_contexts, eq_expr_value, std_or_core};
|
||||
use clippy_utils::{can_mut_borrow_both, eq_expr_value, std_or_core};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
|
||||
@ -172,7 +172,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
|
||||
if_chain! {
|
||||
if let StmtKind::Semi(first) = w[0].kind;
|
||||
if let StmtKind::Semi(second) = w[1].kind;
|
||||
if !differing_macro_contexts(first.span, second.span);
|
||||
if first.span.ctxt() == second.span.ctxt();
|
||||
if let ExprKind::Assign(lhs0, rhs0, _) = first.kind;
|
||||
if let ExprKind::Assign(lhs1, rhs1, _) = second.kind;
|
||||
if eq_expr_value(cx, lhs0, rhs1);
|
||||
|
@ -1,29 +1,31 @@
|
||||
use super::utils::is_layout_incompatible;
|
||||
use super::UNSOUND_COLLECTION_TRANSMUTE;
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::match_any_diagnostic_items;
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
||||
// used to check for UNSOUND_COLLECTION_TRANSMUTE
|
||||
static COLLECTIONS: &[Symbol] = &[
|
||||
sym::Vec,
|
||||
sym::VecDeque,
|
||||
sym::BinaryHeap,
|
||||
sym::BTreeSet,
|
||||
sym::BTreeMap,
|
||||
sym::HashSet,
|
||||
sym::HashMap,
|
||||
];
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
/// Checks for `unsound_collection_transmute` lint.
|
||||
/// Returns `true` if it's triggered, otherwise returns `false`.
|
||||
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> bool {
|
||||
match (&from_ty.kind(), &to_ty.kind()) {
|
||||
(ty::Adt(from_adt, from_substs), ty::Adt(to_adt, to_substs)) => {
|
||||
if from_adt.did != to_adt.did || match_any_diagnostic_items(cx, to_adt.did, COLLECTIONS).is_none() {
|
||||
if from_adt.did != to_adt.did {
|
||||
return false;
|
||||
}
|
||||
if !matches!(
|
||||
cx.tcx.get_diagnostic_name(to_adt.did),
|
||||
Some(
|
||||
sym::BTreeMap
|
||||
| sym::BTreeSet
|
||||
| sym::BinaryHeap
|
||||
| sym::HashMap
|
||||
| sym::HashSet
|
||||
| sym::Vec
|
||||
| sym::VecDeque
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if from_substs
|
||||
|
@ -1,8 +1,8 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_ty_param_diagnostic_item;
|
||||
use clippy_utils::{path_def_id, qpath_generic_tys};
|
||||
use rustc_hir::{self as hir, def_id::DefId, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{sym, Symbol};
|
||||
|
||||
use super::BOX_COLLECTION;
|
||||
|
||||
@ -11,10 +11,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
|
||||
if Some(def_id) == cx.tcx.lang_items().owned_box();
|
||||
if let Some(item_type) = get_std_collection(cx, qpath);
|
||||
then {
|
||||
let generic = if item_type == "String" {
|
||||
""
|
||||
} else {
|
||||
"<..>"
|
||||
let generic = match item_type {
|
||||
sym::String => "",
|
||||
_ => "<..>",
|
||||
};
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
@ -37,14 +36,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
|
||||
}
|
||||
}
|
||||
|
||||
fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
|
||||
if is_ty_param_diagnostic_item(cx, qpath, sym::Vec).is_some() {
|
||||
Some("Vec")
|
||||
} else if is_ty_param_diagnostic_item(cx, qpath, sym::String).is_some() {
|
||||
Some("String")
|
||||
} else if is_ty_param_diagnostic_item(cx, qpath, sym::HashMap).is_some() {
|
||||
Some("HashMap")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Symbol> {
|
||||
let param = qpath_generic_tys(qpath).next()?;
|
||||
let id = path_def_id(cx, param)?;
|
||||
cx.tcx
|
||||
.get_diagnostic_name(id)
|
||||
.filter(|&name| matches!(name, sym::HashMap | sym::String | sym::Vec))
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint;
|
||||
use clippy_utils::is_ty_param_diagnostic_item;
|
||||
use clippy_utils::{path_def_id, qpath_generic_tys};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{self as hir, def_id::DefId, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::symbol::sym;
|
||||
@ -7,16 +8,21 @@ use rustc_span::symbol::sym;
|
||||
use super::OPTION_OPTION;
|
||||
|
||||
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
|
||||
if cx.tcx.is_diagnostic_item(sym::Option, def_id) && is_ty_param_diagnostic_item(cx, qpath, sym::Option).is_some() {
|
||||
span_lint(
|
||||
cx,
|
||||
OPTION_OPTION,
|
||||
hir_ty.span,
|
||||
"consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
|
||||
enum if you need to distinguish all 3 cases",
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
if_chain! {
|
||||
if cx.tcx.is_diagnostic_item(sym::Option, def_id);
|
||||
if let Some(arg) = qpath_generic_tys(qpath).next();
|
||||
if path_def_id(cx, arg) == Some(def_id);
|
||||
then {
|
||||
span_lint(
|
||||
cx,
|
||||
OPTION_OPTION,
|
||||
hir_ty.span,
|
||||
"consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
|
||||
enum if you need to distinguish all 3 cases",
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::source::snippet_with_applicability;
|
||||
use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item};
|
||||
use clippy_utils::{path_def_id, qpath_generic_tys};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind};
|
||||
use rustc_lint::LateContext;
|
||||
@ -20,12 +20,17 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
|
||||
format!("Rc<{}>", alternate),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Vec) {
|
||||
} else {
|
||||
let Some(ty) = qpath_generic_tys(qpath).next() else { return false };
|
||||
let Some(id) = path_def_id(cx, ty) else { return false };
|
||||
if !cx.tcx.is_diagnostic_item(sym::Vec, id) {
|
||||
return false;
|
||||
}
|
||||
let qpath = match &ty.kind {
|
||||
TyKind::Path(qpath) => qpath,
|
||||
_ => return false,
|
||||
};
|
||||
let inner_span = match get_qpath_generic_tys(qpath).next() {
|
||||
let inner_span = match qpath_generic_tys(qpath).next() {
|
||||
Some(ty) => ty.span,
|
||||
None => return false,
|
||||
};
|
||||
@ -55,12 +60,16 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
|
||||
format!("Arc<{}>", alternate),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
} else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Vec) {
|
||||
} else if let Some(ty) = qpath_generic_tys(qpath).next() {
|
||||
let Some(id) = path_def_id(cx, ty) else { return false };
|
||||
if !cx.tcx.is_diagnostic_item(sym::Vec, id) {
|
||||
return false;
|
||||
}
|
||||
let qpath = match &ty.kind {
|
||||
TyKind::Path(qpath) => qpath,
|
||||
_ => return false,
|
||||
};
|
||||
let inner_span = match get_qpath_generic_tys(qpath).next() {
|
||||
let inner_span = match qpath_generic_tys(qpath).next() {
|
||||
Some(ty) => ty.span,
|
||||
None => return false,
|
||||
};
|
||||
@ -85,13 +94,13 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
|
||||
}
|
||||
|
||||
fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
|
||||
if is_ty_param_diagnostic_item(cx, qpath, sym::String).is_some() {
|
||||
Some("str")
|
||||
} else if is_ty_param_diagnostic_item(cx, qpath, sym::OsString).is_some() {
|
||||
Some("std::ffi::OsStr")
|
||||
} else if is_ty_param_diagnostic_item(cx, qpath, sym::PathBuf).is_some() {
|
||||
Some("std::path::Path")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
let ty = qpath_generic_tys(qpath).next()?;
|
||||
let id = path_def_id(cx, ty)?;
|
||||
let path = match cx.tcx.get_diagnostic_name(id)? {
|
||||
sym::String => "str",
|
||||
sym::OsString => "std::ffi::OsStr",
|
||||
sym::PathBuf => "std::path::Path",
|
||||
_ => return None,
|
||||
};
|
||||
Some(path)
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::is_ty_param_diagnostic_item;
|
||||
use clippy_utils::{path_def_id, qpath_generic_tys};
|
||||
use if_chain::if_chain;
|
||||
use rustc_hir::{self as hir, def_id::DefId, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
@ -10,7 +10,9 @@ use super::RC_MUTEX;
|
||||
pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
|
||||
if_chain! {
|
||||
if cx.tcx.is_diagnostic_item(sym::Rc, def_id) ;
|
||||
if let Some(_) = is_ty_param_diagnostic_item(cx, qpath, sym::Mutex) ;
|
||||
if let Some(arg) = qpath_generic_tys(qpath).next();
|
||||
if let Some(id) = path_def_id(cx, arg);
|
||||
if cx.tcx.is_diagnostic_item(sym::Mutex, id);
|
||||
then {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
|
@ -1,8 +1,8 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::source::{snippet, snippet_with_applicability};
|
||||
use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item};
|
||||
use clippy_utils::{path_def_id, qpath_generic_tys};
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{self as hir, def_id::DefId, LangItem, QPath, TyKind};
|
||||
use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
@ -39,21 +39,20 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
|
||||
return true;
|
||||
}
|
||||
|
||||
let (inner_sym, ty) = if let Some(ty) = is_ty_param_lang_item(cx, qpath, LangItem::OwnedBox) {
|
||||
("Box", ty)
|
||||
} else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Rc) {
|
||||
("Rc", ty)
|
||||
} else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Arc) {
|
||||
("Arc", ty)
|
||||
} else {
|
||||
return false;
|
||||
let Some(ty) = qpath_generic_tys(qpath).next() else { return false };
|
||||
let Some(id) = path_def_id(cx, ty) else { return false };
|
||||
let (inner_sym, ty) = match cx.tcx.get_diagnostic_name(id) {
|
||||
Some(sym::Arc) => ("Arc", ty),
|
||||
Some(sym::Rc) => ("Rc", ty),
|
||||
_ if Some(id) == cx.tcx.lang_items().owned_box() => ("Box", ty),
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let inner_qpath = match &ty.kind {
|
||||
TyKind::Path(inner_qpath) => inner_qpath,
|
||||
_ => return false,
|
||||
};
|
||||
let inner_span = match get_qpath_generic_tys(inner_qpath).next() {
|
||||
let inner_span = match qpath_generic_tys(inner_qpath).next() {
|
||||
Some(ty) => {
|
||||
// Box<Box<dyn T>> is smaller than Box<dyn T> because of wide pointers
|
||||
if matches!(ty.kind, TyKind::TraitObject(..)) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::higher;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{differing_macro_contexts, path_to_local, usage::is_potentially_mutated};
|
||||
use clippy_utils::{path_to_local, usage::is_potentially_mutated};
|
||||
use if_chain::if_chain;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
|
||||
@ -238,8 +238,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
|
||||
if let Some(unwrappable) = self.unwrappables.iter()
|
||||
.find(|u| u.local_id == id);
|
||||
// Span contexts should not differ with the conditional branch
|
||||
if !differing_macro_contexts(unwrappable.branch.span, expr.span);
|
||||
if !differing_macro_contexts(unwrappable.branch.span, unwrappable.check.span);
|
||||
let span_ctxt = expr.span.ctxt();
|
||||
if unwrappable.branch.span.ctxt() == span_ctxt;
|
||||
if unwrappable.check.span.ctxt() == span_ctxt;
|
||||
then {
|
||||
if call_to_unwrap == unwrappable.safe_to_unwrap {
|
||||
let is_entire_condition = unwrappable.is_entire_condition;
|
||||
|
@ -4,8 +4,8 @@ use clippy_utils::macros::root_macro_call_first_node;
|
||||
use clippy_utils::source::snippet;
|
||||
use clippy_utils::ty::match_type;
|
||||
use clippy_utils::{
|
||||
higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, method_calls,
|
||||
path_to_res, 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_def_path,
|
||||
method_calls, paths, peel_blocks_with_stmt, SpanlessEq,
|
||||
};
|
||||
use if_chain::if_chain;
|
||||
use rustc_ast as ast;
|
||||
@ -844,7 +844,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem {
|
||||
// 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) = path_to_res(cx, &segments[..]).opt_def_id();
|
||||
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);
|
||||
then {
|
||||
@ -917,7 +917,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
|
||||
// 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 path_to_res(cx, path) != Res::Err {
|
||||
if def_path_res(cx, path) != Res::Err {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -999,7 +999,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
|
||||
}
|
||||
|
||||
for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
|
||||
if let Some(def_id) = path_to_res(cx, module).opt_def_id() {
|
||||
if let Some(def_id) = def_path_res(cx, module).opt_def_id() {
|
||||
for item in cx.tcx.module_children(def_id).iter() {
|
||||
if_chain! {
|
||||
if let Res::Def(DefKind::Const, item_def_id) = item.res;
|
||||
|
@ -1,5 +1,4 @@
|
||||
use crate::consts::{constant_context, constant_simple};
|
||||
use crate::differing_macro_contexts;
|
||||
use crate::source::snippet_opt;
|
||||
use rustc_ast::ast::InlineAsmTemplatePiece;
|
||||
use rustc_data_structures::fx::FxHasher;
|
||||
@ -186,7 +185,7 @@ impl HirEqInterExpr<'_, '_, '_> {
|
||||
|
||||
#[allow(clippy::similar_names)]
|
||||
pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
|
||||
if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
|
||||
if !self.inner.allow_side_effects && left.span.ctxt() != right.span.ctxt() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -77,9 +77,9 @@ use rustc_hir::itemlikevisit::ItemLikeVisitor;
|
||||
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
|
||||
use rustc_hir::{
|
||||
def, lang_items, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr,
|
||||
ExprKind, FnDecl, ForeignItem, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem,
|
||||
Local, MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
|
||||
Target, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
|
||||
ExprKind, FnDecl, ForeignItem, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local,
|
||||
MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Target,
|
||||
TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
|
||||
};
|
||||
use rustc_lint::{LateContext, Level, Lint, LintContext};
|
||||
use rustc_middle::hir::place::PlaceBase;
|
||||
@ -134,13 +134,6 @@ macro_rules! extract_msrv_attr {
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns `true` if the two spans come from differing expansions (i.e., one is
|
||||
/// from a macro and one isn't).
|
||||
#[must_use]
|
||||
pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
|
||||
rhs.ctxt() != lhs.ctxt()
|
||||
}
|
||||
|
||||
/// If the given expression is a local binding, find the initializer expression.
|
||||
/// If that initializer expression is another local binding, find its initializer again.
|
||||
/// This process repeats as long as possible (but usually no more than once). Initializer
|
||||
@ -262,44 +255,6 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
|
||||
matches!(pat.kind, PatKind::Wild)
|
||||
}
|
||||
|
||||
/// Checks if the first type parameter is a lang item.
|
||||
pub fn is_ty_param_lang_item<'tcx>(
|
||||
cx: &LateContext<'_>,
|
||||
qpath: &QPath<'tcx>,
|
||||
item: LangItem,
|
||||
) -> Option<&'tcx hir::Ty<'tcx>> {
|
||||
let ty = get_qpath_generic_tys(qpath).next()?;
|
||||
|
||||
if let TyKind::Path(qpath) = &ty.kind {
|
||||
cx.qpath_res(qpath, ty.hir_id)
|
||||
.opt_def_id()
|
||||
.map_or(false, |id| {
|
||||
cx.tcx.lang_items().require(item).map_or(false, |lang_id| id == lang_id)
|
||||
})
|
||||
.then(|| ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the first type parameter is a diagnostic item.
|
||||
pub fn is_ty_param_diagnostic_item<'tcx>(
|
||||
cx: &LateContext<'_>,
|
||||
qpath: &QPath<'tcx>,
|
||||
item: Symbol,
|
||||
) -> Option<&'tcx hir::Ty<'tcx>> {
|
||||
let ty = get_qpath_generic_tys(qpath).next()?;
|
||||
|
||||
if let TyKind::Path(qpath) = &ty.kind {
|
||||
cx.qpath_res(qpath, ty.hir_id)
|
||||
.opt_def_id()
|
||||
.map_or(false, |id| cx.tcx.is_diagnostic_item(item, id))
|
||||
.then(|| ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if the method call given in `expr` belongs to the given trait.
|
||||
/// This is a deprecated function, consider using [`is_trait_method`].
|
||||
pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
|
||||
@ -360,35 +315,17 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_qpath_generics<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'tcx>> {
|
||||
match path {
|
||||
QPath::Resolved(_, p) => p.segments.last().and_then(|s| s.args),
|
||||
QPath::TypeRelative(_, s) => s.args,
|
||||
QPath::LangItem(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_qpath_generic_tys<'tcx>(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
|
||||
get_qpath_generics(path)
|
||||
.map_or([].as_ref(), |a| a.args)
|
||||
pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
|
||||
last_path_segment(qpath)
|
||||
.args
|
||||
.map_or(&[][..], |a| a.args)
|
||||
.iter()
|
||||
.filter_map(|a| {
|
||||
if let hir::GenericArg::Type(ty) = a {
|
||||
Some(ty)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
.filter_map(|a| match a {
|
||||
hir::GenericArg::Type(ty) => Some(ty),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
|
||||
match *path {
|
||||
QPath::Resolved(_, path) => path.segments.get(0),
|
||||
QPath::TypeRelative(_, seg) => Some(seg),
|
||||
QPath::LangItem(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
|
||||
/// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
|
||||
/// `QPath::Resolved.1.res.opt_def_id()`.
|
||||
@ -420,37 +357,17 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// If the expression is a path, resolve it. Otherwise, return `Res::Err`.
|
||||
pub fn expr_path_res(cx: &LateContext<'_>, expr: &Expr<'_>) -> Res {
|
||||
if let ExprKind::Path(p) = &expr.kind {
|
||||
cx.qpath_res(p, expr.hir_id)
|
||||
} else {
|
||||
Res::Err
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves the path to a `DefId` and checks if it matches the given path.
|
||||
pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool {
|
||||
cx.qpath_res(path, hir_id)
|
||||
.opt_def_id()
|
||||
.map_or(false, |id| match_def_path(cx, id, segments))
|
||||
}
|
||||
|
||||
/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
|
||||
///
|
||||
/// Please use `is_expr_diagnostic_item` if the target is a diagnostic item.
|
||||
pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
|
||||
expr_path_res(cx, expr)
|
||||
.opt_def_id()
|
||||
.map_or(false, |id| match_def_path(cx, id, segments))
|
||||
path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments))
|
||||
}
|
||||
|
||||
/// If the expression is a path, resolves it to a `DefId` and checks if it matches the given
|
||||
/// diagnostic item.
|
||||
pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
|
||||
expr_path_res(cx, expr)
|
||||
.opt_def_id()
|
||||
.map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
|
||||
path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
|
||||
}
|
||||
|
||||
/// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
|
||||
@ -497,8 +414,46 @@ pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool {
|
||||
path_to_local(expr) == Some(id)
|
||||
}
|
||||
|
||||
/// Gets the definition associated to a path.
|
||||
pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
|
||||
pub trait MaybePath<'hir> {
|
||||
fn hir_id(&self) -> HirId;
|
||||
fn qpath_opt(&self) -> Option<&QPath<'hir>>;
|
||||
}
|
||||
|
||||
macro_rules! maybe_path {
|
||||
($ty:ident, $kind:ident) => {
|
||||
impl<'hir> MaybePath<'hir> for hir::$ty<'hir> {
|
||||
fn hir_id(&self) -> HirId {
|
||||
self.hir_id
|
||||
}
|
||||
fn qpath_opt(&self) -> Option<&QPath<'hir>> {
|
||||
match &self.kind {
|
||||
hir::$kind::Path(qpath) => Some(qpath),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
maybe_path!(Expr, ExprKind);
|
||||
maybe_path!(Pat, PatKind);
|
||||
maybe_path!(Ty, TyKind);
|
||||
|
||||
/// If `maybe_path` is a path node, resolves it, otherwise returns `Res::Err`
|
||||
pub fn path_res<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Res {
|
||||
match maybe_path.qpath_opt() {
|
||||
None => Res::Err,
|
||||
Some(qpath) => cx.qpath_res(qpath, maybe_path.hir_id()),
|
||||
}
|
||||
}
|
||||
|
||||
/// If `maybe_path` is a path node which resolves to an item, retrieves the item ID
|
||||
pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Option<DefId> {
|
||||
path_res(cx, maybe_path).opt_def_id()
|
||||
}
|
||||
|
||||
/// Resolves a def path like `std::vec::Vec`.
|
||||
/// This function is expensive and should be used sparingly.
|
||||
pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
|
||||
macro_rules! try_res {
|
||||
($e:expr) => {
|
||||
match $e {
|
||||
@ -574,7 +529,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
|
||||
/// Convenience function to get the `DefId` of a trait by path.
|
||||
/// It could be a trait or trait alias.
|
||||
pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
|
||||
match path_to_res(cx, path) {
|
||||
match def_path_res(cx, path) {
|
||||
Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
|
||||
_ => None,
|
||||
}
|
||||
@ -1649,7 +1604,7 @@ pub fn match_function_call<'tcx>(
|
||||
/// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
|
||||
/// any.
|
||||
///
|
||||
/// Please use `match_any_diagnostic_items` if the targets are all diagnostic items.
|
||||
/// Please use `tcx.get_diagnostic_name` if the targets are all diagnostic items.
|
||||
pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize> {
|
||||
let search_path = cx.get_def_path(did);
|
||||
paths
|
||||
@ -1657,14 +1612,6 @@ pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]])
|
||||
.position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied()))
|
||||
}
|
||||
|
||||
/// Checks if the given `DefId` matches any of provided diagnostic items. Returns the index of
|
||||
/// matching path, if any.
|
||||
pub fn match_any_diagnostic_items(cx: &LateContext<'_>, def_id: DefId, diag_items: &[Symbol]) -> Option<usize> {
|
||||
diag_items
|
||||
.iter()
|
||||
.position(|item| cx.tcx.is_diagnostic_item(*item, def_id))
|
||||
}
|
||||
|
||||
/// Checks if the given `DefId` matches the path.
|
||||
pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool {
|
||||
// We should probably move to Symbols in Clippy as well rather than interning every time.
|
||||
@ -1817,8 +1764,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
|
||||
|
||||
match expr.kind {
|
||||
ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
|
||||
ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
|
||||
_ => false,
|
||||
_ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::query::normalize::AtExt;
|
||||
use std::iter;
|
||||
|
||||
use crate::{expr_path_res, match_def_path, must_use_attr};
|
||||
use crate::{match_def_path, must_use_attr, path_res};
|
||||
|
||||
// Checks if the given type implements copy.
|
||||
pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
@ -443,7 +443,7 @@ impl<'tcx> ExprFnSig<'tcx> {
|
||||
|
||||
/// If the expression is function like, get the signature for it.
|
||||
pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
|
||||
if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = expr_path_res(cx, expr) {
|
||||
if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) {
|
||||
Some(ExprFnSig::Sig(cx.tcx.fn_sig(id)))
|
||||
} else {
|
||||
let ty = cx.typeck_results().expr_ty_adjusted(expr).peel_refs();
|
||||
|
@ -235,7 +235,11 @@ Use the following functions to deal with macros:
|
||||
assert_eq!(in_external_macro(cx.sess(), match_span), true);
|
||||
```
|
||||
|
||||
- `differing_macro_contexts()`: returns true if the two given spans are not from the same context
|
||||
- `span.ctxt()`: the span's context represents whether it is from expansion, and if so, what expanded it
|
||||
|
||||
One thing `SpanContext` is useful for is to check if two spans are in the same context. For example,
|
||||
in `a == b`, `a` and `b` have the same context. In a `macro_rules!` with `a == $b`, `$b` is expanded to some
|
||||
expression with a different context from `a`.
|
||||
|
||||
```rust
|
||||
macro_rules! m {
|
||||
@ -252,7 +256,7 @@ Use the following functions to deal with macros:
|
||||
// These spans are not from the same context
|
||||
// x.is_some() is from inside the macro
|
||||
// x.unwrap() is from outside the macro
|
||||
assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true);
|
||||
assert_eq!(x_is_some_span.ctxt(), x_unwrap_span.ctxt());
|
||||
```
|
||||
|
||||
[TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html
|
||||
|
Loading…
Reference in New Issue
Block a user