use rustc_hir::{Expr, ExprKind, PrimTy, QPath, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
-use rustc_middle::ty::{self, TraitRef, Ty, TyS};
+use rustc_middle::ty::{self, TraitRef, Ty};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
///
/// ### Why is this bad?
/// Readability, this can be written more concisely as
- /// `_.flat_map(_)`
+ /// `_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option`
///
/// ### Example
/// ```rust
/// let vec = vec![vec![1]];
+ /// let opt = Some(5);
///
/// // Bad
/// vec.iter().map(|x| x.iter()).flatten();
+ /// opt.map(|x| Some(x * 2)).flatten();
///
/// // Good
/// vec.iter().flat_map(|x| x.iter());
+ /// opt.and_then(|x| Some(x * 2));
/// ```
#[clippy::version = "1.31.0"]
pub MAP_FLATTEN,
/// Extracts a method call name, args, and `Span` of the method name.
fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> {
- if let ExprKind::MethodCall(path, span, args, _) = recv.kind {
+ if let ExprKind::MethodCall(path, args, _) = recv.kind {
if !args.iter().any(|e| e.span.from_expansion()) {
let name = path.ident.name.as_str();
- return Some((name, args, span));
+ return Some((name, args, path.ident.span));
}
}
None
hir::ExprKind::Call(func, args) => {
from_iter_instead_of_collect::check(cx, expr, args, func);
},
- hir::ExprKind::MethodCall(method_call, ref method_span, args, _) => {
- or_fun_call::check(cx, expr, *method_span, method_call.ident.as_str(), args);
- expect_fun_call::check(cx, expr, *method_span, method_call.ident.as_str(), args);
+ hir::ExprKind::MethodCall(method_call, args, _) => {
+ let method_span = method_call.ident.span;
+ or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
+ expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), args);
clone_on_copy::check(cx, expr, method_call.ident.name, args);
clone_on_ref_ptr::check(cx, expr, method_call.ident.name, args);
inefficient_to_string::check(cx, expr, method_call.ident.name, 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);
unnecessary_to_owned::check(cx, expr, method_call.ident.name, args);
},
// one of the associated types must be Self
for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
+ let assoc_ty = match projection_predicate.term {
+ ty::Term::Ty(ty) => ty,
+ ty::Term::Const(_c) => continue,
+ };
// walk the associated type and check for Self
if let Some(self_adt) = self_ty.ty_adt_def() {
- if contains_adt_constructor(projection_predicate.ty, self_adt) {
+ if contains_adt_constructor(assoc_ty, self_adt) {
return;
}
- } else if contains_ty(projection_predicate.ty, self_ty) {
+ } else if contains_ty(assoc_ty, self_ty) {
return;
}
}
}
}
- if name == "new" && !TyS::same_type(ret_ty, self_ty) {
+ if name == "new" && ret_ty != self_ty {
span_lint(
cx,
NEW_RET_NO_SELF,
("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),
- _ => unwrap_used::check(cx, 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);
+ },
+ _ => {},
+ }
+ unwrap_used::check(cx, expr, recv);
},
("unwrap_or", [u_arg]) => match method_call(recv) {
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {