X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=clippy_lints%2Fsrc%2Futils%2Fauthor.rs;h=63f946286307ed7ea998d631526481d9f7cbde6c;hb=f195680edb1d0ba2c04bfd6ba4fccfca184e8dbe;hp=fe8123d288d1f3f30088933a494a2ee4c92b46f7;hpb=8c07772dbb817114f338692188dd7733bcd741cb;p=rust.git diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index fe8123d288d..63f94628630 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,61 +1,54 @@ //! A group of attributes that can be attached to Rust code in order //! to generate a clippy lint detecting said code automatically. -#![allow(print_stdout, use_debug)] - -use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; -use rustc::{declare_tool_lint, lint_array}; +use crate::utils::get_attr; use rustc::hir; -use rustc::hir::{Expr, ExprKind, QPath, TyKind, Pat, PatKind, BindingAnnotation, StmtKind, DeclKind, Stmt}; use rustc::hir::intravisit::{NestedVisitorMap, Visitor}; -use syntax::ast::{Attribute, LitKind, DUMMY_NODE_ID}; -use std::collections::HashMap; -use crate::utils::get_attr; +use rustc::hir::{BindingAnnotation, Expr, ExprKind, Pat, PatKind, QPath, Stmt, StmtKind, TyKind}; +use rustc::lint::{LateContext, LateLintPass, LintArray, LintContext, LintPass}; +use rustc::session::Session; +use rustc::{declare_lint_pass, declare_tool_lint}; +use rustc_data_structures::fx::FxHashMap; +use syntax::ast::{Attribute, LitKind}; -/// **What it does:** Generates clippy code that detects the offending pattern -/// -/// **Example:** -/// ```rust -/// // ./tests/ui/my_lint.rs -/// fn foo() { -/// // detect the following pattern -/// #[clippy::author] -/// if x == 42 { -/// // but ignore everything from here on -/// #![clippy::author = "ignore"] -/// } -/// } -/// ``` -/// -/// Running `TESTNAME=ui/my_lint cargo test --test compile-test` will produce -/// a `./tests/ui/new_lint.stdout` file with the generated code: -/// -/// ```rust -/// // ./tests/ui/new_lint.stdout -/// if_chain!{ -/// if let ExprKind::If(ref cond, ref then, None) = item.node, -/// if let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.node, -/// if let ExprKind::Path(ref path) = left.node, -/// if let ExprKind::Lit(ref lit) = right.node, -/// if let LitKind::Int(42, _) = lit.node, -/// then { -/// // report your lint here -/// } -/// } -/// ``` declare_clippy_lint! { + /// **What it does:** Generates clippy code that detects the offending pattern + /// + /// **Example:** + /// ```rust + /// // ./tests/ui/my_lint.rs + /// fn foo() { + /// // detect the following pattern + /// #[clippy::author] + /// if x == 42 { + /// // but ignore everything from here on + /// #![clippy::author = "ignore"] + /// } + /// } + /// ``` + /// + /// Running `TESTNAME=ui/my_lint cargo uitest` will produce + /// a `./tests/ui/new_lint.stdout` file with the generated code: + /// + /// ```rust + /// // ./tests/ui/new_lint.stdout + /// if_chain! { + /// if let ExprKind::If(ref cond, ref then, None) = item.node, + /// if let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.node, + /// if let ExprKind::Path(ref path) = left.node, + /// if let ExprKind::Lit(ref lit) = right.node, + /// if let LitKind::Int(42, _) = lit.node, + /// then { + /// // report your lint here + /// } + /// } + /// ``` pub LINT_AUTHOR, internal_warn, "helper for writing lints" } -pub struct Pass; - -impl LintPass for Pass { - fn get_lints(&self) -> LintArray { - lint_array!(LINT_AUTHOR) - } -} +declare_lint_pass!(Author => [LINT_AUTHOR]); fn prelude() { println!("if_chain! {{"); @@ -68,9 +61,9 @@ fn done() { println!("}}"); } -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { - fn check_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { - if !has_attr(&item.attrs) { +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Author { + fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { + if !has_attr(cx.sess(), &item.attrs) { return; } prelude(); @@ -78,8 +71,8 @@ fn check_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) { done(); } - fn check_impl_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem) { - if !has_attr(&item.attrs) { + fn check_impl_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ImplItem) { + if !has_attr(cx.sess(), &item.attrs) { return; } prelude(); @@ -87,8 +80,8 @@ fn check_impl_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Impl done(); } - fn check_trait_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) { - if !has_attr(&item.attrs) { + fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) { + if !has_attr(cx.sess(), &item.attrs) { return; } prelude(); @@ -96,17 +89,17 @@ fn check_trait_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Tra done(); } - fn check_variant(&mut self, _cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, generics: &hir::Generics) { - if !has_attr(&var.node.attrs) { + fn check_variant(&mut self, cx: &LateContext<'a, 'tcx>, var: &'tcx hir::Variant, generics: &hir::Generics) { + if !has_attr(cx.sess(), &var.node.attrs) { return; } prelude(); - PrintVisitor::new("var").visit_variant(var, generics, DUMMY_NODE_ID); + PrintVisitor::new("var").visit_variant(var, generics, hir::DUMMY_HIR_ID); done(); } - fn check_struct_field(&mut self, _cx: &LateContext<'a, 'tcx>, field: &'tcx hir::StructField) { - if !has_attr(&field.attrs) { + fn check_struct_field(&mut self, cx: &LateContext<'a, 'tcx>, field: &'tcx hir::StructField) { + if !has_attr(cx.sess(), &field.attrs) { return; } prelude(); @@ -114,8 +107,8 @@ fn check_struct_field(&mut self, _cx: &LateContext<'a, 'tcx>, field: &'tcx hir:: done(); } - fn check_expr(&mut self, _cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { - if !has_attr(&expr.attrs) { + fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { + if !has_attr(cx.sess(), &expr.attrs) { return; } prelude(); @@ -123,8 +116,8 @@ fn check_expr(&mut self, _cx: &LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) { done(); } - fn check_arm(&mut self, _cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) { - if !has_attr(&arm.attrs) { + fn check_arm(&mut self, cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) { + if !has_attr(cx.sess(), &arm.attrs) { return; } prelude(); @@ -132,8 +125,8 @@ fn check_arm(&mut self, _cx: &LateContext<'a, 'tcx>, arm: &'tcx hir::Arm) { done(); } - fn check_stmt(&mut self, _cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) { - if !has_attr(stmt.node.attrs()) { + fn check_stmt(&mut self, cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) { + if !has_attr(cx.sess(), stmt.node.attrs()) { return; } prelude(); @@ -141,8 +134,8 @@ fn check_stmt(&mut self, _cx: &LateContext<'a, 'tcx>, stmt: &'tcx hir::Stmt) { done(); } - fn check_foreign_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ForeignItem) { - if !has_attr(&item.attrs) { + fn check_foreign_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::ForeignItem) { + if !has_attr(cx.sess(), &item.attrs) { return; } prelude(); @@ -154,7 +147,7 @@ fn check_foreign_item(&mut self, _cx: &LateContext<'a, 'tcx>, item: &'tcx hir::F impl PrintVisitor { fn new(s: &'static str) -> Self { Self { - ids: HashMap::new(), + ids: FxHashMap::default(), current: s.to_owned(), } } @@ -186,12 +179,13 @@ fn print_qpath(&mut self, path: &QPath) { struct PrintVisitor { /// Fields are the current index that needs to be appended to pattern /// binding names - ids: HashMap<&'static str, usize>, + ids: FxHashMap<&'static str, usize>, /// the name that needs to be destructured current: String, } impl<'tcx> Visitor<'tcx> for PrintVisitor { + #[allow(clippy::too_many_lines)] fn visit_expr(&mut self, expr: &Expr) { print!(" if let ExprKind::"); let current = format!("{}.node", self.current); @@ -240,7 +234,10 @@ fn visit_expr(&mut self, expr: &Expr) { 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!( + "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); @@ -259,6 +256,7 @@ fn visit_expr(&mut self, expr: &Expr) { 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), @@ -303,7 +301,10 @@ fn visit_expr(&mut self, expr: &Expr) { let then_pat = self.next("then"); if let Some(ref else_) = *opt_else { let else_pat = self.next("else_"); - println!("If(ref {}, ref {}, Some(ref {})) = {};", cond_pat, then_pat, else_pat, current); + println!( + "If(ref {}, ref {}, Some(ref {})) = {};", + cond_pat, then_pat, else_pat, current + ); self.current = else_pat; self.visit_expr(else_); } else { @@ -318,7 +319,10 @@ fn visit_expr(&mut self, expr: &Expr) { let cond_pat = self.next("cond"); let body_pat = self.next("body"); let label_pat = self.next("label"); - println!("While(ref {}, ref {}, ref {}) = {};", cond_pat, body_pat, label_pat, current); + println!( + "While(ref {}, ref {}, ref {}) = {};", + cond_pat, body_pat, label_pat, current + ); self.current = cond_pat; self.visit_expr(cond); self.current = body_pat; @@ -345,9 +349,15 @@ fn visit_expr(&mut self, expr: &Expr) { 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); - self.current = guard_pat; - self.visit_expr(guard); + println!(" if let Some(ref {}) = {}[{}].guard;", guard_pat, arms_pat, i); + match guard { + hir::Guard::If(ref 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); + }, + } } println!(" if {}[{}].pats.len() == {};", arms_pat, i, arm.pats.len()); for (j, pat) in arm.pats.iter().enumerate() { @@ -385,7 +395,10 @@ fn visit_expr(&mut self, expr: &Expr) { 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!( + "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); @@ -438,13 +451,15 @@ fn visit_expr(&mut self, expr: &Expr) { println!("Again(ref {}) = {};", destination_pat, current); // FIXME: implement label printing }, - ExprKind::Ret(ref opt_value) => if let Some(ref 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 { - println!("Ret(None) = {};", current); + ExprKind::Ret(ref opt_value) => { + if let Some(ref 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 { + println!("Ret(None) = {};", current); + } }, ExprKind::InlineAsm(_, ref _input, ref _output) => { println!("InlineAsm(_, ref input, ref output) = {};", current); @@ -457,10 +472,7 @@ fn visit_expr(&mut self, expr: &Expr) { let base_pat = self.next("base"); println!( "Struct(ref {}, ref {}, Some(ref {})) = {};", - path_pat, - fields_pat, - base_pat, - current + path_pat, fields_pat, base_pat, current ); self.current = base_pat; self.visit_expr(base); @@ -480,15 +492,25 @@ fn visit_expr(&mut self, expr: &Expr) { self.current = value_pat; self.visit_expr(value); }, + ExprKind::Err => { + println!("Err = {}", current); + }, + ExprKind::DropTemps(ref expr) => { + let expr_pat = self.next("expr"); + println!("DropTemps(ref {}) = {};", expr_pat, current); + self.current = expr_pat; + self.visit_expr(expr); + }, } } + #[allow(clippy::too_many_lines)] fn visit_pat(&mut self, pat: &Pat) { print!(" if let PatKind::"); let current = format!("{}.node", self.current); match pat.node { PatKind::Wild => println!("Wild = {};", current), - PatKind::Binding(anno, _, ident, ref sub) => { + PatKind::Binding(anno, .., ident, ref sub) => { let anno_pat = match anno { BindingAnnotation::Unannotated => "BindingAnnotation::Unannotated", BindingAnnotation::Mutable => "BindingAnnotation::Mutable", @@ -498,27 +520,36 @@ fn visit_pat(&mut self, pat: &Pat) { let name_pat = self.next("name"); if let Some(ref sub) = *sub { let sub_pat = self.next("sub"); - println!("Binding({}, _, {}, Some(ref {})) = {};", anno_pat, name_pat, sub_pat, current); + 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 {}.node.as_str() == \"{}\";", name_pat, ident.as_str()); - } + }, PatKind::Struct(ref path, ref fields, ignore) => { let path_pat = self.next("path"); let fields_pat = self.next("fields"); - println!("Struct(ref {}, ref {}, {}) = {};", path_pat, fields_pat, ignore, current); + println!( + "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"); - } + }, PatKind::TupleStruct(ref path, ref 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); + 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()); @@ -529,13 +560,13 @@ fn visit_pat(&mut self, pat: &Pat) { println!("Path(ref {}) = {};", path_pat, current); self.current = path_pat; self.print_qpath(path); - } + }, PatKind::Tuple(ref fields, skip_pos) => { 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"); - } + }, PatKind::Box(ref pat) => { let pat_pat = self.next("pat"); println!("Box(ref {}) = {};", pat_pat, current); @@ -553,22 +584,28 @@ fn visit_pat(&mut self, pat: &Pat) { 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); + println!( + "Range(ref {}, ref {}, RangeEnd::{:?}) = {};", + start_pat, end_pat, end_kind, current + ); self.current = start_pat; self.visit_expr(start); self.current = end_pat; self.visit_expr(end); - } + }, PatKind::Slice(ref start, ref middle, ref end) => { let start_pat = self.next("start"); let end_pat = self.next("end"); if let Some(ref middle) = middle { let middle_pat = self.next("middle"); - println!("Slice(ref {}, Some(ref {}), ref {}) = {};", start_pat, middle_pat, end_pat, current); + println!( + "Slice(ref {}, Some(ref {}), ref {}) = {};", + start_pat, middle_pat, end_pat, current + ); self.current = middle_pat; self.visit_pat(middle); } else { @@ -584,7 +621,7 @@ fn visit_pat(&mut self, pat: &Pat) { self.current = format!("{}[{}]", end_pat, i); self.visit_pat(pat); } - } + }, } } @@ -592,35 +629,26 @@ fn visit_stmt(&mut self, s: &Stmt) { print!(" if let StmtKind::"); let current = format!("{}.node", self.current); match s.node { - // Could be an item or a local (let) binding: - StmtKind::Decl(ref decl, _) => { - let decl_pat = self.next("decl"); - println!("Decl(ref {}, _) = {}", decl_pat, current); - print!(" if let DeclKind::"); - let current = format!("{}.node", decl_pat); - match decl.node { - // A local (let) binding: - DeclKind::Local(ref local) => { - let local_pat = self.next("local"); - println!("Local(ref {}) = {};", local_pat, current); - if let Some(ref 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); - }, - // An item binding: - DeclKind::Item(_) => { - println!("Item(item_id) = {};", current); - }, + // A local (let) binding: + StmtKind::Local(ref local) => { + let local_pat = self.next("local"); + println!("Local(ref {}) = {};", local_pat, current); + if let Some(ref 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); + }, + // An item binding: + StmtKind::Item(_) => { + println!("Item(item_id) = {};", current); + }, // Expr without trailing semi-colon (must have unit type): - StmtKind::Expr(ref e, _) => { + StmtKind::Expr(ref e) => { let e_pat = self.next("e"); println!("Expr(ref {}, _) = {}", e_pat, current); self.current = e_pat; @@ -628,7 +656,7 @@ fn visit_stmt(&mut self, s: &Stmt) { }, // Expr with trailing semi-colon (may have any type): - StmtKind::Semi(ref e, _) => { + StmtKind::Semi(ref e) => { let e_pat = self.next("e"); println!("Semi(ref {}, _) = {}", e_pat, current); self.current = e_pat; @@ -642,8 +670,8 @@ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { } } -fn has_attr(attrs: &[Attribute]) -> bool { - get_attr(attrs, "author").count() > 0 +fn has_attr(sess: &Session, attrs: &[Attribute]) -> bool { + get_attr(sess, attrs, "author").count() > 0 } fn desugaring_name(des: hir::MatchSource) -> String { @@ -652,7 +680,10 @@ fn desugaring_name(des: hir::MatchSource) -> String { hir::MatchSource::TryDesugar => "MatchSource::TryDesugar".to_string(), hir::MatchSource::WhileLetDesugar => "MatchSource::WhileLetDesugar".to_string(), hir::MatchSource::Normal => "MatchSource::Normal".to_string(), - hir::MatchSource::IfLetDesugar { contains_else_clause } => format!("MatchSource::IfLetDesugar {{ contains_else_clause: {} }}", contains_else_clause), + hir::MatchSource::IfLetDesugar { contains_else_clause } => format!( + "MatchSource::IfLetDesugar {{ contains_else_clause: {} }}", + contains_else_clause + ), } } @@ -666,13 +697,15 @@ fn loop_desugaring_name(des: hir::LoopSource) -> &'static str { fn print_path(path: &QPath, first: &mut bool) { match *path { - QPath::Resolved(_, ref path) => for segment in &path.segments { - if *first { - *first = false; - } else { - print!(", "); + QPath::Resolved(_, ref path) => { + for segment in &path.segments { + if *first { + *first = false; + } else { + print!(", "); + } + print!("{:?}", segment.ident.as_str()); } - print!("{:?}", segment.ident.as_str()); }, QPath::TypeRelative(ref ty, ref segment) => match ty.node { hir::TyKind::Path(ref inner_path) => {