Make use of Option/Result diagnostic items

This commit is contained in:
Philipp Hansch 2020-04-12 15:23:07 +02:00
parent 79982a2813
commit 83874d0ee7
No known key found for this signature in database
GPG Key ID: 2B4399C4BF4DCBDE
14 changed files with 45 additions and 55 deletions

View File

@ -1,5 +1,5 @@
use crate::utils::{
get_trait_def_id, implements_trait, in_macro, match_type, paths, snippet_opt, span_lint_and_sugg,
get_trait_def_id, is_type_diagnostic_item, implements_trait, in_macro, paths, snippet_opt, span_lint_and_sugg,
span_lint_and_then, SpanlessEq,
};
use if_chain::if_chain;
@ -249,7 +249,7 @@ fn simplify_not(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> Option<String> {
},
ExprKind::MethodCall(path, _, args) if args.len() == 1 => {
let type_of_receiver = cx.tables.expr_ty(&args[0]);
if !match_type(cx, type_of_receiver, &paths::OPTION) && !match_type(cx, type_of_receiver, &paths::RESULT) {
if !is_type_diagnostic_item(cx, type_of_receiver, sym!(option_type)) && !is_type_diagnostic_item(cx, type_of_receiver, sym!(result_type)) {
return None;
}
METHODS_WITH_NEGATION

View File

@ -9,7 +9,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;
use rustc_span::BytePos;
use crate::utils::{match_type, paths, snippet_opt, span_lint_and_help, LimitStack};
use crate::utils::{snippet_opt, span_lint_and_help, LimitStack, is_type_diagnostic_item};
declare_clippy_lint! {
/// **What it does:** Checks for methods with high cognitive complexity.
@ -61,7 +61,7 @@ impl CognitiveComplexity {
helper.visit_expr(expr);
let CCHelper { cc, returns } = helper;
let ret_ty = cx.tables.node_type(expr.hir_id);
let ret_adjust = if match_type(cx, ret_ty, &paths::RESULT) {
let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym!(result_type)) {
returns
} else {
#[allow(clippy::integer_division)]

View File

@ -1,4 +1,4 @@
use crate::utils::{implements_trait, is_entrypoint_fn, match_type, paths, return_ty, span_lint};
use crate::utils::{implements_trait, is_entrypoint_fn, is_type_diagnostic_item, return_ty, span_lint};
use if_chain::if_chain;
use itertools::Itertools;
use rustc_ast::ast::{AttrKind, Attribute};
@ -217,7 +217,7 @@ fn lint_for_missing_headers<'a, 'tcx>(
);
}
if !headers.errors {
if match_type(cx, return_ty(cx, hir_id), &paths::RESULT) {
if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) {
span_lint(
cx,
MISSING_ERRORS_DOC,
@ -235,7 +235,7 @@ fn lint_for_missing_headers<'a, 'tcx>(
if let ty::Opaque(_, subs) = ret_ty.kind;
if let Some(gen) = subs.types().next();
if let ty::Generator(_, subs, _) = gen.kind;
if match_type(cx, subs.as_generator().return_ty(), &paths::RESULT);
if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym!(result_type));
then {
span_lint(
cx,

View File

@ -1,10 +1,10 @@
use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT, OPTION, RESULT};
use crate::utils::{is_expn_of, match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty};
use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT};
use crate::utils::{is_expn_of, match_def_path, method_chain_args, span_lint_and_then, walk_ptrs_ty, is_type_diagnostic_item};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::map::Map;
use rustc_middle::ty::{self, Ty};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;
@ -76,7 +76,7 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
let reciever_ty = walk_ptrs_ty(self.tables.expr_ty(&arglists[0][0]));
if match_type(self.lcx, reciever_ty, &OPTION) || match_type(self.lcx, reciever_ty, &RESULT) {
if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) {
self.result.push(expr.span);
}
}
@ -124,10 +124,3 @@ fn lint_impl_body<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, impl_span: Span, impl_it
}
}
}
fn match_type(cx: &LateContext<'_, '_>, ty: Ty<'_>, path: &[&str]) -> bool {
match ty.kind {
ty::Adt(adt, _) => match_def_path(cx, adt.did, path),
_ => false,
}
}

View File

@ -1,4 +1,4 @@
use crate::utils::{match_type, method_chain_args, paths, snippet_with_applicability, span_lint_and_sugg};
use crate::utils::{is_type_diagnostic_item, method_chain_args, snippet_with_applicability, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, MatchSource, PatKind, QPath};
@ -45,8 +45,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for OkIfLet {
if let ExprKind::MethodCall(_, ok_span, ref result_types) = op.kind; //check is expr.ok() has type Result<T,E>.ok()
if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation
if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized;
let is_result_type = match_type(cx, cx.tables.expr_ty(&result_types[0]), &paths::RESULT);
if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some" && is_result_type;
if is_type_diagnostic_item(cx, cx.tables.expr_ty(&result_types[0]), sym!(result_type));
if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some";
then {
let mut applicability = Applicability::MachineApplicable;

View File

@ -1392,7 +1392,7 @@ fn check_for_loop_arg(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>, e
/// Checks for `for` loops over `Option`s and `Result`s.
fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) {
let ty = cx.tables.expr_ty(arg);
if match_type(cx, ty, &paths::OPTION) {
if is_type_diagnostic_item(cx, ty, sym!(option_type)) {
span_lint_and_help(
cx,
FOR_LOOP_OVER_OPTION,
@ -1408,7 +1408,7 @@ fn check_arg_type(cx: &LateContext<'_, '_>, pat: &Pat<'_>, arg: &Expr<'_>) {
snippet(cx, arg.span, "_")
),
);
} else if match_type(cx, ty, &paths::RESULT) {
} else if is_type_diagnostic_item(cx, ty, sym!(result_type)) {
span_lint_and_help(
cx,
FOR_LOOP_OVER_RESULT,

View File

@ -1,6 +1,6 @@
use crate::utils::paths;
use crate::utils::{
is_copy, match_trait_method, match_type, remove_blocks, snippet_with_applicability, span_lint_and_sugg,
is_copy, is_type_diagnostic_item, match_trait_method, remove_blocks, snippet_with_applicability, span_lint_and_sugg,
};
use if_chain::if_chain;
use rustc_ast::ast::Ident;
@ -52,7 +52,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MapClone {
if args.len() == 2;
if method.ident.as_str() == "map";
let ty = cx.tables.expr_ty(&args[0]);
if match_type(cx, ty, &paths::OPTION) || match_trait_method(cx, e, &paths::ITERATOR);
if is_type_diagnostic_item(cx, ty, sym!(option_type)) || match_trait_method(cx, e, &paths::ITERATOR);
if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind;
let closure_body = cx.tcx.hir().body(body_id);
let closure_expr = remove_blocks(&closure_body.value);

View File

@ -1,5 +1,4 @@
use crate::utils::paths;
use crate::utils::{iter_input_pats, match_type, method_chain_args, snippet, span_lint_and_then};
use crate::utils::{is_type_diagnostic_item, iter_input_pats, method_chain_args, snippet, span_lint_and_then};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@ -206,9 +205,9 @@ fn suggestion_msg(function_type: &str, map_type: &str) -> String {
fn lint_map_unit_fn(cx: &LateContext<'_, '_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr<'_>, map_args: &[hir::Expr<'_>]) {
let var_arg = &map_args[0];
let (map_type, variant, lint) = if match_type(cx, cx.tables.expr_ty(var_arg), &paths::OPTION) {
let (map_type, variant, lint) = if is_type_diagnostic_item(cx, cx.tables.expr_ty(var_arg), sym!(option_type)) {
("Option", "Some", OPTION_MAP_UNIT_FN)
} else if match_type(cx, cx.tables.expr_ty(var_arg), &paths::RESULT) {
} else if is_type_diagnostic_item(cx, cx.tables.expr_ty(var_arg), sym!(result_type)) {
("Result", "Ok", RESULT_MAP_UNIT_FN)
} else {
return;

View File

@ -3,7 +3,7 @@ use crate::utils::paths;
use crate::utils::sugg::Sugg;
use crate::utils::usage::is_unused;
use crate::utils::{
expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, is_wild,
expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable, is_type_diagnostic_item, is_wild,
match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet, snippet_block,
snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
walk_ptrs_ty,
@ -642,7 +642,7 @@ fn check_overlapping_arms<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ex: &'tcx Expr<'
fn check_wild_err_arm(cx: &LateContext<'_, '_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
let ex_ty = walk_ptrs_ty(cx.tables.expr_ty(ex));
if match_type(cx, ex_ty, &paths::RESULT) {
if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) {
for arm in arms {
if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind {
let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));

View File

@ -1836,9 +1836,9 @@ fn lint_expect_fun_call(
}
let receiver_type = cx.tables.expr_ty_adjusted(&args[0]);
let closure_args = if match_type(cx, receiver_type, &paths::OPTION) {
let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym!(option_type)) {
"||"
} else if match_type(cx, receiver_type, &paths::RESULT) {
} else if is_type_diagnostic_item(cx, receiver_type, sym!(result_type)) {
"|_|"
} else {
return;
@ -2067,7 +2067,7 @@ fn lint_cstring_as_ptr(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, source: &
if_chain! {
let source_type = cx.tables.expr_ty(source);
if let ty::Adt(def, substs) = source_type.kind;
if match_def_path(cx, def.did, &paths::RESULT);
if cx.tcx.is_diagnostic_item(sym!(result_type), def.did);
if match_type(cx, substs.type_at(0), &paths::CSTRING);
then {
span_lint_and_then(
@ -2395,9 +2395,9 @@ fn derefs_to_slice<'a, 'tcx>(
fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) {
let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&unwrap_args[0]));
let mess = if match_type(cx, obj_ty, &paths::OPTION) {
let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
Some((OPTION_UNWRAP_USED, "an Option", "None"))
} else if match_type(cx, obj_ty, &paths::RESULT) {
} else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) {
Some((RESULT_UNWRAP_USED, "a Result", "Err"))
} else {
None
@ -2422,9 +2422,9 @@ fn lint_unwrap(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, unwrap_args: &[hi
fn lint_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
let obj_ty = walk_ptrs_ty(cx.tables.expr_ty(&expect_args[0]));
let mess = if match_type(cx, obj_ty, &paths::OPTION) {
let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) {
Some((OPTION_EXPECT_USED, "an Option", "None"))
} else if match_type(cx, obj_ty, &paths::RESULT) {
} else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) {
Some((RESULT_EXPECT_USED, "a Result", "Err"))
} else {
None
@ -2445,7 +2445,7 @@ fn lint_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, expect_args: &[hi
fn lint_ok_expect(cx: &LateContext<'_, '_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) {
if_chain! {
// lint if the caller of `ok()` is a `Result`
if match_type(cx, cx.tables.expr_ty(&ok_args[0]), &paths::RESULT);
if is_type_diagnostic_item(cx, cx.tables.expr_ty(&ok_args[0]), sym!(result_type));
let result_type = cx.tables.expr_ty(&ok_args[0]);
if let Some(error_type) = get_error_type(cx, result_type);
if has_debug_impl(error_type, cx);
@ -2491,8 +2491,8 @@ fn lint_map_unwrap_or_else<'a, 'tcx>(
unwrap_args: &'tcx [hir::Expr<'_>],
) {
// lint if the caller of `map()` is an `Option`
let is_option = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION);
let is_result = match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::RESULT);
let is_option = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(option_type));
let is_result = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(result_type));
if is_option || is_result {
// Don't make a suggestion that may fail to compile due to mutably borrowing
@ -2559,8 +2559,8 @@ fn lint_map_or_none<'a, 'tcx>(
expr: &'tcx hir::Expr<'_>,
map_or_args: &'tcx [hir::Expr<'_>],
) {
let is_option = match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::OPTION);
let is_result = match_type(cx, cx.tables.expr_ty(&map_or_args[0]), &paths::RESULT);
let is_option = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_or_args[0]), sym!(option_type));
let is_result = is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_or_args[0]), sym!(result_type));
// There are two variants of this `map_or` lint:
// (1) using `map_or` as an adapter from `Result<T,E>` to `Option<T>`
@ -3210,7 +3210,6 @@ fn is_maybe_uninit_ty_valid(cx: &LateContext<'_, '_>, ty: Ty<'_>) -> bool {
ty::Array(ref component, _) => is_maybe_uninit_ty_valid(cx, component),
ty::Tuple(ref types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)),
ty::Adt(ref adt, _) => {
// needs to be a MaybeUninit
match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT)
},
_ => false,
@ -3326,7 +3325,7 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
/// Given a `Result<T, E>` type, return its error type (`E`).
fn get_error_type<'a>(cx: &LateContext<'_, '_>, ty: Ty<'a>) -> Option<Ty<'a>> {
match ty.kind {
ty::Adt(_, substs) if match_type(cx, ty, &paths::RESULT) => substs.types().nth(1),
ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym!(result_type)) => substs.types().nth(1),
_ => None,
}
}

View File

@ -1,5 +1,5 @@
use crate::utils::{differing_macro_contexts, paths, snippet_with_applicability, span_lint_and_then};
use crate::utils::{is_copy, match_type};
use crate::utils::{differing_macro_contexts, snippet_with_applicability, span_lint_and_then};
use crate::utils::{is_copy, is_type_diagnostic_item};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_path, NestedVisitorMap, Visitor};
@ -20,7 +20,7 @@ pub(super) fn lint<'a, 'tcx>(
map_span: Span,
) {
// lint if the caller of `map()` is an `Option`
if match_type(cx, cx.tables.expr_ty(&map_args[0]), &paths::OPTION) {
if is_type_diagnostic_item(cx, cx.tables.expr_ty(&map_args[0]), sym!(option_type)) {
if !is_copy(cx, cx.tables.expr_ty(&unwrap_args[1])) {
// Do not lint if the `map` argument uses identifiers in the `map`
// argument that are also used in the `unwrap_or` argument

View File

@ -5,10 +5,9 @@ use rustc_hir::{def, BindingAnnotation, Block, Expr, ExprKind, MatchSource, PatK
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use crate::utils::paths::{OPTION, OPTION_NONE};
use crate::utils::sugg::Sugg;
use crate::utils::{
higher, match_def_path, match_qpath, match_type, snippet_with_applicability, span_lint_and_sugg, SpanlessEq,
higher, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability, span_lint_and_sugg, SpanlessEq,
};
declare_clippy_lint! {
@ -141,7 +140,7 @@ impl QuestionMark {
fn is_option(cx: &LateContext<'_, '_>, expression: &Expr<'_>) -> bool {
let expr_ty = cx.tables.expr_ty(expression);
match_type(cx, expr_ty, &OPTION)
is_type_diagnostic_item(cx, expr_ty, sym!(option_type))
}
fn expression_returns_none(cx: &LateContext<'_, '_>, expression: &Expr<'_>) -> bool {
@ -158,7 +157,7 @@ impl QuestionMark {
if let Res::Def(DefKind::Ctor(def::CtorOf::Variant, def::CtorKind::Const), def_id) =
cx.tables.qpath_res(qp, expression.hir_id)
{
return match_def_path(cx, def_id, &OPTION_NONE);
return match_def_path(cx, def_id, &paths::OPTION_NONE);
}
false

View File

@ -420,7 +420,7 @@ impl Types {
return; // don't recurse into the type
}
}
} else if match_def_path(cx, def_id, &paths::OPTION) {
} else if cx.tcx.is_diagnostic_item(sym!(option_type), def_id) {
if match_type_parameter(cx, qpath, &paths::OPTION).is_some() {
span_lint(
cx,

View File

@ -1,4 +1,4 @@
use crate::utils::{higher::if_block, match_type, paths, span_lint_and_then, usage::is_potentially_mutated};
use crate::utils::{higher::if_block, span_lint_and_then, usage::is_potentially_mutated, is_type_diagnostic_item};
use if_chain::if_chain;
use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Path, QPath, UnOp};
@ -100,7 +100,7 @@ fn collect_unwrap_info<'a, 'tcx>(
if let ExprKind::MethodCall(method_name, _, args) = &expr.kind;
if let ExprKind::Path(QPath::Resolved(None, path)) = &args[0].kind;
let ty = cx.tables.expr_ty(&args[0]);
if match_type(cx, ty, &paths::OPTION) || match_type(cx, ty, &paths::RESULT);
if is_type_diagnostic_item(cx, ty, sym!(option_type)) || is_type_diagnostic_item(cx, ty, sym!(result_type));
let name = method_name.ident.as_str();
if ["is_some", "is_none", "is_ok", "is_err"].contains(&&*name);
then {