Fix FP with mut_mut and for loops

This commit is contained in:
mcarton 2016-06-21 22:54:22 +02:00
parent 5f6b982bc9
commit 7fa38f6787
No known key found for this signature in database
GPG key ID: 5E427C794CBA45E8
2 changed files with 69 additions and 21 deletions

View file

@ -1,7 +1,8 @@
use rustc::hir;
use rustc::hir::intravisit;
use rustc::lint::*;
use rustc::ty::{TypeAndMut, TyRef};
use rustc::hir::*;
use utils::{in_external_macro, span_lint};
use utils::{in_external_macro, recover_for_loop, span_lint};
/// **What it does:** This lint checks for instances of `mut mut` references.
///
@ -27,30 +28,56 @@ impl LintPass for MutMut {
}
impl LateLintPass for MutMut {
fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
if in_external_macro(cx, expr.span) {
fn check_block(&mut self, cx: &LateContext, block: &hir::Block) {
intravisit::walk_block(&mut MutVisitor { cx: cx }, block);
}
fn check_ty(&mut self, cx: &LateContext, ty: &hir::Ty) {
use rustc::hir::intravisit::Visitor;
MutVisitor { cx: cx }.visit_ty(ty);
}
}
pub struct MutVisitor<'a, 'tcx: 'a> {
cx: &'a LateContext<'a, 'tcx>,
}
impl<'a, 'tcx, 'v> intravisit::Visitor<'v> for MutVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'v hir::Expr) {
if in_external_macro(self.cx, expr.span) {
return;
}
if let ExprAddrOf(MutMutable, ref e) = expr.node {
if let ExprAddrOf(MutMutable, _) = e.node {
span_lint(cx, MUT_MUT, expr.span, "generally you want to avoid `&mut &mut _` if possible");
} else {
if let TyRef(_, TypeAndMut { mutbl: MutMutable, .. }) = cx.tcx.expr_ty(e).sty {
span_lint(cx,
MUT_MUT,
expr.span,
"this expression mutably borrows a mutable reference. Consider reborrowing");
}
if let Some((_, arg, body)) = recover_for_loop(expr) {
// A `for` loop lowers to:
// ```rust
// match ::std::iter::Iterator::next(&mut iter) {
// // ^^^^
// ```
// Let's ignore the generated code.
intravisit::walk_expr(self, arg);
intravisit::walk_expr(self, body);
} else if let hir::ExprAddrOf(hir::MutMutable, ref e) = expr.node {
if let hir::ExprAddrOf(hir::MutMutable, _) = e.node {
span_lint(self.cx, MUT_MUT, expr.span, "generally you want to avoid `&mut &mut _` if possible");
} else if let TyRef(_, TypeAndMut { mutbl: hir::MutMutable, .. }) = self.cx.tcx.expr_ty(e).sty {
span_lint(self.cx,
MUT_MUT,
expr.span,
"this expression mutably borrows a mutable reference. Consider reborrowing");
}
}
}
fn check_ty(&mut self, cx: &LateContext, ty: &Ty) {
if let TyRptr(_, MutTy { ty: ref pty, mutbl: MutMutable }) = ty.node {
if let TyRptr(_, MutTy { mutbl: MutMutable, .. }) = pty.node {
span_lint(cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible");
fn visit_ty(&mut self, ty: &hir::Ty) {
if let hir::TyRptr(_, hir::MutTy { ty: ref pty, mutbl: hir::MutMutable }) = ty.node {
if let hir::TyRptr(_, hir::MutTy { mutbl: hir::MutMutable, .. }) = pty.node {
span_lint(self.cx, MUT_MUT, ty.span, "generally you want to avoid `&mut &mut _` if possible");
}
}
intravisit::walk_ty(self, ty);
}
}