use crate::utils::paths;
use crate::utils::sugg::Sugg;
use crate::utils::{
- expr_block, in_macro, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, remove_blocks, snippet,
+ expr_block, is_allowed, is_expn_of, match_qpath, match_type, multispan_sugg, remove_blocks, snippet,
snippet_with_applicability, span_lint_and_sugg, span_lint_and_then, span_note_and_lint, walk_ptrs_ty,
};
use if_chain::if_chain;
use rustc::hir::def::CtorKind;
use rustc::hir::*;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
-use rustc::ty::{self, Ty, TyKind};
-use rustc::{declare_tool_lint, lint_array};
+use rustc::ty::{self, Ty};
+use rustc::{declare_lint_pass, declare_tool_lint};
use rustc_errors::Applicability;
use std::cmp::Ordering;
use std::collections::Bound;
}
declare_clippy_lint! {
- /// **What it does:** Checks for matches with a two arms where an `if let else` will
+ /// **What it does:** Checks for matches with two arms where an `if let else` will
/// usually suffice.
///
/// **Why is this bad?** Just readability – `if let` nests less than a `match`.
/// Using `match`:
///
/// ```rust
+ /// # fn bar(foo: &usize) {}
+ /// # let other_ref: usize = 1;
+ /// # let x: Option<&usize> = Some(&1);
/// match x {
/// Some(ref foo) => bar(foo),
- /// _ => bar(other_ref),
+ /// _ => bar(&other_ref),
/// }
/// ```
///
/// Using `if let` with `else`:
///
/// ```rust
+ /// # fn bar(foo: &usize) {}
+ /// # let other_ref: usize = 1;
+ /// # let x: Option<&usize> = Some(&1);
/// if let Some(ref foo) = x {
/// bar(foo);
/// } else {
- /// bar(other_ref);
+ /// bar(&other_ref);
/// }
/// ```
pub SINGLE_MATCH_ELSE,
pedantic,
- "a match statement with a two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
+ "a match statement with two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
}
declare_clippy_lint! {
///
/// **Example:**
/// ```rust
+ /// # enum Foo { A(usize), B(usize) }
+ /// # let x = Foo::B(1);
/// match x {
/// A => {},
/// _ => {},
"a wildcard enum match arm using `_`"
}
-#[allow(missing_copy_implementations)]
-pub struct MatchPass;
-
-impl LintPass for MatchPass {
- fn get_lints(&self) -> LintArray {
- lint_array!(
- SINGLE_MATCH,
- MATCH_REF_PATS,
- MATCH_BOOL,
- SINGLE_MATCH_ELSE,
- MATCH_OVERLAPPING_ARM,
- MATCH_WILD_ERR_ARM,
- MATCH_AS_REF,
- WILDCARD_ENUM_MATCH_ARM
- )
- }
-
- fn name(&self) -> &'static str {
- "Matches"
- }
-}
-
-impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchPass {
+declare_lint_pass!(Matches => [
+ SINGLE_MATCH,
+ MATCH_REF_PATS,
+ MATCH_BOOL,
+ SINGLE_MATCH_ELSE,
+ MATCH_OVERLAPPING_ARM,
+ MATCH_WILD_ERR_ARM,
+ MATCH_AS_REF,
+ WILDCARD_ENUM_MATCH_ARM
+]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Matches {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if in_external_macro(cx.sess(), expr.span) {
return;
// already covered.
let mut missing_variants = vec![];
- if let TyKind::Adt(def, _) = ty.sty {
+ if let ty::Adt(def, _) = ty.sty {
for variant in &def.variants {
missing_variants.push(variant);
}
for pat in &arm.pats {
if let PatKind::Path(ref path) = pat.deref().node {
if let QPath::Resolved(_, p) = path {
- missing_variants.retain(|e| e.did != p.def.def_id());
+ missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
}
} else if let PatKind::TupleStruct(ref path, ..) = pat.deref().node {
if let QPath::Resolved(_, p) = path {
- missing_variants.retain(|e| e.did != p.def.def_id());
+ missing_variants.retain(|e| e.ctor_def_id != Some(p.res.def_id()));
}
}
}
String::new()
};
// This path assumes that the enum type is imported into scope.
- format!("{}{}{}", ident_str, cx.tcx.item_path_str(v.did), suffix)
+ format!("{}{}{}", ident_str, cx.tcx.def_path_str(v.def_id), suffix)
})
.collect();
}));
span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |db| {
- if !in_macro(expr.span) {
+ if !expr.span.from_expansion() {
multispan_sugg(db, msg.to_owned(), suggs);
}
});
} else {
"as_mut"
};
+
+ let output_ty = cx.tables.expr_ty(expr);
+ let input_ty = cx.tables.expr_ty(ex);
+
+ let cast = if_chain! {
+ if let ty::Adt(_, substs) = input_ty.sty;
+ let input_ty = substs.type_at(0);
+ if let ty::Adt(_, substs) = output_ty.sty;
+ let output_ty = substs.type_at(0);
+ if let ty::Ref(_, output_ty, _) = output_ty.sty;
+ if input_ty != output_ty;
+ then {
+ ".map(|x| x as _)"
+ } else {
+ ""
+ }
+ };
+
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
&format!("use {}() instead", suggestion),
"try this",
format!(
- "{}.{}()",
+ "{}.{}(){}",
snippet_with_applicability(cx, ex.span, "_", &mut applicability),
- suggestion
+ suggestion,
+ cast,
),
applicability,
)
T: Copy + Ord,
{
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
- enum Kind<'a, T: 'a> {
+ enum Kind<'a, T> {
Start(T, &'a SpannedRange<T>),
End(Bound<T>, &'a SpannedRange<T>),
}