diff options
| -rw-r--r-- | clippy_lints/src/utils/author.rs | 611 | ||||
| -rw-r--r-- | tests/ui/author.stdout | 2 | ||||
| -rw-r--r-- | tests/ui/author/blocks.rs | 9 | ||||
| -rw-r--r-- | tests/ui/author/blocks.stdout | 34 | ||||
| -rw-r--r-- | tests/ui/author/call.stdout | 4 | ||||
| -rw-r--r-- | tests/ui/author/for_loop.rs | 8 | ||||
| -rw-r--r-- | tests/ui/author/for_loop.stdout | 64 | ||||
| -rw-r--r-- | tests/ui/author/if.rs | 7 | ||||
| -rw-r--r-- | tests/ui/author/if.stdout | 40 | ||||
| -rw-r--r-- | tests/ui/author/loop.rs | 36 | ||||
| -rw-r--r-- | tests/ui/author/loop.stdout | 112 | ||||
| -rw-r--r-- | tests/ui/author/matches.stdout | 14 | ||||
| -rw-r--r-- | tests/ui/author/repeat.rs | 5 | ||||
| -rw-r--r-- | tests/ui/author/repeat.stdout | 10 | ||||
| -rw-r--r-- | tests/ui/author/struct.rs | 40 | ||||
| -rw-r--r-- | tests/ui/author/struct.stdout | 61 |
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, ¤t), 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, ¤t), + 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 + } +} |
