about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/utils/author.rs611
-rw-r--r--tests/ui/author.stdout2
-rw-r--r--tests/ui/author/blocks.rs9
-rw-r--r--tests/ui/author/blocks.stdout34
-rw-r--r--tests/ui/author/call.stdout4
-rw-r--r--tests/ui/author/for_loop.rs8
-rw-r--r--tests/ui/author/for_loop.stdout64
-rw-r--r--tests/ui/author/if.rs7
-rw-r--r--tests/ui/author/if.stdout40
-rw-r--r--tests/ui/author/loop.rs36
-rw-r--r--tests/ui/author/loop.stdout112
-rw-r--r--tests/ui/author/matches.stdout14
-rw-r--r--tests/ui/author/repeat.rs5
-rw-r--r--tests/ui/author/repeat.stdout10
-rw-r--r--tests/ui/author/struct.rs40
-rw-r--r--tests/ui/author/struct.stdout61
16 files changed, 827 insertions, 230 deletions
diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs
index f93d7782e25..38157cc16ef 100644
--- a/clippy_lints/src/utils/author.rs
+++ b/clippy_lints/src/utils/author.rs
@@ -1,13 +1,13 @@
 //! A group of attributes that can be attached to Rust code in order
 //! to generate a clippy lint detecting said code automatically.
 
-use clippy_utils::get_attr;
+use clippy_utils::{get_attr, higher};
 use rustc_ast::ast::{LitFloatType, LitKind};
-use rustc_ast::walk_list;
+use rustc_ast::{walk_list, Label, LitIntType};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
-use rustc_hir::{Block, Expr, ExprKind, Pat, PatKind, QPath, Stmt, StmtKind, TyKind};
+use rustc_hir::{Arm, Block, Expr, ExprKind, FnRetTy, Lit, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -70,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
             return;
         }
         prelude();
-        PrintVisitor::new("item").visit_item(item);
+        PrintVisitor::new("item", cx).visit_item(item);
         done();
     }
 
@@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
             return;
         }
         prelude();
-        PrintVisitor::new("item").visit_impl_item(item);
+        PrintVisitor::new("item", cx).visit_impl_item(item);
         done();
     }
 
@@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
             return;
         }
         prelude();
-        PrintVisitor::new("item").visit_trait_item(item);
+        PrintVisitor::new("item", cx).visit_trait_item(item);
         done();
     }
 
@@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
         }
         prelude();
         let parent_hir_id = cx.tcx.hir().get_parent_node(var.id);
-        PrintVisitor::new("var").visit_variant(var, &hir::Generics::empty(), parent_hir_id);
+        PrintVisitor::new("var", cx).visit_variant(var, &hir::Generics::empty(), parent_hir_id);
         done();
     }
 
@@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
             return;
         }
         prelude();
-        PrintVisitor::new("field").visit_field_def(field);
+        PrintVisitor::new("field", cx).visit_field_def(field);
         done();
     }
 
@@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
             return;
         }
         prelude();
-        PrintVisitor::new("expr").visit_expr(expr);
+        PrintVisitor::new("expr", cx).visit_expr(expr);
         done();
     }
 
@@ -125,7 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
             return;
         }
         prelude();
-        PrintVisitor::new("arm").visit_arm(arm);
+        PrintVisitor::new("arm", cx).visit_arm(arm);
         done();
     }
 
@@ -138,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for Author {
             _ => {},
         }
         prelude();
-        PrintVisitor::new("stmt").visit_stmt(stmt);
+        PrintVisitor::new("stmt", cx).visit_stmt(stmt);
         done();
     }
 
@@ -147,17 +147,18 @@ impl<'tcx> LateLintPass<'tcx> for Author {
             return;
         }
         prelude();
-        PrintVisitor::new("item").visit_foreign_item(item);
+        PrintVisitor::new("item", cx).visit_foreign_item(item);
         done();
     }
 }
 
-impl PrintVisitor {
+impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
     #[must_use]
-    fn new(s: &'static str) -> Self {
+    fn new(s: &'static str, cx: &'a LateContext<'tcx>) -> Self {
         Self {
             ids: FxHashMap::default(),
             current: s.to_owned(),
+            cx,
         }
     }
 
@@ -190,43 +191,299 @@ impl PrintVisitor {
             println!("]);");
         }
     }
+
+    fn print_label(&mut self, label: Option<Label>) {
+        if let Some(label) = label {
+            let label_bind = self.next("label");
+
+            println!("    if let Some(ref {}) = {}", label_bind, self.current);
+
+            let label_name_bind = self.next("label_name");
+            let label_name = label.ident.name;
+
+            println!(
+                "    if {}.ident.name.as_str() == {:?};",
+                label_name_bind,
+                label_name.as_str()
+            );
+        }
+    }
+
+    fn print_lit_expr(&mut self, lit: &Lit, current: &str) {
+        let lit_pat = self.next("lit");
+
+        println!("Lit(ref {}) = {};", lit_pat, current);
+
+        match lit.node {
+            LitKind::Bool(val) => println!("    if let LitKind::Bool({:?}) = {}.node;", val, lit_pat),
+            LitKind::Char(c) => println!("    if let LitKind::Char({:?}) = {}.node;", c, lit_pat),
+            LitKind::Err(val) => println!("    if let LitKind::Err({}) = {}.node;", val, lit_pat),
+            LitKind::Byte(b) => println!("    if let LitKind::Byte({}) = {}.node;", b, lit_pat),
+            LitKind::Int(i, suffix) => {
+                let int_ty = match suffix {
+                    LitIntType::Signed(int_ty) => format!("LitIntType::Signed(IntTy::{:?})", int_ty),
+                    LitIntType::Unsigned(uint_ty) => format!("LitIntType::Unsigned(UintTy::{:?})", uint_ty),
+                    LitIntType::Unsuffixed => String::from("LitIntType::Unsuffixed"),
+                };
+
+                println!("    if let LitKind::Int({}, {}) = {}.node;", i, int_ty, lit_pat);
+            },
+            LitKind::Float(_, suffix) => {
+                let float_ty = match suffix {
+                    LitFloatType::Suffixed(suffix_ty) => format!("LitFloatType::Suffixed(FloatTy::{:?})", suffix_ty),
+                    LitFloatType::Unsuffixed => String::from("LitFloatType::Unsuffixed"),
+                };
+
+                println!("    if let LitKind::Float(_, {}) = {}.node;", float_ty, lit_pat);
+            },
+            LitKind::ByteStr(ref vec) => {
+                let vec_pat = self.next("vec");
+
+                println!("    if let LitKind::ByteStr(ref {}) = {}.node;", vec_pat, lit_pat);
+                println!("    if let [{:?}] = **{};", vec, vec_pat);
+            },
+            LitKind::Str(ref text, _) => {
+                let str_pat = self.next("s");
+
+                println!("    if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat);
+                println!("    if {}.as_str() == {:?}", str_pat, &*text.as_str());
+            },
+        }
+    }
+
+    fn print_match_expr(&mut self, expr: &Expr<'_>, arms: &[Arm<'_>], des: MatchSource, current: &str) {
+        let expr_pat = self.next("expr");
+        let arms_pat = self.next("arms");
+
+        println!(
+            "Match(ref {}, ref {}, MatchSource::{:?}) = {};",
+            expr_pat, arms_pat, des, current
+        );
+
+        self.current = expr_pat;
+        self.visit_expr(expr);
+
+        println!("    if {}.len() == {};", arms_pat, arms.len());
+
+        for (i, arm) in arms.iter().enumerate() {
+            self.current = format!("{}[{}].body", arms_pat, i);
+            self.visit_expr(arm.body);
+
+            if let Some(ref guard) = arm.guard {
+                let guard_pat = self.next("guard");
+
+                println!("    if let Some(ref {}) = {}[{}].guard;", guard_pat, arms_pat, i);
+
+                match guard {
+                    hir::Guard::If(if_expr) => {
+                        let if_expr_pat = self.next("expr");
+
+                        println!("    if let Guard::If(ref {}) = {};", if_expr_pat, guard_pat);
+
+                        self.current = if_expr_pat;
+                        self.visit_expr(if_expr);
+                    },
+                    hir::Guard::IfLet(if_let_pat, if_let_expr) => {
+                        let if_let_pat_pat = self.next("pat");
+                        let if_let_expr_pat = self.next("expr");
+
+                        println!(
+                            "    if let Guard::IfLet(ref {}, ref {}) = {};",
+                            if_let_pat_pat, if_let_expr_pat, guard_pat
+                        );
+
+                        self.current = if_let_expr_pat;
+                        self.visit_expr(if_let_expr);
+
+                        self.current = if_let_pat_pat;
+                        self.visit_pat(if_let_pat);
+                    },
+                }
+            }
+            self.current = format!("{}[{}].pat", arms_pat, i);
+            self.visit_pat(arm.pat);
+        }
+    }
+
+    fn check_higher(&mut self, expr: &Expr<'_>) -> bool {
+        if let Some(higher::While { condition, body }) = higher::While::hir(expr) {
+            let condition_pat = self.next("condition");
+            let body_pat = self.next("body");
+
+            println!(
+                "    if let Some(higher::While {{ condition: {}, body: {} }}) = higher::While::hir({})",
+                condition_pat, body_pat, self.current
+            );
+
+            self.current = condition_pat;
+            self.visit_expr(condition);
+
+            self.current = body_pat;
+            self.visit_expr(body);
+
+            return true;
+        }
+
+        if let Some(higher::WhileLet {
+            let_pat,
+            let_expr,
+            if_then,
+        }) = higher::WhileLet::hir(expr)
+        {
+            let let_pat_ = self.next("let_pat");
+            let let_expr_pat = self.next("let_expr");
+            let if_then_pat = self.next("if_then");
+
+            println!(
+                "    if let Some(higher::WhileLet {{ let_pat: {}, let_expr: {}, if_then: {} }}) = higher::WhileLet::hir({})",
+                let_pat_, let_expr_pat, if_then_pat, self.current
+            );
+
+            self.current = let_pat_;
+            self.visit_pat(let_pat);
+
+            self.current = let_expr_pat;
+            self.visit_expr(let_expr);
+
+            self.current = if_then_pat;
+            self.visit_expr(if_then);
+
+            return true;
+        }
+
+        if let Some(higher::IfLet {
+            let_pat,
+            let_expr,
+            if_then,
+            if_else,
+        }) = higher::IfLet::hir(self.cx, expr)
+        {
+            let let_pat_ = self.next("let_pat");
+            let let_expr_pat = self.next("let_expr");
+            let if_then_pat = self.next("if_then");
+            let else_pat = self.next("else_expr");
+
+            println!(
+                "    if let Some(higher::IfLet {{ let_pat: {}, let_expr: {}, if_then: {}, if_else: {}}}) = higher::IfLet::hir({})",
+                let_pat_, let_expr_pat, if_then_pat, else_pat, self.current
+            );
+
+            self.current = let_pat_;
+            self.visit_pat(let_pat);
+
+            self.current = let_expr_pat;
+            self.visit_expr(let_expr);
+
+            self.current = if_then_pat;
+            self.visit_expr(if_then);
+
+            if let Some(else_expr) = if_else {
+                self.current = else_pat;
+                self.visit_expr(else_expr);
+            }
+
+            return true;
+        }
+
+        if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) {
+            let cond_pat = self.next("cond");
+            let then_pat = self.next("then");
+            let else_pat = self.next("else_expr");
+
+            println!(
+                "    if let Some(higher::If {{ cond: {}, then: {}, r#else: {}}}) = higher::If::hir({})",
+                cond_pat, then_pat, else_pat, self.current
+            );
+
+            self.current = cond_pat;
+            self.visit_expr(cond);
+
+            self.current = then_pat;
+            self.visit_expr(then);
+
+            if let Some(else_expr) = r#else {
+                self.current = else_pat;
+                self.visit_expr(else_expr);
+            }
+
+            return true;
+        }
+
+        if let Some(higher::ForLoop { pat, arg, body, .. }) = higher::ForLoop::hir(expr) {
+            let pat_ = self.next("pat");
+            let arg_pat = self.next("arg");
+            let body_pat = self.next("body");
+
+            println!(
+                "    if let Some(higher::ForLoop {{ pat: {}, arg: {}, body: {}, ..}}) = higher::ForLoop::hir({})",
+                pat_, arg_pat, body_pat, self.current
+            );
+
+            self.current = pat_;
+            self.visit_pat(pat);
+
+            self.current = arg_pat;
+            self.visit_expr(arg);
+
+            self.current = body_pat;
+            self.visit_expr(body);
+
+            return true;
+        }
+
+        false
+    }
 }
 
