Auto merge of #8802 - smoelius:allow-expect-unwrap-in-tests, r=llogiq

Optionally allow `expect` and `unwrap` in tests

This addresses #1015, except it makes the new behavior optional.

The reason for the msrv-related changes is as follows.

Rather than expand `check_methods` list of arguments, it seemed easier to make `check_methods` a method of `Methods`, so that `check_methods` could access `Methods`' fields.

`check_methods` had an `msrv` parameter, which I consequently made a field of `Methods`. But, to avoid adding a lifetime parameter to `Methods`, I made the field type `Option<RustcVersion>` instead of the parameter's existing type, `Option<&RustcVersion>`. This seemed sensible since `RustcVersion` implements `Copy`. But this broke a lot of code that expected an `Option<&RustcVersion>` or `&Option<RustcVersion>`. I changed all of those occurrences to `Option<RustcVersion>`. IMHO, the code is better as a result of these changes, though.

The msrv-related changes are in their own commit to (hopefully) ease review.

Closes #1015

changelog: optionally allow `expect` and `unwrap` in tests

r? `@llogiq`
This commit is contained in:
bors 2022-05-08 15:00:30 +00:00
commit 4667198d4f
47 changed files with 614 additions and 254 deletions

View File

@ -87,9 +87,7 @@ impl ApproxConstant {
let s = s.as_str(); let s = s.as_str();
if s.parse::<f64>().is_ok() { if s.parse::<f64>().is_ok() {
for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
if is_approx_const(constant, s, min_digits) if is_approx_const(constant, s, min_digits) && msrv.map_or(true, |msrv| meets_msrv(self.msrv, msrv)) {
&& msrv.as_ref().map_or(true, |msrv| meets_msrv(self.msrv.as_ref(), msrv))
{
span_lint_and_help( span_lint_and_help(
cx, cx,
APPROX_CONSTANT, APPROX_CONSTANT,

View File

@ -613,7 +613,7 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It
fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option<RustcVersion>) { fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: Option<RustcVersion>) {
if_chain! { if_chain! {
if meets_msrv(msrv.as_ref(), &msrvs::TOOL_ATTRIBUTES); if meets_msrv(msrv, msrvs::TOOL_ATTRIBUTES);
// check cfg_attr // check cfg_attr
if attr.has_name(sym::cfg_attr); if attr.has_name(sym::cfg_attr);
if let Some(items) = attr.meta_item_list(); if let Some(items) = attr.meta_item_list();

View File

@ -57,7 +57,7 @@ impl BorrowAsPtr {
impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr { impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::BORROW_AS_PTR) { if !meets_msrv(self.msrv, msrvs::BORROW_AS_PTR) {
return; return;
} }

View File

@ -16,10 +16,10 @@ pub(super) fn check(
cast_expr: &Expr<'_>, cast_expr: &Expr<'_>,
cast_from: Ty<'_>, cast_from: Ty<'_>,
cast_to: Ty<'_>, cast_to: Ty<'_>,
msrv: &Option<RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if_chain! { if_chain! {
if meets_msrv(msrv.as_ref(), &msrvs::UNSIGNED_ABS); if meets_msrv(msrv, msrvs::UNSIGNED_ABS);
if cast_from.is_integral(); if cast_from.is_integral();
if cast_to.is_integral(); if cast_to.is_integral();
if cast_from.is_signed(); if cast_from.is_signed();

View File

@ -16,7 +16,7 @@ pub(super) fn check(
cast_op: &Expr<'_>, cast_op: &Expr<'_>,
cast_from: Ty<'_>, cast_from: Ty<'_>,
cast_to: Ty<'_>, cast_to: Ty<'_>,
msrv: &Option<RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if !should_lint(cx, expr, cast_from, cast_to, msrv) { if !should_lint(cx, expr, cast_from, cast_to, msrv) {
return; return;
@ -68,7 +68,7 @@ fn should_lint(
expr: &Expr<'_>, expr: &Expr<'_>,
cast_from: Ty<'_>, cast_from: Ty<'_>,
cast_to: Ty<'_>, cast_to: Ty<'_>,
msrv: &Option<RustcVersion>, msrv: Option<RustcVersion>,
) -> bool { ) -> bool {
// Do not suggest using From in consts/statics until it is valid to do so (see #2267). // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
if in_constant(cx, expr.hir_id) { if in_constant(cx, expr.hir_id) {
@ -95,7 +95,7 @@ fn should_lint(
}; };
!is_isize_or_usize(cast_from) && from_nbits < to_nbits !is_isize_or_usize(cast_from) && from_nbits < to_nbits
}, },
(false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv.as_ref(), &msrvs::FROM_BOOL) => true, (false, true) if matches!(cast_from.kind(), ty::Bool) && meets_msrv(msrv, msrvs::FROM_BOOL) => true,
(_, _) => { (_, _) => {
matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)) matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
}, },

View File

@ -8,9 +8,9 @@ use rustc_semver::RustcVersion;
use super::CAST_SLICE_DIFFERENT_SIZES; use super::CAST_SLICE_DIFFERENT_SIZES;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Option<RustcVersion>) { pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Option<RustcVersion>) {
// suggestion is invalid if `ptr::slice_from_raw_parts` does not exist // suggestion is invalid if `ptr::slice_from_raw_parts` does not exist
if !meets_msrv(msrv.as_ref(), &msrvs::PTR_SLICE_RAW_PARTS) { if !meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS) {
return; return;
} }

View File

@ -532,7 +532,7 @@ impl_lint_pass!(Casts => [
impl<'tcx> LateLintPass<'tcx> for Casts { impl<'tcx> LateLintPass<'tcx> for Casts {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !in_external_macro(cx.sess(), expr.span) { if !in_external_macro(cx.sess(), expr.span) {
ptr_as_ptr::check(cx, expr, &self.msrv); ptr_as_ptr::check(cx, expr, self.msrv);
} }
if expr.span.from_expansion() { if expr.span.from_expansion() {
@ -562,9 +562,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_possible_wrap::check(cx, expr, cast_from, cast_to);
cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to);
cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to); cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
} }
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, self.msrv);
cast_enum_constructor::check(cx, expr, cast_expr, cast_from); cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
} }
} }
@ -572,8 +572,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
cast_ref_to_mut::check(cx, expr); cast_ref_to_mut::check(cx, expr);
cast_ptr_alignment::check(cx, expr); cast_ptr_alignment::check(cx, expr);
char_lit_as_u8::check(cx, expr); char_lit_as_u8::check(cx, expr);
ptr_as_ptr::check(cx, expr, &self.msrv); ptr_as_ptr::check(cx, expr, self.msrv);
cast_slice_different_sizes::check(cx, expr, &self.msrv); cast_slice_different_sizes::check(cx, expr, self.msrv);
} }
extract_msrv_attr!(LateContext); extract_msrv_attr!(LateContext);

View File

@ -12,8 +12,8 @@ use rustc_semver::RustcVersion;
use super::PTR_AS_PTR; use super::PTR_AS_PTR;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVersion>) { pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Option<RustcVersion>) {
if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) { if !meets_msrv(msrv, msrvs::POINTER_CAST) {
return; return;
} }

View File

@ -57,7 +57,7 @@ impl_lint_pass!(CheckedConversions => [CHECKED_CONVERSIONS]);
impl<'tcx> LateLintPass<'tcx> for CheckedConversions { impl<'tcx> LateLintPass<'tcx> for CheckedConversions {
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::TRY_FROM) { if !meets_msrv(self.msrv, msrvs::TRY_FROM) {
return; return;
} }

View File

@ -55,7 +55,7 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
impl<'tcx> LateLintPass<'tcx> for FromOverInto { impl<'tcx> LateLintPass<'tcx> for FromOverInto {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::RE_REBALANCING_COHERENCE) { if !meets_msrv(self.msrv, msrvs::RE_REBALANCING_COHERENCE) {
return; return;
} }

View File

@ -57,7 +57,7 @@ impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::BOOL_THEN) { if !meets_msrv(self.msrv, msrvs::BOOL_THEN) {
return; return;
} }

View File

@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some(); if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some();
if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr); if let Some(IfLet {let_pat, if_then, ..}) = IfLet::hir(cx, expr);
if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id); if !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id);
if meets_msrv(self.msrv.as_ref(), &msrvs::SLICE_PATTERNS); if meets_msrv(self.msrv, msrvs::SLICE_PATTERNS);
let found_slices = find_slice_values(cx, let_pat); let found_slices = find_slice_values(cx, let_pat);
if !found_slices.is_empty(); if !found_slices.is_empty();

View File

@ -582,8 +582,17 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
}); });
let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
let allow_expect_in_tests = conf.allow_expect_in_tests;
let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv))); store.register_late_pass(move || Box::new(approx_const::ApproxConstant::new(msrv)));
store.register_late_pass(move || Box::new(methods::Methods::new(avoid_breaking_exported_api, msrv))); store.register_late_pass(move || {
Box::new(methods::Methods::new(
avoid_breaking_exported_api,
msrv,
allow_expect_in_tests,
allow_unwrap_in_tests,
))
});
store.register_late_pass(move || Box::new(matches::Matches::new(msrv))); store.register_late_pass(move || Box::new(matches::Matches::new(msrv)));
store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv))); store.register_early_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveStruct::new(msrv)));
store.register_late_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv))); store.register_late_pass(move || Box::new(manual_non_exhaustive::ManualNonExhaustiveEnum::new(msrv)));

