Factor out is_qpath_def_path

This commit is contained in:
Cameron Steffen
2022-01-06 12:41:17 -06:00
parent ece7fa4f9c
commit bd583d91a1
4 changed files with 44 additions and 48 deletions

View File

@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint; use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; 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_hir::{BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint}; 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::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::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e),
ExprKind::Call(path, _) => { ExprKind::Call(path, _) => path_def_id(cx, path)
if let ExprKind::Path(ref qpath) = path.kind { .map_or(false, |id| match_def_path(cx, id, &paths::ITER_REPEAT))
is_qpath_def_path(cx, qpath, path.hir_id, &paths::ITER_REPEAT).into() .into(),
} else {
Finite
}
},
ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(), ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(),
_ => Finite, _ => Finite,
} }

View File

@@ -1765,22 +1765,22 @@ where
mod redundant_pattern_match { mod redundant_pattern_match {
use super::REDUNDANT_PATTERN_MATCHING; use super::REDUNDANT_PATTERN_MATCHING;
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher;
use clippy_utils::source::snippet; use clippy_utils::source::snippet;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type}; 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 if_chain::if_chain;
use rustc_ast::ast::LitKind; use rustc_ast::ast::LitKind;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk}; use rustc_hir::LangItem::{OptionNone, PollPending};
use rustc_hir::{ use rustc_hir::{
intravisit::{walk_expr, Visitor}, intravisit::{walk_expr, Visitor},
Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath, UnOp, Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath, UnOp,
}; };
use rustc_lint::LateContext; 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; use rustc_span::sym;
pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
@@ -1956,28 +1956,31 @@ mod redundant_pattern_match {
has_else: bool, has_else: bool,
) { ) {
// also look inside refs // 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 we have &None for example, peel it so we can detect "if let None = x"
if let PatKind::Ref(inner, _mutability) = kind { let check_pat = match let_pat.kind {
kind = &inner.kind; PatKind::Ref(inner, _mutability) => inner,
} _ => let_pat,
};
let op_ty = cx.typeck_results().expr_ty(let_expr); let op_ty = cx.typeck_results().expr_ty(let_expr);
// Determine which function should be used, and the type contained by the corresponding // Determine which function should be used, and the type contained by the corresponding
// variant. // variant.
let (good_method, inner_ty) = match kind { let (good_method, inner_ty) = match check_pat.kind {
PatKind::TupleStruct(ref path, [sub_pat], _) => { PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
if let PatKind::Wild = sub_pat.kind { 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)) ("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)) ("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) ("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) ("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) ("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) ("is_ipv6()", op_ty)
} else { } else {
return; return;
@@ -2177,13 +2180,18 @@ mod redundant_pattern_match {
should_be_left: &'a str, should_be_left: &'a str,
should_be_right: &'a str, should_be_right: &'a str,
) -> Option<&'a str> { ) -> Option<&'a str> {
let body_node_pair = if is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_left) let left_id = cx
&& is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_right) .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) (&(*arms[0].body).kind, &(*arms[1].body).kind)
} else if is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_left) } else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) {
&& is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_right)
{
(&(*arms[1].body).kind, &(*arms[0].body).kind) (&(*arms[1].body).kind, &(*arms[0].body).kind)
} else { } else {
return None; return None;

View File

@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg; 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::source::snippet_with_applicability;
use clippy_utils::{match_def_path, path_def_id};
use if_chain::if_chain; use if_chain::if_chain;
use rustc_ast::ast; use rustc_ast::ast;
use rustc_errors::Applicability; 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(); let ty_str = ty.to_string();
// `std::T::MAX` `std::T::MIN` constants // `std::T::MAX` `std::T::MIN` constants
if let hir::ExprKind::Path(path) = &expr.kind { if let Some(id) = path_def_id(cx, expr) {
if is_qpath_def_path(cx, path, expr.hir_id, &["core", &ty_str, "MAX"][..]) { if match_def_path(cx, id, &["core", &ty_str, "MAX"]) {
return Some(MinMax::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); return Some(MinMax::Min);
} }
} }

View File

@@ -357,13 +357,6 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
} }
} }
/// 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. /// 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. /// Please use `is_expr_diagnostic_item` if the target is a diagnostic item.
@@ -1775,8 +1768,7 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
match expr.kind { match expr.kind {
ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)), 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), _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)),
_ => false,
} }
} }