]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/utils/author.rs
Document the author lint
[rust.git] / clippy_lints / src / utils / author.rs
index eadc672e56b9f6ccd20a5d7b71d05156ec8c1d7a..9d708d637c3c93db8f9b0db61f4169769ddb2a7e 100644 (file)
@@ -5,16 +5,16 @@
 
 use rustc::lint::*;
 use rustc::hir;
-use rustc::hir::{Expr, Expr_, QPath};
+use rustc::hir::{Expr, Expr_, QPath, Ty_};
 use rustc::hir::intravisit::{NestedVisitorMap, Visitor};
-use syntax::ast::{self, Attribute, LitKind, NodeId, DUMMY_NODE_ID};
-use syntax::codemap::Span;
+use syntax::ast::{self, Attribute, LitKind, DUMMY_NODE_ID};
 use std::collections::HashMap;
 
 /// **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)]
 /// }
 /// ```
 ///
-/// prints
+/// 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 Expr_::ExprIf(ref cond, ref then, None) = item.node,
 ///     if let Expr_::ExprBinary(BinOp::Eq, ref left, ref right) = cond.node,
@@ -39,9 +41,9 @@
 ///     }
 /// }
 /// ```
-declare_lint! {
+declare_clippy_lint! {
     pub LINT_AUTHOR,
-    Warn,
+    internal_warn,
     "helper for writing lints"
 }
 
@@ -171,6 +173,12 @@ fn next(&mut self, s: &'static str) -> String {
             },
         }
     }
+
+    fn print_qpath(&mut self, path: &QPath) {
+        print!("    if match_qpath({}, &[", self.current);
+        print_path(path, &mut true);
+        println!("]);");
+    }
 }
 
 struct PrintVisitor {
@@ -260,9 +268,17 @@ fn visit_expr(&mut self, expr: &Expr) {
                     },
                 }
             },
-            Expr_::ExprCast(ref expr, ref _ty) => {
+            Expr_::ExprCast(ref expr, ref ty) => {
                 let cast_pat = self.next("expr");
-                println!("Cast(ref {}, _) = {};", cast_pat, current);
+                let cast_ty = self.next("cast_ty");
+                let qp_label = self.next("qp");
+
+                println!("Cast(ref {}, ref {}) = {};", cast_pat, cast_ty, current);
+                if let Ty_::TyPath(ref qp) = ty.node {
+                    println!("    if let Ty_::TyPath(ref {}) = {}.node;", qp_label, cast_ty);
+                    self.current = qp_label;
+                    self.print_qpath(qp);
+                }
                 self.current = cast_pat;
                 self.visit_expr(expr);
             },
@@ -288,16 +304,27 @@ fn visit_expr(&mut self, expr: &Expr) {
                 self.current = then_pat;
                 self.visit_expr(then);
             },
-            Expr_::ExprWhile(ref _cond, ref _body, ref _opt_label) => {
-                println!("While(ref cond, ref body, ref opt_label) = {};", current);
-                println!("    // unimplemented: `ExprWhile` is not further destructured at the moment");
-            },
-            Expr_::ExprLoop(ref _body, ref _opt_label, ref _desuraging) => {
-                println!("Loop(ref body, ref opt_label, ref desugaring) = {};", current);
-                println!("    // unimplemented: `ExprLoop` is not further destructured at the moment");
-            },
-            Expr_::ExprMatch(ref _expr, ref _arms, ref _desugaring) => {
-                println!("Match(ref expr, ref arms, ref desugaring) = {};", current);
+            Expr_::ExprWhile(ref cond, ref body, _) => {
+                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);
+                self.current = cond_pat;
+                self.visit_expr(cond);
+                self.current = body_pat;
+                self.visit_block(body);
+            },
+            Expr_::ExprLoop(ref body, _, desugaring) => {
+                let body_pat = self.next("body");
+                let des = loop_desugaring_name(desugaring);
+                let label_pat = self.next("label");
+                println!("Loop(ref {}, ref {}, {}) = {};", body_pat, label_pat, des, current);
+                self.current = body_pat;
+                self.visit_block(body);
+            },
+            Expr_::ExprMatch(ref _expr, ref _arms, desugaring) => {
+                let des = desugaring_name(desugaring);
+                println!("Match(ref expr, ref arms, {}) = {};", des, current);
                 println!("    // unimplemented: `ExprMatch` is not further destructured at the moment");
             },
             Expr_::ExprClosure(ref _capture_clause, ref _func, _, _, _) => {
@@ -365,7 +392,7 @@ fn visit_expr(&mut self, expr: &Expr) {
                 let path_pat = self.next("path");
                 println!("Path(ref {}) = {};", path_pat, current);
                 self.current = path_pat;
-                self.visit_qpath(path, expr.id, expr.span);
+                self.print_qpath(path);
             },
             Expr_::ExprAddrOf(mutability, ref inner) => {
                 let inner_pat = self.next("inner");
@@ -420,7 +447,7 @@ fn visit_expr(&mut self, expr: &Expr) {
                     println!("Struct(ref {}, ref {}, None) = {};", path_pat, fields_pat, current);
                 }
                 self.current = path_pat;
-                self.visit_qpath(path, expr.id, expr.span);
+                self.print_qpath(path);
                 println!("    if {}.len() == {};", fields_pat, fields.len());
                 println!("    // unimplemented: field checks");
             },
@@ -435,11 +462,6 @@ fn visit_expr(&mut self, expr: &Expr) {
         }
     }
 
-    fn visit_qpath(&mut self, path: &QPath, _: NodeId, _: Span) {
-        print!("    if match_qpath({}, &[", self.current);
-        print_path(path, &mut true);
-        println!("]);");
-    }
     fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
         NestedVisitorMap::None
     }
@@ -456,6 +478,24 @@ fn has_attr(attrs: &[Attribute]) -> bool {
     })
 }
 
+fn desugaring_name(des: hir::MatchSource) -> String {
+    match des {
+        hir::MatchSource::ForLoopDesugar => "MatchSource::ForLoopDesugar".to_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),
+    }
+}
+
+fn loop_desugaring_name(des: hir::LoopSource) -> &'static str {
+    match des {
+        hir::LoopSource::ForLoop => "LoopSource::ForLoop",
+        hir::LoopSource::Loop => "LoopSource::Loop",
+        hir::LoopSource::WhileLet => "LoopSource::WhileLet",
+    }
+}
+
 fn print_path(path: &QPath, first: &mut bool) {
     match *path {
         QPath::Resolved(_, ref path) => for segment in &path.segments {