View File

@ -48,7 +48,7 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]);
impl<'tcx> LateLintPass<'tcx> for ManualBits { impl<'tcx> LateLintPass<'tcx> for ManualBits {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::MANUAL_BITS) { if !meets_msrv(self.msrv, msrvs::MANUAL_BITS) {
return; return;
} }

View File

@ -98,7 +98,7 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]);
impl EarlyLintPass for ManualNonExhaustiveStruct { impl EarlyLintPass for ManualNonExhaustiveStruct {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) { if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) {
return; return;
} }
@ -150,7 +150,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::NON_EXHAUSTIVE) { if !meets_msrv(self.msrv, msrvs::NON_EXHAUSTIVE) {
return; return;
} }

View File

@ -68,7 +68,7 @@ enum StripKind {
impl<'tcx> LateLintPass<'tcx> for ManualStrip { impl<'tcx> LateLintPass<'tcx> for ManualStrip {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) { if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) {
return; return;
} }

View File

@ -144,7 +144,7 @@ impl MapClone {
fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) {
let mut applicability = Applicability::MachineApplicable; let mut applicability = Applicability::MachineApplicable;
let (message, sugg_method) = if is_copy && meets_msrv(self.msrv.as_ref(), &msrvs::ITERATOR_COPIED) { let (message, sugg_method) = if is_copy && meets_msrv(self.msrv, msrvs::ITERATOR_COPIED) {
("you are using an explicit closure for copying elements", "copied") ("you are using an explicit closure for copying elements", "copied")
} else { } else {
("you are using an explicit closure for cloning elements", "cloned") ("you are using an explicit closure for cloning elements", "cloned")

View File

@ -658,7 +658,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
} }
if !contains_cfg_arm(cx, expr, ex, arms) { if !contains_cfg_arm(cx, expr, ex, arms) {
if source == MatchSource::Normal { if source == MatchSource::Normal {
if !(meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) if !(meets_msrv(self.msrv, msrvs::MATCHES_MACRO)
&& match_like_matches::check_match(cx, expr, ex, arms)) && match_like_matches::check_match(cx, expr, ex, arms))
{ {
match_same_arms::check(cx, arms); match_same_arms::check(cx, arms);
@ -685,7 +685,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
match_wild_err_arm::check(cx, ex, arms); match_wild_err_arm::check(cx, ex, arms);
wild_in_or_pats::check(cx, arms); wild_in_or_pats::check(cx, arms);
} else { } else {
if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) { if meets_msrv(self.msrv, msrvs::MATCHES_MACRO) {
match_like_matches::check(cx, expr); match_like_matches::check(cx, expr);
} }
redundant_pattern_match::check(cx, expr); redundant_pattern_match::check(cx, expr);

View File

@ -254,7 +254,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
then { then {
check_replace_option_with_none(cx, src, dest, expr.span); check_replace_option_with_none(cx, src, dest, expr.span);
check_replace_with_uninit(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span);
if meets_msrv(self.msrv.as_ref(), &msrvs::MEM_TAKE) { if meets_msrv(self.msrv, msrvs::MEM_TAKE) {
check_replace_with_default(cx, src, dest, expr.span); check_replace_with_default(cx, src, dest, expr.span);
} }
} }

View File

@ -10,16 +10,16 @@ use rustc_span::{sym, Span};
use super::CLONED_INSTEAD_OF_COPIED; use super::CLONED_INSTEAD_OF_COPIED;
pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<&RustcVersion>) { pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Option<RustcVersion>) {
let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); let recv_ty = cx.typeck_results().expr_ty_adjusted(recv);
let inner_ty = match recv_ty.kind() { let inner_ty = match recv_ty.kind() {
// `Option<T>` -> `T` // `Option<T>` -> `T`
ty::Adt(adt, subst) ty::Adt(adt, subst)
if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, &msrvs::OPTION_COPIED) => if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && meets_msrv(msrv, msrvs::OPTION_COPIED) =>
{ {
subst.type_at(0) subst.type_at(0)
}, },
_ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) => { _ if is_trait_method(cx, expr, sym::Iterator) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) => {
match get_iterator_item_ty(cx, recv_ty) { match get_iterator_item_ty(cx, recv_ty) {
// <T as Iterator>::Item // <T as Iterator>::Item
Some(ty) => ty, Some(ty) => ty,

View File

@ -13,7 +13,7 @@ pub(super) fn check(
cx: &LateContext<'_>, cx: &LateContext<'_>,
_expr: &rustc_hir::Expr<'_>, _expr: &rustc_hir::Expr<'_>,
recv: &rustc_hir::Expr<'_>, recv: &rustc_hir::Expr<'_>,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
expect_span: Span, expect_span: Span,
err_span: Span, err_span: Span,
) { ) {
@ -21,7 +21,7 @@ pub(super) fn check(
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
// Test the version to make sure the lint can be showed (expect_err has been // Test the version to make sure the lint can be showed (expect_err has been
// introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982) // introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982)
if meets_msrv(msrv, &msrvs::EXPECT_ERR); if meets_msrv(msrv, msrvs::EXPECT_ERR);
// Grabs the `Result<T, E>` type // Grabs the `Result<T, E>` type
let result_type = cx.typeck_results().expr_ty(recv); let result_type = cx.typeck_results().expr_ty(recv);

View File

@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_in_test_function;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
@ -7,7 +8,7 @@ use rustc_span::sym;
use super::EXPECT_USED; use super::EXPECT_USED;
/// lint use of `expect()` for `Option`s and `Result`s /// lint use of `expect()` for `Option`s and `Result`s
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_expect_in_tests: bool) {
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
@ -18,6 +19,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
None None
}; };
if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
return;
}
if let Some((lint, kind, none_value)) = mess { if let Some((lint, kind, none_value)) = mess {
span_lint_and_help( span_lint_and_help(
cx, cx,

View File

@ -14,10 +14,10 @@ pub(super) fn check<'tcx>(
expr: &'tcx hir::Expr<'_>, expr: &'tcx hir::Expr<'_>,
recv: &'tcx hir::Expr<'_>, recv: &'tcx hir::Expr<'_>,
arg: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if is_trait_method(cx, expr, sym::Iterator) { if is_trait_method(cx, expr, sym::Iterator) {
if !meets_msrv(msrv, &msrvs::ITERATOR_FIND_MAP) { if !meets_msrv(msrv, msrvs::ITERATOR_FIND_MAP) {
return; return;
} }

View File

@ -15,9 +15,9 @@ pub(super) fn check<'tcx>(
expr: &'tcx Expr<'_>, expr: &'tcx Expr<'_>,
self_arg: &'tcx Expr<'_>, self_arg: &'tcx Expr<'_>,
radix: &'tcx Expr<'_>, radix: &'tcx Expr<'_>,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if !meets_msrv(msrv, &msrvs::IS_ASCII_DIGIT) { if !meets_msrv(msrv, msrvs::IS_ASCII_DIGIT) {
return; return;
} }

View File

@ -19,13 +19,13 @@ pub(super) fn check<'tcx>(
recv: &'tcx hir::Expr<'_>, recv: &'tcx hir::Expr<'_>,
map_arg: &'tcx hir::Expr<'_>, map_arg: &'tcx hir::Expr<'_>,
unwrap_arg: &'tcx hir::Expr<'_>, unwrap_arg: &'tcx hir::Expr<'_>,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) -> bool { ) -> bool {
// lint if the caller of `map()` is an `Option` // lint if the caller of `map()` is an `Option`
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
if is_result && !meets_msrv(msrv, &msrvs::RESULT_MAP_OR_ELSE) { if is_result && !meets_msrv(msrv, msrvs::RESULT_MAP_OR_ELSE) {
return false; return false;
} }

View File

@ -2200,14 +2200,23 @@ declare_clippy_lint! {
pub struct Methods { pub struct Methods {
avoid_breaking_exported_api: bool, avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>, msrv: Option<RustcVersion>,
allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool,
} }
impl Methods { impl Methods {
#[must_use] #[must_use]
pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self { pub fn new(
avoid_breaking_exported_api: bool,
msrv: Option<RustcVersion>,
allow_expect_in_tests: bool,
allow_unwrap_in_tests: bool,
) -> Self {
Self { Self {
avoid_breaking_exported_api, avoid_breaking_exported_api,
msrv, msrv,
allow_expect_in_tests,
allow_unwrap_in_tests,
} }
} }
} }
@ -2306,7 +2315,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
return; return;
} }
check_methods(cx, expr, self.msrv.as_ref()); self.check_methods(cx, expr);
match expr.kind { match expr.kind {
hir::ExprKind::Call(func, args) => { hir::ExprKind::Call(func, args) => {
@ -2322,7 +2331,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
single_char_add_str::check(cx, expr, args); single_char_add_str::check(cx, expr, args);
into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args); into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, args);
single_char_pattern::check(cx, expr, method_call.ident.name, args); single_char_pattern::check(cx, expr, method_call.ident.name, args);
unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv.as_ref()); unnecessary_to_owned::check(cx, expr, method_call.ident.name, args, self.msrv);
}, },
hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { hir::ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => {
let mut info = BinaryExprInfo { let mut info = BinaryExprInfo {
@ -2505,196 +2514,201 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
extract_msrv_attr!(LateContext); extract_msrv_attr!(LateContext);
} }
#[allow(clippy::too_many_lines)] impl Methods {
fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) { #[allow(clippy::too_many_lines)]
if let Some((name, [recv, args @ ..], span)) = method_call(expr) { fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
match (name, args) { if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => { match (name, args) {
zst_offset::check(cx, expr, recv); ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
}, zst_offset::check(cx, expr, recv);
("and_then", [arg]) => {
let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
if !biom_option_linted && !biom_result_linted {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
}
},
("as_deref" | "as_deref_mut", []) => {
needless_option_as_deref::check(cx, expr, recv, name);
},
("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
("collect", []) => match method_call(recv) {
Some((name @ ("cloned" | "copied"), [recv2], _)) => {
iter_cloned_collect::check(cx, name, expr, recv2);
}, },
Some(("map", [m_recv, m_arg], _)) => { ("and_then", [arg]) => {
map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv); let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
}, let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
Some(("take", [take_self_arg, take_arg], _)) => { if !biom_option_linted && !biom_result_linted {
if meets_msrv(msrv, &msrvs::STR_REPEAT) { unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
} }
}, },
_ => {}, ("as_deref" | "as_deref_mut", []) => {
}, needless_option_as_deref::check(cx, expr, recv, name);
(name @ "count", args @ []) => match method_call(recv) {
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
iter_count::check(cx, expr, recv2, name2);
}, },
Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg), ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
_ => {}, ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
}, ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
("drain", [arg]) => { ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv),
iter_with_drain::check(cx, expr, recv, span, arg); ("collect", []) => match method_call(recv) {
}, Some((name @ ("cloned" | "copied"), [recv2], _)) => {
("expect", [_]) => match method_call(recv) { iter_cloned_collect::check(cx, name, expr, recv2);
Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, msrv, span, err_span),
_ => expect_used::check(cx, expr, recv),
},
("extend", [arg]) => {
string_extend_chars::check(cx, expr, recv, arg);
extend_with_drain::check(cx, expr, recv, arg);
},
("filter_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
filter_map_identity::check(cx, expr, arg, span);
},
("find_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
},
("flat_map", [arg]) => {
flat_map_identity::check(cx, expr, arg, span);
flat_map_option::check(cx, expr, arg, span);
},
(name @ "flatten", args @ []) => match method_call(recv) {
Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
_ => {},
},
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
("for_each", [_]) => {
if let Some(("inspect", [_, _], span2)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
}
},
("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
("is_file", []) => filetype_is_file::check(cx, expr, recv),
("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, msrv),
("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
("join", [join_arg]) => {
if let Some(("collect", _, span)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span);
}
},
("last", args @ []) | ("skip", args @ [_]) => {
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv2, name, args);
}
}
},
(name @ ("map" | "map_err"), [m_arg]) => {
if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
match (name, args) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
("filter", [f_arg]) => {
filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
},
("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
_ => {},
}
}
map_identity::check(cx, expr, recv, m_arg, name, span);
},
("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
(name @ "next", args @ []) => {
if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, msrv),
("iter", []) => iter_next_slice::check(cx, expr, recv2),
("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
("skip_while", [_]) => skip_while_next::check(cx, expr),
_ => {},
}
}
},
("nth", args @ [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, recv2, name, args),
Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
},
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
("or_else", [arg]) => {
if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
}
},
("splitn" | "rsplitn", [count_arg, pat_arg]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
str_splitn::check(cx, name, expr, recv, pat_arg, count, msrv);
}
},
("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
}
},
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", args @ [_arg]) => {
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv2, name, args);
}
}
},
("take", []) => needless_option_take::check(cx, expr, recv),
("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
implicit_clone::check(cx, name, expr, recv);
},
("unwrap", []) => {
match method_call(recv) {
Some(("get", [recv, get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, false);
}, },
Some(("get_mut", [recv, get_arg], _)) => { Some(("map", [m_recv, m_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true); map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
}, },
Some(("or", [recv, or_arg], or_span)) => { Some(("take", [take_self_arg, take_arg], _)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span); if meets_msrv(self.msrv, msrvs::STR_REPEAT) {
manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
}
}, },
_ => {}, _ => {},
}
unwrap_used::check(cx, expr, recv);
},
("unwrap_or", [u_arg]) => match method_call(recv) {
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
}, },
Some(("map", [m_recv, m_arg], span)) => { (name @ "count", args @ []) => match method_call(recv) {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
iter_count::check(cx, expr, recv2, name2);
},
Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
_ => {},
},
("drain", [arg]) => {
iter_with_drain::check(cx, expr, recv, span, arg);
},
("expect", [_]) => match method_call(recv) {
Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
_ => expect_used::check(cx, expr, recv, self.allow_expect_in_tests),
},
("extend", [arg]) => {
string_extend_chars::check(cx, expr, recv, arg);
extend_with_drain::check(cx, expr, recv, arg);
},
("filter_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
filter_map_identity::check(cx, expr, arg, span);
},
("find_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
},
("flat_map", [arg]) => {
flat_map_identity::check(cx, expr, arg, span);
flat_map_option::check(cx, expr, arg, span);
},
(name @ "flatten", args @ []) => match method_call(recv) {
Some(("map", [recv, map_arg], map_span)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
_ => {},
},
("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
("for_each", [_]) => {
if let Some(("inspect", [_, _], span2)) = method_call(recv) {
inspect_for_each::check(cx, expr, span2);
}
},
("get_or_insert_with", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "get_or_insert"),
("is_file", []) => filetype_is_file::check(cx, expr, recv),
("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv),
("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
("join", [join_arg]) => {
if let Some(("collect", _, span)) = method_call(recv) {
unnecessary_join::check(cx, expr, recv, join_arg, span);
}
},
("last", args @ []) | ("skip", args @ [_]) => {
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv2, name, args);
}
}
},
(name @ ("map" | "map_err"), [m_arg]) => {
if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
match (name, args) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv),
("filter", [f_arg]) => {
filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
},
("find", [f_arg]) => {
filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true);
},
_ => {},
}
}
map_identity::check(cx, expr, recv, m_arg, name, span);
},
("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
(name @ "next", args @ []) => {
if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
match (name2, args2) {
("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv),
("iter", []) => iter_next_slice::check(cx, expr, recv2),
("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
("skip_while", [_]) => skip_while_next::check(cx, expr),
_ => {},
}
}
},
("nth", args @ [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, recv2, name, args),
Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
},
("ok_or_else", [arg]) => unnecessary_lazy_eval::check(cx, expr, recv, arg, "ok_or"),
("or_else", [arg]) => {
if !bind_instead_of_map::ResultOrElseErrInfo::check(cx, expr, recv, arg) {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
}
},
("splitn" | "rsplitn", [count_arg, pat_arg]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv);
}
},
("splitn_mut" | "rsplitn_mut", [count_arg, _]) => {
if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) {
suspicious_splitn::check(cx, name, expr, recv, count);
}
},
("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
("take", args @ [_arg]) => {
if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
if let ("cloned", []) = (name2, args2) {
iter_overeager_cloned::check(cx, expr, recv2, name, args);
}
}
},
("take", []) => needless_option_take::check(cx, expr, recv),
("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
implicit_clone::check(cx, name, expr, recv);
},
("unwrap", []) => {
match method_call(recv) {
Some(("get", [recv, get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, false);
},
Some(("get_mut", [recv, get_arg], _)) => {
get_unwrap::check(cx, expr, recv, get_arg, true);
},
Some(("or", [recv, or_arg], or_span)) => {
or_then_unwrap::check(cx, expr, recv, or_arg, or_span);
},
_ => {},
}
unwrap_used::check(cx, expr, recv, self.allow_unwrap_in_tests);
},
("unwrap_or", [u_arg]) => match method_call(recv) {
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
},
Some(("map", [m_recv, m_arg], span)) => {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
},
_ => {},
},
("unwrap_or_else", [u_arg]) => match method_call(recv) {
Some(("map", [recv, map_arg], _))
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
_ => {
unwrap_or_else_default::check(cx, expr, recv, u_arg);
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
},
}, },
_ => {}, _ => {},
}, }
("unwrap_or_else", [u_arg]) => match method_call(recv) {
Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
_ => {
unwrap_or_else_default::check(cx, expr, recv, u_arg);
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
},
},
_ => {},
} }
} }
} }

