Merge remote-tracking branch 'upstream/master' into rustup
This commit is contained in:
commit
17b9c42572
78 changed files with 1315 additions and 428 deletions
|
|
@ -1,44 +0,0 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{is_in_cfg_test, is_in_test_function};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::EXPECT_USED;
|
||||
|
||||
/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`.
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
recv: &hir::Expr<'_>,
|
||||
is_err: bool,
|
||||
allow_expect_in_tests: bool,
|
||||
) {
|
||||
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
|
||||
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
|
||||
Some((EXPECT_USED, "an `Option`", "None", ""))
|
||||
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
|
||||
Some((EXPECT_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let method = if is_err { "expect_err" } else { "expect" };
|
||||
|
||||
if allow_expect_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some((lint, kind, none_value, none_prefix)) = mess {
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
lint,
|
||||
expr.span,
|
||||
&format!("used `{method}()` on {kind} value"),
|
||||
None,
|
||||
&format!("if this value is {none_prefix}`{none_value}`, it will panic"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,6 @@ mod collapsible_str_replace;
|
|||
mod drain_collect;
|
||||
mod err_expect;
|
||||
mod expect_fun_call;
|
||||
mod expect_used;
|
||||
mod extend_with_drain;
|
||||
mod filetype_is_file;
|
||||
mod filter_map;
|
||||
|
|
@ -105,7 +104,7 @@ mod unnecessary_lazy_eval;
|
|||
mod unnecessary_literal_unwrap;
|
||||
mod unnecessary_sort_by;
|
||||
mod unnecessary_to_owned;
|
||||
mod unwrap_used;
|
||||
mod unwrap_expect_used;
|
||||
mod useless_asref;
|
||||
mod utils;
|
||||
mod vec_resize_to_zero;
|
||||
|
|
@ -3881,6 +3880,13 @@ impl Methods {
|
|||
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
|
||||
}
|
||||
},
|
||||
("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
|
||||
&& let body = cx.tcx.hir().body(arg.body)
|
||||
&& let [param] = body.params
|
||||
&& let Some(("chars", recv, _, _, _)) = method_call(recv) =>
|
||||
{
|
||||
string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
|
||||
}
|
||||
("arg", [arg]) => {
|
||||
suspicious_command_arg_space::check(cx, recv, arg, span);
|
||||
}
|
||||
|
|
@ -3941,13 +3947,27 @@ impl Methods {
|
|||
match method_call(recv) {
|
||||
Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
|
||||
Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
|
||||
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
|
||||
_ => unwrap_expect_used::check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
false,
|
||||
self.allow_expect_in_tests,
|
||||
unwrap_expect_used::Variant::Expect,
|
||||
),
|
||||
}
|
||||
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
|
||||
},
|
||||
("expect_err", [_]) => {
|
||||
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
|
||||
expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests);
|
||||
unwrap_expect_used::check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
true,
|
||||
self.allow_expect_in_tests,
|
||||
unwrap_expect_used::Variant::Expect,
|
||||
);
|
||||
},
|
||||
("extend", [arg]) => {
|
||||
string_extend_chars::check(cx, expr, recv, arg);
|
||||
|
|
@ -3999,20 +4019,9 @@ impl Methods {
|
|||
unnecessary_join::check(cx, expr, recv, join_arg, span);
|
||||
}
|
||||
},
|
||||
("skip", [arg]) => {
|
||||
iter_skip_zero::check(cx, expr, arg);
|
||||
|
||||
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
|
||||
if let ("cloned", []) = (name2, args2) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
("last", []) => {
|
||||
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
|
||||
if let ("cloned", []) = (name2, args2) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
},
|
||||
("lock", []) => {
|
||||
|
|
@ -4060,13 +4069,6 @@ impl Methods {
|
|||
}
|
||||
}
|
||||
},
|
||||
("any", [arg]) if let ExprKind::Closure(arg) = arg.kind
|
||||
&& let body = cx.tcx.hir().body(arg.body)
|
||||
&& let [param] = body.params
|
||||
&& let Some(("chars", recv, _, _, _)) = method_call(recv) =>
|
||||
{
|
||||
string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
|
||||
}
|
||||
("nth", [n_arg]) => match method_call(recv) {
|
||||
Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
|
||||
Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, false),
|
||||
|
|
@ -4120,6 +4122,13 @@ impl Methods {
|
|||
seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span);
|
||||
}
|
||||
},
|
||||
("skip", [arg]) => {
|
||||
iter_skip_zero::check(cx, expr, arg);
|
||||
|
||||
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
}
|
||||
("sort", []) => {
|
||||
stable_sort_primitive::check(cx, expr, recv);
|
||||
},
|
||||
|
|
@ -4142,10 +4151,8 @@ impl Methods {
|
|||
},
|
||||
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
|
||||
("take", [_arg]) => {
|
||||
if let Some((name2, recv2, args2, _span2, _)) = method_call(recv) {
|
||||
if let ("cloned", []) = (name2, args2) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
|
||||
iter_overeager_cloned::check(cx, expr, recv, recv2, false, false);
|
||||
}
|
||||
},
|
||||
("take", []) => needless_option_take::check(cx, expr, recv),
|
||||
|
|
@ -4180,11 +4187,25 @@ impl Methods {
|
|||
_ => {},
|
||||
}
|
||||
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
|
||||
unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
|
||||
unwrap_expect_used::check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
false,
|
||||
self.allow_unwrap_in_tests,
|
||||
unwrap_expect_used::Variant::Unwrap,
|
||||
);
|
||||
},
|
||||
("unwrap_err", []) => {
|
||||
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
|
||||
unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests);
|
||||
unwrap_expect_used::check(
|
||||
cx,
|
||||
expr,
|
||||
recv,
|
||||
true,
|
||||
self.allow_unwrap_in_tests,
|
||||
unwrap_expect_used::Variant::Unwrap,
|
||||
);
|
||||
},
|
||||
("unwrap_or", [u_arg]) => {
|
||||
match method_call(recv) {
|
||||
|
|
@ -4214,6 +4235,9 @@ impl Methods {
|
|||
}
|
||||
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
|
||||
},
|
||||
("write", []) => {
|
||||
readonly_write_lock::check(cx, expr, recv);
|
||||
}
|
||||
("zip", [arg]) => {
|
||||
if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
|
||||
&& name.ident.name == sym::iter
|
||||
|
|
@ -4221,9 +4245,6 @@ impl Methods {
|
|||
range_zip_with_len::check(cx, expr, iter_recv, arg);
|
||||
}
|
||||
},
|
||||
("write", []) => {
|
||||
readonly_write_lock::check(cx, expr, recv);
|
||||
}
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ use if_chain::if_chain;
|
|||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Closure, Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::ty::{self, GenericArgKind};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::GenericArgKind;
|
||||
use rustc_span::sym;
|
||||
use rustc_span::symbol::Ident;
|
||||
use std::iter;
|
||||
|
|
|
|||
83
clippy_lints/src/methods/unwrap_expect_used.rs
Normal file
83
clippy_lints/src/methods/unwrap_expect_used.rs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_then;
|
||||
use clippy_utils::ty::{is_never_like, is_type_diagnostic_item};
|
||||
use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
|
||||
use rustc_hir::Expr;
|
||||
use rustc_lint::{LateContext, Lint};
|
||||
use rustc_middle::ty;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::{EXPECT_USED, UNWRAP_USED};
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub(super) enum Variant {
|
||||
Unwrap,
|
||||
Expect,
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
fn method_name(self, is_err: bool) -> &'static str {
|
||||
match (self, is_err) {
|
||||
(Variant::Unwrap, true) => "unwrap_err",
|
||||
(Variant::Unwrap, false) => "unwrap",
|
||||
(Variant::Expect, true) => "expect_err",
|
||||
(Variant::Expect, false) => "expect",
|
||||
}
|
||||
}
|
||||
|
||||
fn lint(self) -> &'static Lint {
|
||||
match self {
|
||||
Variant::Unwrap => UNWRAP_USED,
|
||||
Variant::Expect => EXPECT_USED,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lint usage of `unwrap` or `unwrap_err` for `Result` and `unwrap()` for `Option` (and their
|
||||
/// `expect` counterparts).
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &Expr<'_>,
|
||||
recv: &Expr<'_>,
|
||||
is_err: bool,
|
||||
allow_unwrap_in_tests: bool,
|
||||
variant: Variant,
|
||||
) {
|
||||
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
|
||||
let (kind, none_value, none_prefix) = if is_type_diagnostic_item(cx, ty, sym::Option) && !is_err {
|
||||
("an `Option`", "None", "")
|
||||
} else if is_type_diagnostic_item(cx, ty, sym::Result)
|
||||
&& let ty::Adt(_, substs) = ty.kind()
|
||||
&& let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type()
|
||||
{
|
||||
if is_never_like(t_or_e_ty) {
|
||||
return;
|
||||
}
|
||||
|
||||
("a `Result`", if is_err { "Ok" } else { "Err" }, "an ")
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let method_suffix = if is_err { "_err" } else { "" };
|
||||
|
||||
if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
variant.lint(),
|
||||
expr.span,
|
||||
&format!("used `{}()` on {kind} value", variant.method_name(is_err)),
|
||||
|diag| {
|
||||
diag.note(format!("if this value is {none_prefix}`{none_value}`, it will panic"));
|
||||
|
||||
if variant == Variant::Unwrap && is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
|
||||
diag.help(format!(
|
||||
"consider using `expect{method_suffix}()` to provide a better panic message"
|
||||
));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_help;
|
||||
use clippy_utils::ty::is_type_diagnostic_item;
|
||||
use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::{EXPECT_USED, UNWRAP_USED};
|
||||
|
||||
/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`.
|
||||
pub(super) fn check(
|
||||
cx: &LateContext<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
recv: &hir::Expr<'_>,
|
||||
is_err: bool,
|
||||
allow_unwrap_in_tests: bool,
|
||||
) {
|
||||
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
|
||||
|
||||
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
|
||||
Some((UNWRAP_USED, "an `Option`", "None", ""))
|
||||
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
|
||||
Some((UNWRAP_USED, "a `Result`", if is_err { "Ok" } else { "Err" }, "an "))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let method_suffix = if is_err { "_err" } else { "" };
|
||||
|
||||
if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some((lint, kind, none_value, none_prefix)) = mess {
|
||||
let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
|
||||
format!(
|
||||
"if you don't want to handle the `{none_value}` case gracefully, consider \
|
||||
using `expect{method_suffix}()` to provide a better panic message"
|
||||
)
|
||||
} else {
|
||||
format!("if this value is {none_prefix}`{none_value}`, it will panic")
|
||||
};
|
||||
|
||||
span_lint_and_help(
|
||||
cx,
|
||||
lint,
|
||||
expr.span,
|
||||
&format!("used `unwrap{method_suffix}()` on {kind} value"),
|
||||
None,
|
||||
&help,
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue