use syntax::ast;
use utils::sugg;
-use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg, in_external_macro,
- span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, higher,
- walk_ptrs_ty};
+use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, multispan_sugg,
+ in_external_macro, is_refutable, span_help_and_lint, is_integer_literal,
+ get_enclosing_block, span_lint_and_then, higher, walk_ptrs_ty};
use utils::paths;
/// **What it does:** Checks for looping over the range of `0..len` of some
if method_name.node.as_str() == "next" &&
match_trait_method(cx, match_expr, &paths::ITERATOR) &&
lhs_constructor.name.as_str() == "Some" &&
+ !is_refutable(cx, &pat_args[0]) &&
!is_iterator_used_after_while_let(cx, iter_expr) {
let iterator = snippet(cx, method_args[0].span, "_");
let loop_var = snippet(cx, pat_args[0].span, "_");
let env = ty::ParameterEnvironment::for_item(cx.tcx, env);
!ty.subst(cx.tcx, env.free_substs).moves_by_default(cx.tcx.global_tcx(), &env, DUMMY_SP)
}
+
+/// Return whether a pattern is refutable.
+pub fn is_refutable(cx: &LateContext, pat: &Pat) -> bool {
+ fn is_enum_variant(cx: &LateContext, did: NodeId) -> bool {
+ matches!(cx.tcx.def_map.borrow().get(&did).map(|d| d.full_def()), Some(def::Def::Variant(..)))
+ }
+
+ fn are_refutable<'a, I: Iterator<Item=&'a Pat>>(cx: &LateContext, mut i: I) -> bool {
+ i.any(|pat| is_refutable(cx, pat))
+ }
+
+ match pat.node {
+ PatKind::Binding(..) | PatKind::Wild => false,
+ PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
+ PatKind::Lit(..) | PatKind::Range(..) => true,
+ PatKind::Path(..) => is_enum_variant(cx, pat.id),
+ PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
+ PatKind::Struct(_, ref fields, _) => {
+ if is_enum_variant(cx, pat.id) {
+ true
+ } else {
+ are_refutable(cx, fields.iter().map(|field| &*field.node.pat))
+ }
+ }
+ PatKind::TupleStruct(_, ref pats, _) => {
+ if is_enum_variant(cx, pat.id) {
+ true
+ } else {
+ are_refutable(cx, pats.iter().map(|pat| &**pat))
+ }
+ }
+ PatKind::Vec(ref head, ref middle, ref tail) => {
+ are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat))
+ }
+ }
+}