View File

@ -19,9 +19,9 @@ pub(super) fn check<'tcx>(
as_ref_recv: &hir::Expr<'_>, as_ref_recv: &hir::Expr<'_>,
map_arg: &hir::Expr<'_>, map_arg: &hir::Expr<'_>,
is_mut: bool, is_mut: bool,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if !meets_msrv(msrv, &msrvs::OPTION_AS_DEREF) { if !meets_msrv(msrv, msrvs::OPTION_AS_DEREF) {
return; return;
} }

View File

@ -24,7 +24,7 @@ pub(super) fn check(
self_arg: &Expr<'_>, self_arg: &Expr<'_>,
pat_arg: &Expr<'_>, pat_arg: &Expr<'_>,
count: u128, count: u128,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() {
return; return;
@ -34,7 +34,7 @@ pub(super) fn check(
IterUsageKind::Nth(n) => count > n + 1, IterUsageKind::Nth(n) => count > n + 1,
IterUsageKind::NextTuple => count > 2, IterUsageKind::NextTuple => count > 2,
}; };
let manual = count == 2 && meets_msrv(msrv, &msrvs::STR_SPLIT_ONCE); let manual = count == 2 && meets_msrv(msrv, msrvs::STR_SPLIT_ONCE);
match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) { match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir().parent_iter(expr.hir_id)) {
Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg), Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg),