-struct PrintVisitor {
+struct PrintVisitor<'a, 'tcx> {
     /// Fields are the current index that needs to be appended to pattern
     /// binding names
     ids: FxHashMap<&'static str, usize>,
     /// the name that needs to be destructured
     current: String,
+    cx: &'a LateContext<'tcx>,
 }
 
-impl<'tcx> Visitor<'tcx> for PrintVisitor {
+impl<'a, 'tcx> Visitor<'tcx> for PrintVisitor<'a, '_> {
     type Map = Map<'tcx>;
 
     #[allow(clippy::too_many_lines)]
     fn visit_expr(&mut self, expr: &Expr<'_>) {
+        if self.check_higher(expr) {
+            return;
+        }
+
         print!("    if let ExprKind::");
         let current = format!("{}.kind", self.current);
+
         match expr.kind {
             ExprKind::Let(pat, expr, _) => {
                 let let_pat = self.next("pat");
                 let let_expr = self.next("expr");
-                println!("    Let(ref {}, ref {}, _) = {};", let_pat, let_expr, current);
+
+                println!("Let(ref {}, ref {}, _) = {};", let_pat, let_expr, current);
+
                 self.current = let_expr;
                 self.visit_expr(expr);
+
                 self.current = let_pat;
                 self.visit_pat(pat);
             },
             ExprKind::Box(inner) => {
                 let inner_pat = self.next("inner");
+
                 println!("Box(ref {}) = {};", inner_pat, current);
+
                 self.current = inner_pat;
                 self.visit_expr(inner);
             },
             ExprKind::Array(elements) => {
                 let elements_pat = self.next("elements");
+
                 println!("Array(ref {}) = {};", elements_pat, current);
+
                 println!("    if {}.len() == {};", elements_pat, elements.len());
+
                 for (i, element) in elements.iter().enumerate() {
                     self.current = format!("{}[{}]", elements_pat, i);
                     self.visit_expr(element);
@@ -235,26 +492,48 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
             ExprKind::Call(func, args) => {
                 let func_pat = self.next("func");
                 let args_pat = self.next("args");
+
                 println!("Call(ref {}, ref {}) = {};", func_pat, args_pat, current);
+
                 self.current = func_pat;
                 self.visit_expr(func);
+
                 println!("    if {}.len() == {};", args_pat, args.len());
+
                 for (i, arg) in args.iter().enumerate() {
                     self.current = format!("{}[{}]", args_pat, i);
                     self.visit_expr(arg);
                 }
             },
-            ExprKind::MethodCall(_method_name, ref _generics, _args, ref _fn_span) => {
+            ExprKind::MethodCall(method_name, _, args, _) => {
+                let method_name_pat = self.next("method_name");
+                let args_pat = self.next("args");
+
                 println!(
-                    "MethodCall(ref method_name, ref generics, ref args, ref fn_span) = {};",
-                    current
+                    "MethodCall(ref {}, ref {}, _) = {};",
+                    method_name_pat, args_pat, current
                 );
-                println!("    // unimplemented: `ExprKind::MethodCall` is not further destructured at the moment");
+
+                println!(
+                    "    if {}.ident.name.as_str() == {};",
+                    method_name_pat,
+                    method_name.ident.name.as_str()
+                );
+
+                println!("    if {}.len() == {};", args_pat, args.len());
+
+                for (i, arg) in args.iter().enumerate() {
+                    self.current = format!("{}[{}]", args_pat, i);
+                    self.visit_expr(arg);
+                }
             },
             ExprKind::Tup(elements) => {
                 let elements_pat = self.next("elements");
+
                 println!("Tup(ref {}) = {};", elements_pat, current);
+
                 println!("    if {}.len() == {};", elements_pat, elements.len());
+
                 for (i, element) in elements.iter().enumerate() {
                     self.current = format!("{}[{}]", elements_pat, i);
                     self.visit_expr(element);
@@ -264,167 +543,136 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 let op_pat = self.next("op");
                 let left_pat = self.next("left");
                 let right_pat = self.next("right");
+
                 println!(
                     "Binary(ref {}, ref {}, ref {}) = {};",
                     op_pat, left_pat, right_pat, current
                 );
+
                 println!("    if BinOpKind::{:?} == {}.node;", op.node, op_pat);
+
                 self.current = left_pat;
                 self.visit_expr(left);
+
                 self.current = right_pat;
                 self.visit_expr(right);
             },
             ExprKind::Unary(ref op, inner) => {
                 let inner_pat = self.next("inner");
+
                 println!("Unary(UnOp::{:?}, ref {}) = {};", op, inner_pat, current);
+
                 self.current = inner_pat;
                 self.visit_expr(inner);
             },
-            ExprKind::Lit(ref lit) => {
-                let lit_pat = self.next("lit");
-                println!("Lit(ref {}) = {};", lit_pat, current);
-                match lit.node {
-                    LitKind::Bool(val) => println!("    if let LitKind::Bool({:?}) = {}.node;", val, lit_pat),
-                    LitKind::Char(c) => println!("    if let LitKind::Char({:?}) = {}.node;", c, lit_pat),
-                    LitKind::Err(val) => println!("    if let LitKind::Err({}) = {}.node;", val, lit_pat),
-                    LitKind::Byte(b) => println!("    if let LitKind::Byte({}) = {}.node;", b, lit_pat),
-                    // FIXME: also check int type
-                    LitKind::Int(i, _) => println!("    if let LitKind::Int({}, _) = {}.node;", i, lit_pat),
-                    LitKind::Float(_, LitFloatType::Suffixed(_)) => println!(
-                        "    if let LitKind::Float(_, LitFloatType::Suffixed(_)) = {}.node;",
-                        lit_pat
-                    ),
-                    LitKind::Float(_, LitFloatType::Unsuffixed) => println!(
-                        "    if let LitKind::Float(_, LitFloatType::Unsuffixed) = {}.node;",
-                        lit_pat
-                    ),
-                    LitKind::ByteStr(ref vec) => {
-                        let vec_pat = self.next("vec");
-                        println!("    if let LitKind::ByteStr(ref {}) = {}.node;", vec_pat, lit_pat);
-                        println!("    if let [{:?}] = **{};", vec, vec_pat);
-                    },
-                    LitKind::Str(ref text, _) => {
-                        let str_pat = self.next("s");
-                        println!("    if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat);
-                        println!("    if {}.as_str() == {:?}", str_pat, &*text.as_str());
-                    },
-                }
-            },
+            ExprKind::Lit(ref lit) => self.print_lit_expr(lit, &current),
             ExprKind::Cast(expr, ty) => {
                 let cast_pat = self.next("expr");
                 let cast_ty = self.next("cast_ty");
                 let qp_label = self.next("qp");
 
                 println!("Cast(ref {}, ref {}) = {};", cast_pat, cast_ty, current);
+
                 if let TyKind::Path(ref qp) = ty.kind {
                     println!("    if let TyKind::Path(ref {}) = {}.kind;", qp_label, cast_ty);
+
                     self.current = qp_label;
                     self.print_qpath(qp);
                 }
+
                 self.current = cast_pat;
                 self.visit_expr(expr);
             },
             ExprKind::Type(expr, _ty) => {
                 let cast_pat = self.next("expr");
+
                 println!("Type(ref {}, _) = {};", cast_pat, current);
+
                 self.current = cast_pat;
                 self.visit_expr(expr);
             },
-            ExprKind::Loop(body, _, des, _) => {
+            ExprKind::Loop(body, label, des, _) => {
                 let body_pat = self.next("body");
                 let label_pat = self.next("label");
+
                 println!(
                     "Loop(ref {}, ref {}, LoopSource::{:?}) = {};",
                     body_pat, label_pat, des, current
                 );
+
                 self.current = body_pat;
                 self.visit_block(body);
+
+                self.current = label_pat;
+                self.print_label(label);
             },
-            ExprKind::If(cond, then, ref opt_else) => {
-                let cond_pat = self.next("cond");
-                let then_pat = self.next("then");
-                if let Some(else_) = *opt_else {
-                    let else_pat = self.next("else_");
-                    println!(
-                        "If(ref {}, ref {}, Some(ref {})) = {};",
-                        cond_pat, then_pat, else_pat, current
-                    );
-                    self.current = else_pat;
-                    self.visit_expr(else_);
+            ExprKind::If(_, _, _) => {}, // Covered by check_higher
+            ExprKind::Match(match_expr, arms, des) => self.print_match_expr(match_expr, arms, des, &current),
+            ExprKind::Closure(capture_clause, fn_decl, body_id, _, movability) => {
+                let capture_by = format!("CaptureBy::{:?}", capture_clause);
+
+                let movability = if let Some(movability) = movability {
+                    format!("Some(Movability::{:?})", movability)
                 } else {
-                    println!("If(ref {}, ref {}, None) = {};", cond_pat, then_pat, current);
-                }
-                self.current = cond_pat;
-                self.visit_expr(cond);
-                self.current = then_pat;
-                self.visit_expr(then);
-            },
-            ExprKind::Match(expr, arms, des) => {
-                let expr_pat = self.next("expr");
-                let arms_pat = self.next("arms");
+                    String::from("None")
+                };
+
+                let ret_ty = match fn_decl.output {
+                    FnRetTy::DefaultReturn(_) => "FnRetTy::DefaultReturn(_)",
+                    FnRetTy::Return(_) => "FnRetTy::Return(_ty)",
+                };
+
+                let fn_decl_pat = self.next("fn_decl");
+                let body_id_pat = self.next("body_id");
+
                 println!(
-                    "Match(ref {}, ref {}, MatchSource::{:?}) = {};",
-                    expr_pat, arms_pat, des, current
+                    "Closure({}, ref {}, ref {}, _, {}) = {}",
+                    capture_by, fn_decl_pat, body_id_pat, movability, current
                 );
-                self.current = expr_pat;
-                self.visit_expr(expr);
-                println!("    if {}.len() == {};", arms_pat, arms.len());
-                for (i, arm) in arms.iter().enumerate() {
-                    self.current = format!("{}[{}].body", arms_pat, i);
-                    self.visit_expr(arm.body);
-                    if let Some(ref guard) = arm.guard {
-                        let guard_pat = self.next("guard");
-                        println!("    if let Some(ref {}) = {}[{}].guard;", guard_pat, arms_pat, i);
-                        match guard {
-                            hir::Guard::If(if_expr) => {
-                                let if_expr_pat = self.next("expr");
-                                println!("    if let Guard::If(ref {}) = {};", if_expr_pat, guard_pat);
-                                self.current = if_expr_pat;
-                                self.visit_expr(if_expr);
-                            },
-                            hir::Guard::IfLet(if_let_pat, if_let_expr) => {
-                                let if_let_pat_pat = self.next("pat");
-                                let if_let_expr_pat = self.next("expr");
-                                println!(
-                                    "    if let Guard::IfLet(ref {}, ref {}) = {};",
-                                    if_let_pat_pat, if_let_expr_pat, guard_pat
-                                );
-                                self.current = if_let_expr_pat;
-                                self.visit_expr(if_let_expr);
-                                self.current = if_let_pat_pat;
-                                self.visit_pat(if_let_pat);
-                            },
-                        }
-                    }
-                    self.current = format!("{}[{}].pat", arms_pat, i);
-                    self.visit_pat(arm.pat);
-                }
-            },
-            ExprKind::Closure(ref _capture_clause, _func, _, _, _) => {
-                println!("Closure(ref capture_clause, ref func, _, _, _) = {};", current);
-                println!("    // unimplemented: `ExprKind::Closure` is not further destructured at the moment");
+                println!("    if let {} = {}.output", ret_ty, fn_decl_pat);
+
+                let hir = self.cx.tcx.hir();
+                let body = hir.body(body_id);
+
+                let body_pat = self.next("body");
+
+                println!("    let {} = cx.tcx.hir().body({});", body_pat, body_id_pat);
+
+                self.current = format!("{}.value", body_pat);
+                self.visit_expr(&body.value);
             },
-            ExprKind::Yield(sub, _) => {
+            ExprKind::Yield(sub, source) => {
                 let sub_pat = self.next("sub");
-                println!("Yield(ref sub) = {};", current);
+
+                println!("Yield(ref sub, YieldSource::{:?}) = {};", source, current);
+
                 self.current = sub_pat;
                 self.visit_expr(sub);
             },
-            ExprKind::Block(block, _) => {
+            ExprKind::Block(block, label) => {
                 let block_pat = self.next("block");
-                println!("Block(ref {}) = {};", block_pat, current);
+                let label_pat = self.next("label");
+
+                println!("Block(ref {}, ref {}) = {};", block_pat, label_pat, current);
+
                 self.current = block_pat;
                 self.visit_block(block);
+
+                self.current = label_pat;
+                self.print_label(label);
             },
             ExprKind::Assign(target, value, _) => {
                 let target_pat = self.next("target");
                 let value_pat = self.next("value");
+
                 println!(
                     "Assign(ref {}, ref {}, ref _span) = {};",
                     target_pat, value_pat, current
                 );
+
                 self.current = target_pat;
                 self.visit_expr(target);
+
                 self.current = value_pat;
                 self.visit_expr(value);
             },
@@ -432,69 +680,91 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 let op_pat = self.next("op");
                 let target_pat = self.next("target");
                 let value_pat = self.next("value");
+
                 println!(
                     "AssignOp(ref {}, ref {}, ref {}) = {};",
                     op_pat, target_pat, value_pat, current
                 );
+
                 println!("    if BinOpKind::{:?} == {}.node;", op.node, op_pat);
+
                 self.current = target_pat;
                 self.visit_expr(target);
+
                 self.current = value_pat;
                 self.visit_expr(value);
             },
             ExprKind::Field(object, ref field_ident) => {
                 let obj_pat = self.next("object");
                 let field_name_pat = self.next("field_name");
+
                 println!("Field(ref {}, ref {}) = {};", obj_pat, field_name_pat, current);
                 println!("    if {}.as_str() == {:?}", field_name_pat, field_ident.as_str());
+
                 self.current = obj_pat;
                 self.visit_expr(object);
             },
             ExprKind::Index(object, index) => {
                 let object_pat = self.next("object");
                 let index_pat = self.next("index");
+
                 println!("Index(ref {}, ref {}) = {};", object_pat, index_pat, current);
+
                 self.current = object_pat;
                 self.visit_expr(object);
+
                 self.current = index_pat;
                 self.visit_expr(index);
             },
             ExprKind::Path(ref path) => {
                 let path_pat = self.next("path");
+
                 println!("Path(ref {}) = {};", path_pat, current);
+
                 self.current = path_pat;
                 self.print_qpath(path);
             },
             ExprKind::AddrOf(kind, mutability, inner) => {
                 let inner_pat = self.next("inner");
+
                 println!(
                     "AddrOf(BorrowKind::{:?}, Mutability::{:?}, ref {}) = {};",
                     kind, mutability, inner_pat, current
                 );
+
                 self.current = inner_pat;
                 self.visit_expr(inner);
             },
-            ExprKind::Break(ref _destination, ref opt_value) => {
+            ExprKind::Break(ref destination, ref opt_value) => {
                 let destination_pat = self.next("destination");
+
                 if let Some(value) = *opt_value {
                     let value_pat = self.next("value");
+
                     println!("Break(ref {}, Some(ref {})) = {};", destination_pat, value_pat, current);
+
                     self.current = value_pat;
                     self.visit_expr(value);
                 } else {
                     println!("Break(ref {}, None) = {};", destination_pat, current);
                 }
-                // FIXME: implement label printing
+
+                self.current = format!("{}.label", destination_pat);
+                self.print_label(destination.label);
             },
-            ExprKind::Continue(ref _destination) => {
+            ExprKind::Continue(ref destination) => {
                 let destination_pat = self.next("destination");
-                println!("Again(ref {}) = {};", destination_pat, current);
-                // FIXME: implement label printing
+                println!("Continue(ref {}) = {};", destination_pat, current);
+
+                self.current = format!("{}.label", destination_pat);
+                self.print_label(destination.label);
             },
             ExprKind::Ret(ref opt_value) => {
                 if let Some(value) = *opt_value {
                     let value_pat = self.next("value");
+
                     println!("Ret(Some(ref {})) = {};", value_pat, current);
+
                     self.current = value_pat;
                     self.visit_expr(value);
                 } else {
@@ -512,41 +782,66 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
             ExprKind::Struct(path, fields, ref opt_base) => {
                 let path_pat = self.next("path");
                 let fields_pat = self.next("fields");
+
                 if let Some(base) = *opt_base {
                     let base_pat = self.next("base");
+
                     println!(
                         "Struct(ref {}, ref {}, Some(ref {})) = {};",
                         path_pat, fields_pat, base_pat, current
                     );
+
                     self.current = base_pat;
                     self.visit_expr(base);
                 } else {
                     println!("Struct(ref {}, ref {}, None) = {};", path_pat, fields_pat, current);
                 }
+
                 self.current = path_pat;
                 self.print_qpath(path);
+
                 println!("    if {}.len() == {};", fields_pat, fields.len());
-                println!("    // unimplemented: field checks");
+
+                for (i, field) in fields.iter().enumerate() {
+                    println!(
+                        "    if {}[{}].ident.name.as_str() == {:?}",
+                        fields_pat,
+                        i,
+                        &*field.ident.name.as_str()
+                    );
+
+                    self.current = format!("{}[{}]", fields_pat, i);
+                    self.visit_expr(field.expr);
+                }
             },
             ExprKind::ConstBlock(_) => {
                 let value_pat = self.next("value");
-                println!("Const({})", value_pat);
+                println!("Const({}) = {}", value_pat, current);
                 self.current = value_pat;
             },
-            // FIXME: compute length (needs type info)
-            ExprKind::Repeat(value, _) => {
+            ExprKind::Repeat(value, length) => {
                 let value_pat = self.next("value");
-                println!("Repeat(ref {}, _) = {};", value_pat, current);
-                println!("// unimplemented: repeat count check");
+                let length_pat = self.next("length");
+
+                println!("Repeat(ref {}, ref {}) = {};", value_pat, length_pat, current);
+
                 self.current = value_pat;
                 self.visit_expr(value);
+
+                let hir = self.cx.tcx.hir();
+                let body = hir.body(length.body);
+
+                self.current = format!("{}.value", length_pat);
+                self.visit_expr(&body.value);
             },
             ExprKind::Err => {
                 println!("Err = {}", current);
             },
             ExprKind::DropTemps(expr) => {
                 let expr_pat = self.next("expr");
+
                 println!("DropTemps(ref {}) = {};", expr_pat, current);
+
                 self.current = expr_pat;
                 self.visit_expr(expr);
             },
@@ -555,11 +850,14 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
 
     fn visit_block(&mut self, block: &Block<'_>) {
         println!("    if {}.stmts.len() == {};", self.current, block.stmts.len());
+
         let block_name = self.current.clone();
+
         for (i, stmt) in block.stmts.iter().enumerate() {
             self.current = format!("{}.stmts[{}]", block_name, i);
             self.visit_stmt(stmt);
         }
+
         if let Some(expr) = block.expr {
             self.current = self.next("trailing_expr");
             println!("    if let Some({}) = &{}.expr;", self.current, block_name);
@@ -573,22 +871,27 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
     fn visit_pat(&mut self, pat: &Pat<'_>) {
         print!("    if let PatKind::");
         let current = format!("{}.kind", self.current);
+
         match pat.kind {
             PatKind::Wild => println!("Wild = {};", current),
             PatKind::Binding(anno, .., ident, ref sub) => {
                 let anno_pat = &format!("BindingAnnotation::{:?}", anno);
                 let name_pat = self.next("name");
+
                 if let Some(sub) = *sub {
                     let sub_pat = self.next("sub");
+
                     println!(
                         "Binding({}, _, {}, Some(ref {})) = {};",
                         anno_pat, name_pat, sub_pat, current
                     );
+
                     self.current = sub_pat;
                     self.visit_pat(sub);
                 } else {
                     println!("Binding({}, _, {}, None) = {};", anno_pat, name_pat, current);
                 }
+
                 println!("    if {}.as_str() == \"{}\";", name_pat, ident.as_str());
             },
             PatKind::Struct(ref path, fields, ignore) => {
@@ -598,32 +901,57 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                     "Struct(ref {}, ref {}, {}) = {};",
                     path_pat, fields_pat, ignore, current
                 );
+
                 self.current = path_pat;
                 self.print_qpath(path);
+
                 println!("    if {}.len() == {};", fields_pat, fields.len());
-                println!("    // unimplemented: field checks");
+
+                for (i, field) in fields.iter().enumerate() {
+                    println!(
+                        "    if {}[{}].ident.name.as_str() == {:?}",
+                        fields_pat,
+                        i,
+                        &*field.ident.name.as_str()
+                    );
+
+                    self.current = format!("{}[{}]", fields_pat, i);
+                    self.visit_pat(field.pat);
+                }
             },
             PatKind::Or(fields) => {
                 let fields_pat = self.next("fields");
                 println!("Or(ref {}) = {};", fields_pat, current);
                 println!("    if {}.len() == {};", fields_pat, fields.len());
-                println!("    // unimplemented: field checks");
+
+                for (i, field) in fields.iter().enumerate() {
+                    self.current = format!("{}[{}]", fields_pat, i);
+                    self.visit_pat(field);
+                }
             },
             PatKind::TupleStruct(ref path, fields, skip_pos) => {
                 let path_pat = self.next("path");
                 let fields_pat = self.next("fields");
+
                 println!(
                     "TupleStruct(ref {}, ref {}, {:?}) = {};",
                     path_pat, fields_pat, skip_pos, current
                 );
+
                 self.current = path_pat;
                 self.print_qpath(path);
+
                 println!("    if {}.len() == {};", fields_pat, fields.len());
-                println!("    // unimplemented: field checks");
+
+                for (i, field) in fields.iter().enumerate() {
+                    self.current = format!("{}[{}]", fields_pat, i);
+                    self.visit_pat(field);
+                }
             },
             PatKind::Path(ref path) => {
                 let path_pat = self.next("path");
                 println!("Path(ref {}) = {};", path_pat, current);
+
                 self.current = path_pat;
                 self.print_qpath(path);
             },
@@ -631,41 +959,52 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 let fields_pat = self.next("fields");
                 println!("Tuple(ref {}, {:?}) = {};", fields_pat, skip_pos, current);
                 println!("    if {}.len() == {};", fields_pat, fields.len());
-                println!("    // unimplemented: field checks");
+
+                for (i, field) in fields.iter().enumerate() {
+                    self.current = format!("{}[{}]", fields_pat, i);
+                    self.visit_pat(field);
+                }
             },
             PatKind::Box(pat) => {
                 let pat_pat = self.next("pat");
                 println!("Box(ref {}) = {};", pat_pat, current);
+
                 self.current = pat_pat;
                 self.visit_pat(pat);
             },
             PatKind::Ref(pat, muta) => {
                 let pat_pat = self.next("pat");
                 println!("Ref(ref {}, Mutability::{:?}) = {};", pat_pat, muta, current);
+
                 self.current = pat_pat;
                 self.visit_pat(pat);
             },
             PatKind::Lit(lit_expr) => {
                 let lit_expr_pat = self.next("lit_expr");
                 println!("Lit(ref {}) = {}", lit_expr_pat, current);
+
                 self.current = lit_expr_pat;
                 self.visit_expr(lit_expr);
             },
             PatKind::Range(ref start, ref end, end_kind) => {
                 let start_pat = self.next("start");
                 let end_pat = self.next("end");
+
                 println!(
                     "Range(ref {}, ref {}, RangeEnd::{:?}) = {};",
                     start_pat, end_pat, end_kind, current
                 );
+
                 self.current = start_pat;
                 walk_list!(self, visit_expr, start);
+
                 self.current = end_pat;
                 walk_list!(self, visit_expr, end);
             },
             PatKind::Slice(start, ref middle, end) => {
                 let start_pat = self.next("start");
                 let end_pat = self.next("end");
+
                 if let Some(middle) = middle {
                     let middle_pat = self.next("middle");
                     println!(
@@ -677,12 +1016,16 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                 } else {
                     println!("Slice(ref {}, None, ref {}) = {};", start_pat, end_pat, current);
                 }
+
                 println!("    if {}.len() == {};", start_pat, start.len());
+
                 for (i, pat) in start.iter().enumerate() {
                     self.current = format!("{}[{}]", start_pat, i);
                     self.visit_pat(pat);
                 }
+
                 println!("    if {}.len() == {};", end_pat, end.len());
+
                 for (i, pat) in end.iter().enumerate() {
                     self.current = format!("{}[{}]", end_pat, i);
                     self.visit_pat(pat);
@@ -694,17 +1037,21 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
     fn visit_stmt(&mut self, s: &Stmt<'_>) {
         print!("    if let StmtKind::");
         let current = format!("{}.kind", self.current);
+
         match s.kind {
             // A local (let) binding:
             StmtKind::Local(local) => {
                 let local_pat = self.next("local");
                 println!("Local(ref {}) = {};", local_pat, current);
+
                 if let Some(init) = local.init {
                     let init_pat = self.next("init");
                     println!("    if let Some(ref {}) = {}.init;", init_pat, local_pat);
+
                     self.current = init_pat;
                     self.visit_expr(init);
                 }
+
                 self.current = format!("{}.pat", local_pat);
                 self.visit_pat(local.pat);
             },
@@ -717,6 +1064,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
             StmtKind::Expr(e) => {
                 let e_pat = self.next("e");
                 println!("Expr(ref {}, _) = {}", e_pat, current);
+
                 self.current = e_pat;
                 self.visit_expr(e);
             },
@@ -725,6 +1073,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
             StmtKind::Semi(e) => {
                 let e_pat = self.next("e");
                 println!("Semi(ref {}, _) = {}", e_pat, current);
+
                 self.current = e_pat;
                 self.visit_expr(e);
             },
diff --git a/tests/ui/author.stdout b/tests/ui/author.stdout
index 211d11c7c1a..313597bf534 100644
--- a/tests/ui/author.stdout
+++ b/tests/ui/author.stdout
@@ -5,7 +5,7 @@ if_chain! {
     if let TyKind::Path(ref qp) = cast_ty.kind;
     if match_qpath(qp, &["char"]);
     if let ExprKind::Lit(ref lit) = expr.kind;
-    if let LitKind::Int(69, _) = lit.node;
+    if let LitKind::Int(69, LitIntType::Unsuffixed) = lit.node;
     if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
     if name.as_str() == "x";
     then {
diff --git a/tests/ui/author/blocks.rs b/tests/ui/author/blocks.rs
index c8465cd59aa..a7335c01baa 100644
--- a/tests/ui/author/blocks.rs
+++ b/tests/ui/author/blocks.rs
@@ -1,10 +1,16 @@
+// edition:2018
+
 #![allow(redundant_semicolons, clippy::no_effect)]
+#![feature(stmt_expr_attributes)]
+#![feature(async_closure)]
 
 #[rustfmt::skip]
 fn main() {
     #[clippy::author]
     {
         let x = 42i32;
+        let _t = 1f32;
+
         -x;
     };
     #[clippy::author]
@@ -12,4 +18,7 @@ fn main() {
         let expr = String::new();
         drop(expr)
     };
+
+    #[clippy::author]
+    async move || {};
 }
diff --git a/tests/ui/author/blocks.stdout b/tests/ui/author/blocks.stdout
index 854bc28083a..31c7fced7f7 100644
--- a/tests/ui/author/blocks.stdout
+++ b/tests/ui/author/blocks.stdout
@@ -1,13 +1,19 @@
 if_chain! {
-    if let ExprKind::Block(ref block) = expr.kind;
-    if block.stmts.len() == 2;
+    if let ExprKind::Block(ref block, ref label) = expr.kind;
+    if block.stmts.len() == 3;
     if let StmtKind::Local(ref local) = block.stmts[0].kind;
     if let Some(ref init) = local.init;
     if let ExprKind::Lit(ref lit) = init.kind;
-    if let LitKind::Int(42, _) = lit.node;
+    if let LitKind::Int(42, LitIntType::Signed(IntTy::I32)) = lit.node;
     if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local.pat.kind;
     if name.as_str() == "x";
-    if let StmtKind::Semi(ref e, _) = block.stmts[1].kind
+    if let StmtKind::Local(ref local1) = block.stmts[1].kind;
+    if let Some(ref init1) = local1.init;
+    if let ExprKind::Lit(ref lit1) = init1.kind;
+    if let LitKind::Float(_, LitFloatType::Suffixed(FloatTy::F32)) = lit1.node;
+    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind;
+    if name1.as_str() == "_t";
+    if let StmtKind::Semi(ref e, _) = block.stmts[2].kind
     if let ExprKind::Unary(UnOp::Neg, ref inner) = e.kind;
     if let ExprKind::Path(ref path) = inner.kind;
     if match_qpath(path, &["x"]);
@@ -17,7 +23,7 @@ if_chain! {
     }
 }
 if_chain! {
-    if let ExprKind::Block(ref block) = expr.kind;
+    if let ExprKind::Block(ref block, ref label) = expr.kind;
     if block.stmts.len() == 1;
     if let StmtKind::Local(ref local) = block.stmts[0].kind;
     if let Some(ref init) = local.init;
@@ -38,3 +44,21 @@ if_chain! {
         // report your lint here
     }
 }
+if_chain! {
+    if let ExprKind::Closure(CaptureBy::Value, ref fn_decl, ref body_id, _, None) = expr.kind
+    if let FnRetTy::DefaultReturn(_) = fn_decl.output
+    let body = cx.tcx.hir().body(body_id);
+    if let ExprKind::Call(ref func, ref args) = body.value.kind;
+    if let ExprKind::Path(ref path) = func.kind;
+    if matches!(path, QPath::LangItem(LangItem::FromGenerator, _));
+    if args.len() == 1;
+    if let ExprKind::Closure(CaptureBy::Value, ref fn_decl1, ref body_id1, _, Some(Movability::Static)) = args[0].kind
+    if let FnRetTy::DefaultReturn(_) = fn_decl1.output
+    let body1 = cx.tcx.hir().body(body_id1);
+    if let ExprKind::Block(ref block, ref label) = body1.value.kind;
+    if block.stmts.len() == 0;
+    if block.expr.is_none();
+    then {
+        // report your lint here
+    }
+}
diff --git a/tests/ui/author/call.stdout b/tests/ui/author/call.stdout
index 4dccf666631..07958dbc356 100644
--- a/tests/ui/author/call.stdout
+++ b/tests/ui/author/call.stdout
@@ -6,9 +6,9 @@ if_chain! {
     if match_qpath(path, &["{{root}}", "std", "cmp", "min"]);
     if args.len() == 2;
     if let ExprKind::Lit(ref lit) = args[0].kind;
-    if let LitKind::Int(3, _) = lit.node;
+    if let LitKind::Int(3, LitIntType::Unsuffixed) = lit.node;
     if let ExprKind::Lit(ref lit1) = args[1].kind;
-    if let LitKind::Int(4, _) = lit1.node;
+    if let LitKind::Int(4, LitIntType::Unsuffixed) = lit1.node;
     if let PatKind::Wild = local.pat.kind;
     then {
         // report your lint here
diff --git a/tests/ui/author/for_loop.rs b/tests/ui/author/for_loop.rs
deleted file mode 100644
index b3dec876535..00000000000
--- a/tests/ui/author/for_loop.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(stmt_expr_attributes)]
-
-fn main() {
-    #[clippy::author]
-    for y in 0..10 {
-        let z = y;
-    }
-}
diff --git a/tests/ui/author/for_loop.stdout b/tests/ui/author/for_loop.stdout
deleted file mode 100644
index f1b4d4e096e..00000000000
--- a/tests/ui/author/for_loop.stdout
+++ /dev/null
@@ -1,64 +0,0 @@
-if_chain! {
-    if let ExprKind::DropTemps(ref expr) = expr.kind;
-    if let ExprKind::Match(ref expr1, ref arms, MatchSource::ForLoopDesugar) = expr.kind;
-    if let ExprKind::Call(ref func, ref args) = expr1.kind;
-    if let ExprKind::Path(ref path) = func.kind;
-    if matches!(path, QPath::LangItem(LangItem::IntoIterIntoIter, _));
-    if args.len() == 1;
-    if let ExprKind::Struct(ref path1, ref fields, None) = args[0].kind;
-    if matches!(path1, QPath::LangItem(LangItem::Range, _));
-    if fields.len() == 2;
-    // unimplemented: field checks
-    if arms.len() == 1;
-    if let ExprKind::Loop(ref body, ref label, LoopSource::ForLoop) = arms[0].body.kind;
-    if body.stmts.len() == 4;
-    if let StmtKind::Local(ref local) = body.stmts[0].kind;
-    if let PatKind::Binding(BindingAnnotation::Mutable, _, name, None) = local.pat.kind;
-    if name.as_str() == "__next";
-    if let StmtKind::Expr(ref e, _) = body.stmts[1].kind
-    if let ExprKind::Match(ref expr2, ref arms1, MatchSource::ForLoopDesugar) = e.kind;
-    if let ExprKind::Call(ref func1, ref args1) = expr2.kind;
-    if let ExprKind::Path(ref path2) = func1.kind;
-    if matches!(path2, QPath::LangItem(LangItem::IteratorNext, _));
-    if args1.len() == 1;
-    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, ref inner) = args1[0].kind;
-    if let ExprKind::Path(ref path3) = inner.kind;
-    if match_qpath(path3, &["iter"]);
-    if arms1.len() == 2;
-    if let ExprKind::Assign(ref target, ref value, ref _span) = arms1[0].body.kind;
-    if let ExprKind::Path(ref path4) = target.kind;
-    if match_qpath(path4, &["__next"]);
-    if let ExprKind::Path(ref path5) = value.kind;
-    if match_qpath(path5, &["val"]);
-    if let PatKind::Struct(ref path6, ref fields1, false) = arms1[0].pat.kind;
-    if matches!(path6, QPath::LangItem(LangItem::OptionSome, _));
-    if fields1.len() == 1;
-    // unimplemented: field checks
-    if let ExprKind::Break(ref destination, None) = arms1[1].body.kind;
-    if let PatKind::Struct(ref path7, ref fields2, false) = arms1[1].pat.kind;
-    if matches!(path7, QPath::LangItem(LangItem::OptionNone, _));
-    if fields2.len() == 0;
-    // unimplemented: field checks
-    if let StmtKind::Local(ref local1) = body.stmts[2].kind;
-    if let Some(ref init) = local1.init;
-    if let ExprKind::Path(ref path8) = init.kind;
-    if match_qpath(path8, &["__next"]);
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local1.pat.kind;
-    if name1.as_str() == "y";
-    if let StmtKind::Expr(ref e1, _) = body.stmts[3].kind
-    if let ExprKind::Block(ref block) = e1.kind;
-    if block.stmts.len() == 1;
-    if let StmtKind::Local(ref local2) = block.stmts[0].kind;
-    if let Some(ref init1) = local2.init;
-    if let ExprKind::Path(ref path9) = init1.kind;
-    if match_qpath(path9, &["y"]);
-    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name2, None) = local2.pat.kind;
-    if name2.as_str() == "z";
-    if block.expr.is_none();
-    if body.expr.is_none();
-    if let PatKind::Binding(BindingAnnotation::Mutable, _, name3, None) = arms[0].pat.kind;
-    if name3.as_str() == "iter";
-    then {
-        // report your lint here
-    }
-}
diff --git a/tests/ui/author/if.rs b/tests/ui/author/if.rs
index 2e9cb1466d0..946088ab346 100644
--- a/tests/ui/author/if.rs
+++ b/tests/ui/author/if.rs
@@ -7,4 +7,11 @@ fn main() {
     } else {
         2 == 2;
     };
+
+    let a = true;
+
+    #[clippy::author]
+    if let true = a {
+    } else {
+    };
 }
diff --git a/tests/ui/author/if.stdout b/tests/ui/author/if.stdout
index 1653de9a6f2..7e72a548011 100644
--- a/tests/ui/author/if.stdout
+++ b/tests/ui/author/if.stdout
@@ -1,32 +1,48 @@
 if_chain! {
     if let StmtKind::Local(ref local) = stmt.kind;
     if let Some(ref init) = local.init;
-    if let ExprKind::If(ref cond, ref then, Some(ref else_)) = init.kind;
-    if let ExprKind::Block(ref block) = else_.kind;
+    if let Some(higher::If { cond: cond, then: then, r#else: else_expr}) = higher::If::hir(init)
+    if let ExprKind::Lit(ref lit) = cond.kind;
+    if let LitKind::Bool(true) = lit.node;
+    if let ExprKind::Block(ref block, ref label) = then.kind;
     if block.stmts.len() == 1;
     if let StmtKind::Semi(ref e, _) = block.stmts[0].kind
     if let ExprKind::Binary(ref op, ref left, ref right) = e.kind;
     if BinOpKind::Eq == op.node;
-    if let ExprKind::Lit(ref lit) = left.kind;
-    if let LitKind::Int(2, _) = lit.node;
-    if let ExprKind::Lit(ref lit1) = right.kind;
-    if let LitKind::Int(2, _) = lit1.node;
+    if let ExprKind::Lit(ref lit1) = left.kind;
+    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node;
+    if let ExprKind::Lit(ref lit2) = right.kind;
+    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit2.node;
     if block.expr.is_none();
-    if let ExprKind::DropTemps(ref expr) = cond.kind;
-    if let ExprKind::Lit(ref lit2) = expr.kind;
-    if let LitKind::Bool(true) = lit2.node;
-    if let ExprKind::Block(ref block1) = then.kind;
+    if let ExprKind::Block(ref block1, ref label1) = else_expr.kind;
     if block1.stmts.len() == 1;
     if let StmtKind::Semi(ref e1, _) = block1.stmts[0].kind
     if let ExprKind::Binary(ref op1, ref left1, ref right1) = e1.kind;
     if BinOpKind::Eq == op1.node;
     if let ExprKind::Lit(ref lit3) = left1.kind;
-    if let LitKind::Int(1, _) = lit3.node;
+    if let LitKind::Int(2, LitIntType::Unsuffixed) = lit3.node;
     if let ExprKind::Lit(ref lit4) = right1.kind;
-    if let LitKind::Int(1, _) = lit4.node;
+    if let LitKind::Int(2, LitIntType::Unsuffixed) = lit4.node;
     if block1.expr.is_none();
     if let PatKind::Wild = local.pat.kind;
     then {
         // report your lint here
     }
 }
+if_chain! {
+    if let Some(higher::IfLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then, if_else: else_expr}) = higher::IfLet::hir(expr)
+    if let PatKind::Lit(ref lit_expr) = let_pat.kind
+    if let ExprKind::Lit(ref lit) = lit_expr.kind;
+    if let LitKind::Bool(true) = lit.node;
+    if let ExprKind::Path(ref path) = let_expr.kind;
+    if match_qpath(path, &["a"]);
+    if let ExprKind::Block(ref block, ref label) = if_then.kind;
+    if block.stmts.len() == 0;
+    if block.expr.is_none();
+    if let ExprKind::Block(ref block1, ref label1) = else_expr.kind;
+    if block1.stmts.len() == 0;
+    if block1.expr.is_none();
+    then {
+        // report your lint here
+    }
+}
diff --git a/tests/ui/author/loop.rs b/tests/ui/author/loop.rs
new file mode 100644
index 00000000000..d6de21631e2
--- /dev/null
+++ b/tests/ui/author/loop.rs
@@ -0,0 +1,36 @@
+#![feature(stmt_expr_attributes)]
+#![allow(clippy::never_loop, clippy::while_immutable_condition)]
+
+fn main() {
+    #[clippy::author]
+    for y in 0..10 {
+        let z = y;
+    }
+
+    #[clippy::author]
+    for _ in 0..10 {
+        break;
+    }
+
+    #[clippy::author]
+    'label: for _ in 0..10 {
+        break 'label;
+    }
+
+    let a = true;
+
+    #[clippy::author]
+    while a {
+        break;
+    }
+
+    #[clippy::author]
+    while let true = a {
+        break;
+    }
+
+    #[clippy::author]
+    loop {
+        break;
+    }
+}
diff --git a/tests/ui/author/loop.stdout b/tests/ui/author/loop.stdout
new file mode 100644
index 00000000000..fa146f03495
--- /dev/null
+++ b/tests/ui/author/loop.stdout
@@ -0,0 +1,112 @@
+if_chain! {
+    if let ExprKind::DropTemps(ref expr) = expr.kind;
+    if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, ..}) = higher::ForLoop::hir(expr)
+    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = pat.kind;
+    if name.as_str() == "y";
+    if let ExprKind::Struct(ref path, ref fields, None) = arg.kind;
+    if matches!(path, QPath::LangItem(LangItem::Range, _));
+    if fields.len() == 2;
+    if fields[0].ident.name.as_str() == "start"
+    if let ExprKind::Lit(ref lit) = fields[0].kind;
+    if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
+    if fields[1].ident.name.as_str() == "end"
+    if let ExprKind::Lit(ref lit1) = fields[1].kind;
+    if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
+    if let ExprKind::Block(ref block, ref label) = body.kind;
+    if block.stmts.len() == 1;
+    if let StmtKind::Local(ref local) = block.stmts[0].kind;
+    if let Some(ref init) = local.init;
+    if let ExprKind::Path(ref path1) = init.kind;
+    if match_qpath(path1, &["y"]);
+    if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
+    if name1.as_str() == "z";
+    if block.expr.is_none();
+    then {
+        // report your lint here
+    }
+}
+if_chain! {
+    if let ExprKind::DropTemps(ref expr) = expr.kind;
+    if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, ..}) = higher::ForLoop::hir(expr)
+    if let PatKind::Wild = pat.kind;
+    if let ExprKind::Struct(ref path, ref fields, None) = arg.kind;
+    if matches!(path, QPath::LangItem(LangItem::Range, _));
+    if fields.len() == 2;
+    if fields[0].ident.name.as_str() == "start"
+    if let ExprKind::Lit(ref lit) = fields[0].kind;
+    if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
+    if fields[1].ident.name.as_str() == "end"
+    if let ExprKind::Lit(ref lit1) = fields[1].kind;
+    if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
+    if let ExprKind::Block(ref block, ref label) = body.kind;
+    if block.stmts.len() == 1;
+    if let StmtKind::Semi(ref e, _) = block.stmts[0].kind
+    if let ExprKind::Break(ref destination, None) = e.kind;
+    if block.expr.is_none();
+    then {
+        // report your lint here
+    }
+}
+if_chain! {
+    if let ExprKind::DropTemps(ref expr) = expr.kind;
+    if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, ..}) = higher::ForLoop::hir(expr)
+    if let PatKind::Wild = pat.kind;
+    if let ExprKind::Struct(ref path, ref fields, None) = arg.kind;
+    if matches!(path, QPath::LangItem(LangItem::Range, _));
+    if fields.len() == 2;
+    if fields[0].ident.name.as_str() == "start"
+    if let ExprKind::Lit(ref lit) = fields[0].kind;
+    if let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node;
+    if fields[1].ident.name.as_str() == "end"
+    if let ExprKind::Lit(ref lit1) = fields[1].kind;
+    if let LitKind::Int(10, LitIntType::Unsuffixed) = lit1.node;
+    if let ExprKind::Block(ref block, ref label) = body.kind;
+    if block.stmts.len() == 1;
+    if let StmtKind::Semi(ref e, _) = block.stmts[0].kind
+    if let ExprKind::Break(ref destination, None) = e.kind;
+    if let Some(ref label1) = destination.label
+    if label_name.ident.name.as_str() == "'label";
+    if block.expr.is_none();
+    then {
+        // report your lint here
+    }
+}
+if_chain! {
+    if let Some(higher::While { condition: condition, body: body }) = higher::While::hir(expr)
+    if let ExprKind::Path(ref path) = condition.kind;
+    if match_qpath(path, &["a"]);
+    if let ExprKind::Block(ref block, ref label) = body.kind;
+    if block.stmts.len() == 1;
+    if let StmtKind::Semi(ref e, _) = block.stmts[0].kind
+    if let ExprKind::Break(ref destination, None) = e.kind;
+    if block.expr.is_none();
+    then {
+        // report your lint here
+    }
+}
+if_chain! {
+    if let Some(higher::WhileLet { let_pat: let_pat, let_expr: let_expr, if_then: if_then }) = higher::WhileLet::hir(expr)
+    if let PatKind::Lit(ref lit_expr) = let_pat.kind
+    if let ExprKind::Lit(ref lit) = lit_expr.kind;
+    if let LitKind::Bool(true) = lit.node;
+    if let ExprKind::Path(ref path) = let_expr.kind;
+    if match_qpath(path, &["a"]);
+    if let ExprKind::Block(ref block, ref label) = if_then.kind;
+    if block.stmts.len() == 1;
+    if let StmtKind::Semi(ref e, _) = block.stmts[0].kind
+    if let ExprKind::Break(ref destination, None) = e.kind;
+    if block.expr.is_none();
+    then {
+        // report your lint here
+    }
+}
+if_chain! {
+    if let ExprKind::Loop(ref body, ref label, LoopSource::Loop) = expr.kind;
+    if body.stmts.len() == 1;
+    if let StmtKind::Semi(ref e, _) = body.stmts[0].kind
+    if let ExprKind::Break(ref destination, None) = e.kind;
+    if body.expr.is_none();
+    then {
+        // report your lint here
+    }
+}
diff --git a/tests/ui/author/matches.stdout b/tests/ui/author/matches.stdout
index 68cc2b214eb..3be61fe3772 100644
--- a/tests/ui/author/matches.stdout
+++ b/tests/ui/author/matches.stdout
@@ -3,19 +3,19 @@ if_chain! {
     if let Some(ref init) = local.init;
     if let ExprKind::Match(ref expr, ref arms, MatchSource::Normal) = init.kind;
     if let ExprKind::Lit(ref lit) = expr.kind;
-    if let LitKind::Int(42, _) = lit.node;
+    if let LitKind::Int(42, LitIntType::Unsuffixed) = lit.node;
     if arms.len() == 3;
     if let ExprKind::Lit(ref lit1) = arms[0].body.kind;
-    if let LitKind::Int(5, _) = lit1.node;
+    if let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node;
     if let PatKind::Lit(ref lit_expr) = arms[0].pat.kind
     if let ExprKind::Lit(ref lit2) = lit_expr.kind;
-    if let LitKind::Int(16, _) = lit2.node;
-    if let ExprKind::Block(ref block) = arms[1].body.kind;
+    if let LitKind::Int(16, LitIntType::Unsuffixed) = lit2.node;
+    if let ExprKind::Block(ref block, ref label) = arms[1].body.kind;
     if block.stmts.len() == 1;
     if let StmtKind::Local(ref local1) = block.stmts[0].kind;
     if let Some(ref init1) = local1.init;
     if let ExprKind::Lit(ref lit3) = init1.kind;
-    if let LitKind::Int(3, _) = lit3.node;
+    if let LitKind::Int(3, LitIntType::Unsuffixed) = lit3.node;
     if let PatKind::Binding(BindingAnnotation::Unannotated, _, name, None) = local1.pat.kind;
     if name.as_str() == "x";
     if let Some(trailing_expr) = &block.expr;
@@ -23,9 +23,9 @@ if_chain! {
     if match_qpath(path, &["x"]);
     if let PatKind::Lit(ref lit_expr1) = arms[1].pat.kind
     if let ExprKind::Lit(ref lit4) = lit_expr1.kind;
-    if let LitKind::Int(17, _) = lit4.node;
+    if let LitKind::Int(17, LitIntType::Unsuffixed) = lit4.node;
     if let ExprKind::Lit(ref lit5) = arms[2].body.kind;
-    if let LitKind::Int(1, _) = lit5.node;
+    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit5.node;
     if let PatKind::Wild = arms[2].pat.kind;
     if let PatKind::Binding(BindingAnnotation::Unannotated, _, name1, None) = local.pat.kind;
     if name1.as_str() == "a";
diff --git a/tests/ui/author/repeat.rs b/tests/ui/author/repeat.rs
new file mode 100644
index 00000000000..d8e9d589e68
--- /dev/null
+++ b/tests/ui/author/repeat.rs
@@ -0,0 +1,5 @@
+#[allow(clippy::no_effect)]
+fn main() {
+    #[clippy::author]
+    [1_u8; 5];
+}
diff --git a/tests/ui/author/repeat.stdout b/tests/ui/author/repeat.stdout
new file mode 100644
index 00000000000..9ff376373e6
--- /dev/null
+++ b/tests/ui/author/repeat.stdout
@@ -0,0 +1,10 @@
+if_chain! {
+    if let ExprKind::Repeat(ref value, ref length) = expr.kind;
+    if let ExprKind::Lit(ref lit) = value.kind;
+    if let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node;
+    if let ExprKind::Lit(ref lit1) = length.value.kind;
+    if let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node;
+    then {
+        // report your lint here
+    }
+}
diff --git a/tests/ui/author/struct.rs b/tests/ui/author/struct.rs
new file mode 100644
index 00000000000..5fdf3433a37
--- /dev/null
+++ b/tests/ui/author/struct.rs
@@ -0,0 +1,40 @@
+#[allow(clippy::unnecessary_operation, clippy::single_match)]
+fn main() {
+    struct Test {
+        field: u32,
+    }
+
+    #[clippy::author]
+    Test {
+        field: if true { 1 } else { 0 },
+    };
+
+    let test = Test { field: 1 };
+
+    match test {
+        #[clippy::author]
+        Test { field: 1 } => {},
+        _ => {},
+    }
+
+    struct TestTuple(u32);
+
+    let test_tuple = TestTuple(1);
+
+    match test_tuple {
+        #[clippy::author]
+        TestTuple(1) => {},
+        _ => {},
+    }
+
+    struct TestMethodCall(u32);
+
+    impl TestMethodCall {
+        fn test(&self) {}
+    }
+
+    let test_method_call = TestMethodCall(1);
+
+    #[clippy::author]
+    test_method_call.test();
+}
diff --git a/tests/ui/author/struct.stdout b/tests/ui/author/struct.stdout
new file mode 100644
index 00000000000..98055d73779
--- /dev/null
+++ b/tests/ui/author/struct.stdout
@@ -0,0 +1,61 @@
+if_chain! {
+    if let ExprKind::Struct(ref path, ref fields, None) = expr.kind;
+    if match_qpath(path, &["Test"]);
+    if fields.len() == 1;
+    if fields[0].ident.name.as_str() == "field"
+    if let Some(higher::If { cond: cond, then: then, r#else: else_expr}) = higher::If::hir(fields[0])
+    if let ExprKind::Lit(ref lit) = cond.kind;
+    if let LitKind::Bool(true) = lit.node;
+    if let ExprKind::Block(ref block, ref label) = then.kind;
+    if block.stmts.len() == 0;
+    if let Some(trailing_expr) = &block.expr;
+    if let ExprKind::Lit(ref lit1) = trailing_expr.kind;
+    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node;
+    if let ExprKind::Block(ref block1, ref label1) = else_expr.kind;
+    if block1.stmts.len() == 0;
+    if let Some(trailing_expr1) = &block1.expr;
+    if let ExprKind::Lit(ref lit2) = trailing_expr1.kind;
+    if let LitKind::Int(0, LitIntType::Unsuffixed) = lit2.node;
+    then {
+        // report your lint here
+    }
+}
+if_chain! {
+    if let PatKind::Struct(ref path, ref fields, false) = arm.kind;
+    if match_qpath(path, &["Test"]);
+    if fields.len() == 1;
+    if fields[0].ident.name.as_str() == "field"
+    if let PatKind::Lit(ref lit_expr) = fields[0].kind
+    if let ExprKind::Lit(ref lit) = lit_expr.kind;
+    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
+    if let ExprKind::Block(ref block, ref label) = lit_expr.kind;
+    if block.stmts.len() == 0;
+    if block.expr.is_none();
+    then {
+        // report your lint here
+    }
+}
+if_chain! {
+    if let PatKind::TupleStruct(ref path, ref fields, None) = arm.kind;
+    if match_qpath(path, &["TestTuple"]);
+    if fields.len() == 1;
+    if let PatKind::Lit(ref lit_expr) = fields[0].kind
+    if let ExprKind::Lit(ref lit) = lit_expr.kind;
+    if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node;
+    if let ExprKind::Block(ref block, ref label) = lit_expr.kind;
+    if block.stmts.len() == 0;
+    if block.expr.is_none();
+    then {
+        // report your lint here
+    }
+}
+if_chain! {
+    if let ExprKind::MethodCall(ref method_name, ref args, _) = expr.kind;
+    if method_name.ident.name.as_str() == test;
+    if args.len() == 1;
+    if let ExprKind::Path(ref path) = args[0].kind;
+    if match_qpath(path, &["test_method_call"]);
+    then {
+        // report your lint here
+    }
+}