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,
/// }
/// }
/// ```
-declare_lint! {
+declare_clippy_lint! {
pub LINT_AUTHOR,
- Warn,
+ internal_warn,
"helper for writing lints"
}
},
}
}
+
+ fn print_qpath(&mut self, path: &QPath) {
+ print!(" if match_qpath({}, &[", self.current);
+ print_path(path, &mut true);
+ println!("]);");
+ }
}
struct PrintVisitor {
},
}
},
- 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);
},
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, _, _, _) => {
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");
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");
},
}
}
- 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
}
})
}
+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 {