View File

@ -26,7 +26,7 @@ pub fn check<'tcx>(
expr: &'tcx Expr<'tcx>, expr: &'tcx Expr<'tcx>,
method_name: Symbol, method_name: Symbol,
args: &'tcx [Expr<'tcx>], args: &'tcx [Expr<'tcx>],
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) { ) {
if_chain! { if_chain! {
if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
@ -198,7 +198,7 @@ fn check_into_iter_call_arg(
expr: &Expr<'_>, expr: &Expr<'_>,
method_name: Symbol, method_name: Symbol,
receiver: &Expr<'_>, receiver: &Expr<'_>,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) -> bool { ) -> bool {
if_chain! { if_chain! {
if let Some(parent) = get_parent_expr(cx, expr); if let Some(parent) = get_parent_expr(cx, expr);
@ -213,7 +213,7 @@ fn check_into_iter_call_arg(
if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) { if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver, true) {
return true; return true;
} }
let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, &msrvs::ITERATOR_COPIED) { let cloned_or_copied = if is_copy(cx, item_ty) && meets_msrv(msrv, msrvs::ITERATOR_COPIED) {
"copied" "copied"
} else { } else {
"cloned" "cloned"

View File

@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_in_test_function;
use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::ty::is_type_diagnostic_item;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint::LateContext; use rustc_lint::LateContext;
@ -7,7 +8,7 @@ use rustc_span::sym;
use super::UNWRAP_USED; use super::UNWRAP_USED;
/// lint use of `unwrap()` for `Option`s and `Result`s /// lint use of `unwrap()` for `Option`s and `Result`s
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) {
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
@ -18,6 +19,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
None None
}; };
if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
return;
}
if let Some((lint, kind, none_value)) = mess { if let Some((lint, kind, none_value)) = mess {
span_lint_and_help( span_lint_and_help(
cx, cx,

View File

@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
span: Span, span: Span,
hir_id: HirId, hir_id: HirId,
) { ) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::CONST_IF_MATCH) { if !meets_msrv(self.msrv, msrvs::CONST_IF_MATCH) {
return; return;
} }
@ -146,7 +146,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
let mir = cx.tcx.optimized_mir(def_id); let mir = cx.tcx.optimized_mir(def_id);
if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv.as_ref()) { if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) {
if cx.tcx.is_const_fn_raw(def_id.to_def_id()) { if cx.tcx.is_const_fn_raw(def_id.to_def_id()) {
cx.tcx.sess.span_err(span, err.as_ref()); cx.tcx.sess.span_err(span, err.as_ref());
} }

View File

@ -193,7 +193,7 @@ impl<'tcx> LateLintPass<'tcx> for Ranges {
check_range_zip_with_len(cx, path, args, expr.span); check_range_zip_with_len(cx, path, args, expr.span);
}, },
ExprKind::Binary(ref op, l, r) => { ExprKind::Binary(ref op, l, r) => {
if meets_msrv(self.msrv.as_ref(), &msrvs::RANGE_CONTAINS) { if meets_msrv(self.msrv, msrvs::RANGE_CONTAINS) {
check_possible_range_contains(cx, op.node, l, r, expr); check_possible_range_contains(cx, op.node, l, r, expr);
} }
}, },

View File

@ -51,7 +51,7 @@ impl_lint_pass!(RedundantFieldNames => [REDUNDANT_FIELD_NAMES]);
impl EarlyLintPass for RedundantFieldNames { impl EarlyLintPass for RedundantFieldNames {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::FIELD_INIT_SHORTHAND) { if !meets_msrv(self.msrv, msrvs::FIELD_INIT_SHORTHAND) {
return; return;
} }

View File

@ -99,7 +99,7 @@ impl RedundantStaticLifetimes {
impl EarlyLintPass for RedundantStaticLifetimes { impl EarlyLintPass for RedundantStaticLifetimes {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
if !meets_msrv(self.msrv.as_ref(), &msrvs::STATIC_IN_CONST) { if !meets_msrv(self.msrv, msrvs::STATIC_IN_CONST) {
return; return;
} }

View File

@ -61,13 +61,13 @@ impl_lint_pass!(UnnestedOrPatterns => [UNNESTED_OR_PATTERNS]);
impl EarlyLintPass for UnnestedOrPatterns { impl EarlyLintPass for UnnestedOrPatterns {
fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) { fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) {
if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
lint_unnested_or_patterns(cx, &a.pat); lint_unnested_or_patterns(cx, &a.pat);
} }
} }
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
if let ast::ExprKind::Let(pat, _, _) = &e.kind { if let ast::ExprKind::Let(pat, _, _) = &e.kind {
lint_unnested_or_patterns(cx, pat); lint_unnested_or_patterns(cx, pat);
} }
@ -75,13 +75,13 @@ impl EarlyLintPass for UnnestedOrPatterns {
} }
fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) { fn check_param(&mut self, cx: &EarlyContext<'_>, p: &ast::Param) {
if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
lint_unnested_or_patterns(cx, &p.pat); lint_unnested_or_patterns(cx, &p.pat);
} }
} }
fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) { fn check_local(&mut self, cx: &EarlyContext<'_>, l: &ast::Local) {
if meets_msrv(self.msrv.as_ref(), &msrvs::OR_PATTERNS) { if meets_msrv(self.msrv, msrvs::OR_PATTERNS) {
lint_unnested_or_patterns(cx, &l.pat); lint_unnested_or_patterns(cx, &l.pat);
} }
} }

View File

@ -198,7 +198,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) { fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
if_chain! { if_chain! {
if !hir_ty.span.from_expansion(); if !hir_ty.span.from_expansion();
if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS); if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check { if let Some(&StackItem::Check {
impl_id, impl_id,
in_body, in_body,
@ -225,7 +225,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! { if_chain! {
if !expr.span.from_expansion(); if !expr.span.from_expansion();
if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS); if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id); if cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id);
then {} else { return; } then {} else { return; }
@ -256,7 +256,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
if_chain! { if_chain! {
if !pat.span.from_expansion(); if !pat.span.from_expansion();
if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS); if meets_msrv(self.msrv, msrvs::TYPE_ALIAS_ENUM_VARIANTS);
if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last(); if let Some(&StackItem::Check { impl_id, .. }) = self.stack.last();
if let PatKind::Path(QPath::Resolved(_, path)) = pat.kind; if let PatKind::Path(QPath::Resolved(_, path)) = pat.kind;
if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _)); if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _));

View File

@ -316,6 +316,14 @@ define_Conf! {
/// ///
/// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes /// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
(max_include_file_size: u64 = 1_000_000), (max_include_file_size: u64 = 1_000_000),
/// Lint: EXPECT_USED.
///
/// Whether `expect` should be allowed in test functions
(allow_expect_in_tests: bool = false),
/// Lint: UNWRAP_USED.
///
/// Whether `unwrap` should be allowed in test functions
(allow_unwrap_in_tests: bool = false),
} }
/// Search for the configuration file. /// Search for the configuration file.

View File

@ -117,8 +117,8 @@ pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Opt
None None
} }
pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool { pub fn meets_msrv(msrv: Option<RustcVersion>, lint_msrv: RustcVersion) -> bool {
msrv.map_or(true, |msrv| msrv.meets(*lint_msrv)) msrv.map_or(true, |msrv| msrv.meets(lint_msrv))
} }
#[macro_export] #[macro_export]

View File

@ -19,7 +19,7 @@ use std::borrow::Cow;
type McfResult = Result<(), (Span, Cow<'static, str>)>; type McfResult = Result<(), (Span, Cow<'static, str>)>;
pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<&RustcVersion>) -> McfResult { pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<RustcVersion>) -> McfResult {
let def_id = body.source.def_id(); let def_id = body.source.def_id();
let mut current = def_id; let mut current = def_id;
loop { loop {
@ -269,7 +269,7 @@ fn check_terminator<'a, 'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
body: &'a Body<'tcx>, body: &'a Body<'tcx>,
terminator: &Terminator<'tcx>, terminator: &Terminator<'tcx>,
msrv: Option<&RustcVersion>, msrv: Option<RustcVersion>,
) -> McfResult { ) -> McfResult {
let span = terminator.source_info.span; let span = terminator.source_info.span;
match &terminator.kind { match &terminator.kind {
@ -353,7 +353,7 @@ fn check_terminator<'a, 'tcx>(
} }
} }
fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> bool { fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<RustcVersion>) -> bool {
tcx.is_const_fn(def_id) tcx.is_const_fn(def_id)
&& tcx.lookup_const_stability(def_id).map_or(true, |const_stab| { && tcx.lookup_const_stability(def_id).map_or(true, |const_stab| {
if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level { if let rustc_attr::StabilityLevel::Stable { since } = const_stab.level {
@ -362,7 +362,7 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: Option<&RustcVersion>) -> b
// as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
crate::meets_msrv( crate::meets_msrv(
msrv, msrv,
&RustcVersion::parse(since.as_str()) RustcVersion::parse(since.as_str())
.expect("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted"), .expect("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted"),
) )
} else { } else {

View File

@ -432,7 +432,7 @@ The project's MSRV can then be matched against the feature MSRV in the LintPass
using the `meets_msrv` utility function. using the `meets_msrv` utility function.
``` rust ``` rust
if !meets_msrv(self.msrv.as_ref(), &msrvs::STR_STRIP_PREFIX) { if !meets_msrv(self.msrv, msrvs::STR_STRIP_PREFIX) {
return; return;
} }
``` ```

View File

@ -0,0 +1 @@
allow-expect-in-tests = true

View File

@ -0,0 +1,29 @@
// compile-flags: --test
#![warn(clippy::expect_used)]
fn expect_option() {
let opt = Some(0);
let _ = opt.expect("");
}
fn expect_result() {
let res: Result<u8, ()> = Ok(0);
let _ = res.expect("");
}
fn main() {
expect_option();
expect_result();
}
#[test]
fn test_expect_option() {
let opt = Some(0);
let _ = opt.expect("");
}
#[test]
fn test_expect_result() {
let res: Result<u8, ()> = Ok(0);
let _ = res.expect("");
}

View File

@ -0,0 +1,19 @@
error: used `expect()` on `an Option` value
--> $DIR/expect_used.rs:6:13
|
LL | let _ = opt.expect("");
| ^^^^^^^^^^^^^^
|
= note: `-D clippy::expect-used` implied by `-D warnings`
= help: if this value is an `None`, it will panic
error: used `expect()` on `a Result` value
--> $DIR/expect_used.rs:11:13
|
LL | let _ = res.expect("");
| ^^^^^^^^^^^^^^
|
= help: if this value is an `Err`, it will panic
error: aborting due to 2 previous errors

View File

@ -1,4 +1,4 @@
error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `enable-raw-pointer-heuristic-for-send`, `max-suggested-slice-pattern-length`, `await-holding-invalid-types`, `max-include-file-size`, `third-party` at line 5 column 1 error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `standard-macro-braces`, `enforced-import-renames`, `allowed-scripts`, `enable-raw-pointer-heuristic-for-send`, `max-suggested-slice-pattern-length`, `await-holding-invalid-types`, `max-include-file-size`, `allow-expect-in-tests`, `allow-unwrap-in-tests`, `third-party` at line 5 column 1
error: aborting due to previous error error: aborting due to previous error

View File

@ -0,0 +1 @@
allow-unwrap-in-tests = true

View File

@ -0,0 +1,74 @@
// compile-flags: --test
#![allow(unused_mut, clippy::from_iter_instead_of_collect)]
#![warn(clippy::unwrap_used)]
#![deny(clippy::get_unwrap)]
use std::collections::BTreeMap;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::iter::FromIterator;
struct GetFalsePositive {
arr: [u32; 3],
}
impl GetFalsePositive {
fn get(&self, pos: usize) -> Option<&u32> {
self.arr.get(pos)
}
fn get_mut(&mut self, pos: usize) -> Option<&mut u32> {
self.arr.get_mut(pos)
}
}
fn main() {
let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
let mut some_slice = &mut [0, 1, 2, 3];
let mut some_vec = vec![0, 1, 2, 3];
let mut some_vecdeque: VecDeque<_> = some_vec.iter().cloned().collect();
let mut some_hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(1, 'a'), (2, 'b')]);
let mut some_btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(1, 'a'), (2, 'b')]);
let mut false_positive = GetFalsePositive { arr: [0, 1, 2] };
{
// Test `get().unwrap()`
let _ = boxed_slice.get(1).unwrap();
let _ = some_slice.get(0).unwrap();
let _ = some_vec.get(0).unwrap();
let _ = some_vecdeque.get(0).unwrap();
let _ = some_hashmap.get(&1).unwrap();
let _ = some_btreemap.get(&1).unwrap();
#[allow(clippy::unwrap_used)]
let _ = false_positive.get(0).unwrap();
// Test with deref
let _: u8 = *boxed_slice.get(1).unwrap();
}
{
// Test `get_mut().unwrap()`
*boxed_slice.get_mut(0).unwrap() = 1;
*some_slice.get_mut(0).unwrap() = 1;
*some_vec.get_mut(0).unwrap() = 1;
*some_vecdeque.get_mut(0).unwrap() = 1;
// Check false positives
#[allow(clippy::unwrap_used)]
{
*some_hashmap.get_mut(&1).unwrap() = 'b';
*some_btreemap.get_mut(&1).unwrap() = 'b';
*false_positive.get_mut(0).unwrap() = 1;
}
}
{
// Test `get().unwrap().foo()` and `get_mut().unwrap().bar()`
let _ = some_vec.get(0..1).unwrap().to_vec();
let _ = some_vec.get_mut(0..1).unwrap().to_vec();
}
}
#[test]
fn test() {
let boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
let _ = boxed_slice.get(1).unwrap();
}

View File

@ -0,0 +1,197 @@
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:36:17
|
LL | let _ = boxed_slice.get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
|
note: the lint level is defined here
--> $DIR/unwrap_used.rs:5:9
|
LL | #![deny(clippy::get_unwrap)]
| ^^^^^^^^^^^^^^^^^^
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:36:17
|
LL | let _ = boxed_slice.get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::unwrap-used` implied by `-D warnings`
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:37:17
|
LL | let _ = some_slice.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:37:17
|
LL | let _ = some_slice.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:38:17
|
LL | let _ = some_vec.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:38:17
|
LL | let _ = some_vec.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:39:17
|
LL | let _ = some_vecdeque.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:39:17
|
LL | let _ = some_vecdeque.get(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:40:17
|
LL | let _ = some_hashmap.get(&1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:40:17
|
LL | let _ = some_hashmap.get(&1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:41:17
|
LL | let _ = some_btreemap.get(&1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:41:17
|
LL | let _ = some_btreemap.get(&1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:45:21
|
LL | let _: u8 = *boxed_slice.get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:45:22
|
LL | let _: u8 = *boxed_slice.get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:50:9
|
LL | *boxed_slice.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:50:10
|
LL | *boxed_slice.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:51:9
|
LL | *some_slice.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:51:10
|
LL | *some_slice.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:52:9
|
LL | *some_vec.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:52:10
|
LL | *some_vec.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:53:9
|
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:53:10
|
LL | *some_vecdeque.get_mut(0).unwrap() = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:65:17
|
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:65:17
|
LL | let _ = some_vec.get(0..1).unwrap().to_vec();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:66:17
|
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
error: used `unwrap()` on `an Option` value
--> $DIR/unwrap_used.rs:66:17
|
LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
--> $DIR/unwrap_used.rs:73:13
|
LL | let _ = boxed_slice.get(1).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
error: aborting due to 27 previous errors