diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 9e832c19a166a..96ccb2999ae15 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -299,7 +299,7 @@ struct Context { // Others operate directly on @ast::item structures (or similar). Finally, // others still are added to the Session object via `add_lint`, and these // are all passed with the lint_session visitor. - visitors: ~[visit::vt<()>], + visitors: ~[visit::vt<@mut Context>], } impl Context { @@ -416,20 +416,20 @@ impl Context { } } - fn add_lint(&mut self, v: visit::vt<()>) { + fn add_lint(&mut self, v: visit::vt<@mut Context>) { self.visitors.push(item_stopping_visitor(v)); } - fn process(&self, n: AttributedNode) { + fn process(@mut self, n: AttributedNode) { match n { Item(it) => { for self.visitors.each |v| { - visit::visit_item(it, (), *v); + visit::visit_item(it, self, *v); } } Crate(c) => { for self.visitors.each |v| { - visit::visit_crate(c, (), *v); + visit::visit_crate(c, self, *v); } } // Can't use visit::visit_method_helper because the @@ -439,7 +439,7 @@ impl Context { let fk = visit::fk_method(copy m.ident, &m.generics, m); for self.visitors.each |v| { visit::visit_fn(&fk, &m.decl, &m.body, m.span, m.id, - (), *v); + self, *v); } } } @@ -499,9 +499,9 @@ fn ty_stopping_visitor(v: visit::vt) -> visit::vt { visit::mk_vt(@visit::Visitor {visit_ty: |_t, _e, _v| { },.. **v}) } -fn lint_while_true(cx: @mut Context) -> visit::vt<()> { - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_expr: |e: @ast::expr| { +fn lint_while_true() -> visit::vt<@mut Context> { + visit::mk_vt(@visit::Visitor { + visit_expr: |e, cx: @mut Context, vt| { match e.node { ast::expr_while(cond, _) => { match cond.node { @@ -517,12 +517,13 @@ fn lint_while_true(cx: @mut Context) -> visit::vt<()> { } _ => () } + visit::visit_expr(e, cx, vt); }, - .. *visit::default_simple_visitor() + .. *visit::default_visitor() }) } -fn lint_type_limits(cx: @mut Context) -> visit::vt<()> { +fn lint_type_limits() -> visit::vt<@mut Context> { fn is_valid(binop: ast::binop, v: T, min: T, max: T) -> bool { match binop { @@ -568,7 +569,7 @@ fn lint_type_limits(cx: @mut Context) -> visit::vt<()> { } } - fn check_limits(cx: @mut Context, binop: ast::binop, l: &ast::expr, + fn check_limits(cx: &Context, binop: ast::binop, l: &ast::expr, r: &ast::expr) -> bool { let (lit, expr, swap) = match (&l.node, &r.node) { (&ast::expr_lit(_), _) => (l, r, true), @@ -621,26 +622,26 @@ fn lint_type_limits(cx: @mut Context) -> visit::vt<()> { } } - let visit_expr: @fn(@ast::expr) = |e| { - match e.node { - ast::expr_binary(ref binop, @ref l, @ref r) => { - if is_comparison(*binop) - && !check_limits(cx, *binop, l, r) { - cx.span_lint(type_limits, e.span, - "comparison is useless due to type limits"); + visit::mk_vt(@visit::Visitor { + visit_expr: |e, cx: @mut Context, vt| { + match e.node { + ast::expr_binary(ref binop, @ref l, @ref r) => { + if is_comparison(*binop) + && !check_limits(cx, *binop, l, r) { + cx.span_lint(type_limits, e.span, + "comparison is useless due to type limits"); + } } + _ => () } - _ => () - } - }; + visit::visit_expr(e, cx, vt); + }, - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_expr: visit_expr, - .. *visit::default_simple_visitor() + .. *visit::default_visitor() }) } -fn check_item_default_methods(cx: @mut Context, item: @ast::item) { +fn check_item_default_methods(cx: &Context, item: @ast::item) { match item.node { ast::item_trait(_, _, ref methods) => { for methods.each |method| { @@ -657,9 +658,9 @@ fn check_item_default_methods(cx: @mut Context, item: @ast::item) { } } -fn check_item_ctypes(cx: @mut Context, it: @ast::item) { +fn check_item_ctypes(cx: &Context, it: @ast::item) { - fn check_foreign_fn(cx: @mut Context, decl: &ast::fn_decl) { + fn check_foreign_fn(cx: &Context, decl: &ast::fn_decl) { let tys = vec::map(decl.inputs, |a| a.ty ); for vec::each(vec::append_one(tys, decl.output)) |ty| { match ty.node { @@ -699,7 +700,7 @@ fn check_item_ctypes(cx: @mut Context, it: @ast::item) { } } -fn check_type_for_lint(cx: @mut Context, lint: lint, span: span, ty: ty::t) { +fn check_type_for_lint(cx: &Context, lint: lint, span: span, ty: ty::t) { if cx.get_level(lint) == allow { return } let mut n_box = 0; @@ -726,13 +727,13 @@ fn check_type_for_lint(cx: @mut Context, lint: lint, span: span, ty: ty::t) { } } -fn check_type(cx: @mut Context, span: span, ty: ty::t) { +fn check_type(cx: &Context, span: span, ty: ty::t) { for [managed_heap_memory, owned_heap_memory, heap_memory].each |lint| { check_type_for_lint(cx, *lint, span, ty); } } -fn check_item_heap(cx: @mut Context, it: @ast::item) { +fn check_item_heap(cx: &Context, it: @ast::item) { match it.node { ast::item_fn(*) | ast::item_ty(*) | @@ -756,19 +757,20 @@ fn check_item_heap(cx: @mut Context, it: @ast::item) { } } -fn lint_heap(cx: @mut Context) -> visit::vt<()> { - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_expr: |e| { +fn lint_heap() -> visit::vt<@mut Context> { + visit::mk_vt(@visit::Visitor { + visit_expr: |e, cx: @mut Context, vt| { let ty = ty::expr_ty(cx.tcx, e); check_type(cx, e.span, ty); + visit::visit_expr(e, cx, vt); }, - .. *visit::default_simple_visitor() + .. *visit::default_visitor() }) } -fn lint_path_statement(cx: @mut Context) -> visit::vt<()> { - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_stmt: |s| { +fn lint_path_statement() -> visit::vt<@mut Context> { + visit::mk_vt(@visit::Visitor { + visit_stmt: |s, cx: @mut Context, vt| { match s.node { ast::stmt_semi( @ast::expr { node: ast::expr_path(_), _ }, @@ -779,12 +781,13 @@ fn lint_path_statement(cx: @mut Context) -> visit::vt<()> { } _ => () } + visit::visit_stmt(s, cx, vt); }, - .. *visit::default_simple_visitor() + .. *visit::default_visitor() }) } -fn check_item_non_camel_case_types(cx: @mut Context, it: @ast::item) { +fn check_item_non_camel_case_types(cx: &Context, it: @ast::item) { fn is_camel_case(cx: ty::ctxt, ident: ast::ident) -> bool { let ident = cx.sess.str_of(ident); assert!(!ident.is_empty()); @@ -808,7 +811,7 @@ fn check_item_non_camel_case_types(cx: @mut Context, it: @ast::item) { } } - fn check_case(cx: @mut Context, ident: ast::ident, span: span) { + fn check_case(cx: &Context, ident: ast::ident, span: span) { if !is_camel_case(cx.tcx, ident) { cx.span_lint(non_camel_case_types, span, "type, variant, or trait should have \ @@ -831,27 +834,26 @@ fn check_item_non_camel_case_types(cx: @mut Context, it: @ast::item) { } } -fn lint_unused_unsafe(cx: @mut Context) -> visit::vt<()> { - let visit_expr: @fn(@ast::expr) = |e| { - match e.node { - ast::expr_block(ref blk) if blk.node.rules == ast::unsafe_blk => { - if !cx.tcx.used_unsafe.contains(&blk.node.id) { - cx.span_lint(unused_unsafe, blk.span, - "unnecessary `unsafe` block"); +fn lint_unused_unsafe() -> visit::vt<@mut Context> { + visit::mk_vt(@visit::Visitor { + visit_expr: |e, cx: @mut Context, vt| { + match e.node { + ast::expr_block(ref blk) if blk.node.rules == ast::unsafe_blk => { + if !cx.tcx.used_unsafe.contains(&blk.node.id) { + cx.span_lint(unused_unsafe, blk.span, + "unnecessary `unsafe` block"); + } } + _ => () } - _ => () - } - }; - - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_expr: visit_expr, - .. *visit::default_simple_visitor() + visit::visit_expr(e, cx, vt); + }, + .. *visit::default_visitor() }) } -fn lint_unused_mut(cx: @mut Context) -> visit::vt<()> { - let check_pat: @fn(@ast::pat) = |p| { +fn lint_unused_mut() -> visit::vt<@mut Context> { + fn check_pat(cx: &Context, p: @ast::pat) { let mut used = false; let mut bindings = 0; do pat_util::pat_bindings(cx.tcx.def_map, p) |_, id, _, _| { @@ -866,37 +868,48 @@ fn lint_unused_mut(cx: @mut Context) -> visit::vt<()> { }; cx.span_lint(unused_mut, p.span, msg); } - }; + } - let visit_fn_decl: @fn(&ast::fn_decl) = |fd| { + fn visit_fn_decl(cx: &Context, fd: &ast::fn_decl) { for fd.inputs.each |arg| { if arg.is_mutbl { - check_pat(arg.pat); + check_pat(cx, arg.pat); } } - }; + } - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_local: |l| { + visit::mk_vt(@visit::Visitor { + visit_local: |l, cx: @mut Context, vt| { if l.node.is_mutbl { - check_pat(l.node.pat); + check_pat(cx, l.node.pat); } + visit::visit_local(l, cx, vt); + }, + visit_fn: |a, fd, b, c, d, cx, vt| { + visit_fn_decl(cx, fd); + visit::visit_fn(a, fd, b, c, d, cx, vt); + }, + visit_ty_method: |tm, cx, vt| { + visit_fn_decl(cx, &tm.decl); + visit::visit_ty_method(tm, cx, vt); }, - visit_fn: |_, fd, _, _, _| visit_fn_decl(fd), - visit_ty_method: |tm| visit_fn_decl(&tm.decl), - visit_struct_method: |sm| visit_fn_decl(&sm.decl), - visit_trait_method: |tm| { + visit_struct_method: |sm, cx, vt| { + visit_fn_decl(cx, &sm.decl); + visit::visit_struct_method(sm, cx, vt); + }, + visit_trait_method: |tm, cx, vt| { match *tm { - ast::required(ref tm) => visit_fn_decl(&tm.decl), - ast::provided(m) => visit_fn_decl(&m.decl), + ast::required(ref tm) => visit_fn_decl(cx, &tm.decl), + ast::provided(m) => visit_fn_decl(cx, &m.decl) } + visit::visit_trait_method(tm, cx, vt); }, - .. *visit::default_simple_visitor() + .. *visit::default_visitor() }) } -fn lint_session(cx: @mut Context) -> visit::vt<()> { - ast_util::id_visitor(|id| { +fn lint_session() -> visit::vt<@mut Context> { + ast_util::id_visitor(|id, cx: @mut Context| { match cx.tcx.sess.lints.pop(&id) { None => {}, Some(l) => { @@ -908,10 +921,10 @@ fn lint_session(cx: @mut Context) -> visit::vt<()> { }) } -fn lint_unnecessary_allocations(cx: @mut Context) -> visit::vt<()> { +fn lint_unnecessary_allocations() -> visit::vt<@mut Context> { // Warn if string and vector literals with sigils are immediately borrowed. // Those can have the sigil removed. - fn check(cx: @mut Context, e: @ast::expr) { + fn check(cx: &Context, e: @ast::expr) { match e.node { ast::expr_vstore(e2, ast::expr_vstore_uniq) | ast::expr_vstore(e2, ast::expr_vstore_box) => { @@ -938,19 +951,18 @@ fn lint_unnecessary_allocations(cx: @mut Context) -> visit::vt<()> { } } - let visit_expr: @fn(@ast::expr) = |e| { - check(cx, e); - }; - - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_expr: visit_expr, - .. *visit::default_simple_visitor() + visit::mk_vt(@visit::Visitor { + visit_expr: |e, cx: @mut Context, vt| { + check(cx, e); + visit::visit_expr(e, cx, vt); + }, + .. *visit::default_visitor() }) } -fn lint_missing_struct_doc(cx: @mut Context) -> visit::vt<()> { - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_struct_field: |field| { +fn lint_missing_struct_doc() -> visit::vt<@mut Context> { + visit::mk_vt(@visit::Visitor { + visit_struct_field: |field, cx: @mut Context, vt| { let relevant = match field.node.kind { ast::named_field(_, vis) => vis != ast::private, ast::unnamed_field => false, @@ -969,14 +981,16 @@ fn lint_missing_struct_doc(cx: @mut Context) -> visit::vt<()> { for a field."); } } + + visit::visit_struct_field(field, cx, vt); }, - .. *visit::default_simple_visitor() + .. *visit::default_visitor() }) } -fn lint_missing_trait_doc(cx: @mut Context) -> visit::vt<()> { - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_trait_method: |method| { +fn lint_missing_trait_doc() -> visit::vt<@mut Context> { + visit::mk_vt(@visit::Visitor { + visit_trait_method: |method, cx: @mut Context, vt| { let mut has_doc = false; let span = match copy *method { ast::required(m) => { @@ -1006,8 +1020,9 @@ fn lint_missing_trait_doc(cx: @mut Context) -> visit::vt<()> { cx.span_lint(missing_trait_doc, span, "missing documentation \ for a method."); } + visit::visit_trait_method(method, cx, vt); }, - .. *visit::default_simple_visitor() + .. *visit::default_visitor() }) } @@ -1031,39 +1046,33 @@ pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) { } // Register each of the lint passes with the context - cx.add_lint(lint_while_true(cx)); - cx.add_lint(lint_path_statement(cx)); - cx.add_lint(lint_heap(cx)); - cx.add_lint(lint_type_limits(cx)); - cx.add_lint(lint_unused_unsafe(cx)); - cx.add_lint(lint_unused_mut(cx)); - cx.add_lint(lint_session(cx)); - cx.add_lint(lint_unnecessary_allocations(cx)); - cx.add_lint(lint_missing_struct_doc(cx)); - cx.add_lint(lint_missing_trait_doc(cx)); - - // type inference doesn't like this being declared below, we need to tell it - // what the type of this first function is... - let visit_item: - @fn(@ast::item, @mut Context, visit::vt<@mut Context>) = - |it, cx, vt| { - do cx.with_lint_attrs(it.attrs) { - check_item_ctypes(cx, it); - check_item_non_camel_case_types(cx, it); - check_item_default_methods(cx, it); - check_item_heap(cx, it); - - cx.process(Item(it)); - visit::visit_item(it, cx, vt); - } - }; + cx.add_lint(lint_while_true()); + cx.add_lint(lint_path_statement()); + cx.add_lint(lint_heap()); + cx.add_lint(lint_type_limits()); + cx.add_lint(lint_unused_unsafe()); + cx.add_lint(lint_unused_mut()); + cx.add_lint(lint_session()); + cx.add_lint(lint_unnecessary_allocations()); + cx.add_lint(lint_missing_struct_doc()); + cx.add_lint(lint_missing_trait_doc()); // Actually perform the lint checks (iterating the ast) do cx.with_lint_attrs(crate.node.attrs) { cx.process(Crate(crate)); visit::visit_crate(crate, cx, visit::mk_vt(@visit::Visitor { - visit_item: visit_item, + visit_item: |it, cx: @mut Context, vt| { + do cx.with_lint_attrs(it.attrs) { + check_item_ctypes(cx, it); + check_item_non_camel_case_types(cx, it); + check_item_default_methods(cx, it); + check_item_heap(cx, it); + + cx.process(Item(it)); + visit::visit_item(it, cx, vt); + } + }, visit_fn: |fk, decl, body, span, id, cx, vt| { match *fk { visit::fk_method(_, _, m) => { diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 59743b6e8927f..8d5af682d6205 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -386,82 +386,103 @@ pub impl id_range { } } -pub fn id_visitor(vfn: @fn(node_id)) -> visit::vt<()> { - let visit_generics: @fn(&Generics) = |generics| { +pub fn id_visitor(vfn: @fn(node_id, T)) -> visit::vt { + let visit_generics: @fn(&Generics, T) = |generics, t| { for generics.ty_params.each |p| { - vfn(p.id); + vfn(p.id, t); } for generics.lifetimes.each |p| { - vfn(p.id); + vfn(p.id, t); } }; - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_mod: |_m, _sp, id| vfn(id), + visit::mk_vt(@visit::Visitor { + visit_mod: |m, sp, id, t, vt| { + vfn(id, t); + visit::visit_mod(m, sp, id, t, vt); + }, - visit_view_item: |vi| { + visit_view_item: |vi, t, vt| { match vi.node { - view_item_extern_mod(_, _, id) => vfn(id), + view_item_extern_mod(_, _, id) => vfn(id, t), view_item_use(ref vps) => { for vps.each |vp| { match vp.node { - view_path_simple(_, _, id) => vfn(id), - view_path_glob(_, id) => vfn(id), + view_path_simple(_, _, id) => vfn(id, t), + view_path_glob(_, id) => vfn(id, t), view_path_list(_, ref paths, id) => { - vfn(id); + vfn(id, t); for paths.each |p| { - vfn(p.node.id); + vfn(p.node.id, t); } } } } } } + visit::visit_view_item(vi, t, vt); }, - visit_foreign_item: |ni| vfn(ni.id), + visit_foreign_item: |ni, t, vt| { + vfn(ni.id, t); + visit::visit_foreign_item(ni, t, vt); + }, - visit_item: |i| { - vfn(i.id); + visit_item: |i, t, vt| { + vfn(i.id, t); match i.node { item_enum(ref enum_definition, _) => - for (*enum_definition).variants.each |v| { vfn(v.node.id); }, + for (*enum_definition).variants.each |v| { vfn(v.node.id, t); }, _ => () } + visit::visit_item(i, t, vt); }, - visit_local: |l| vfn(l.node.id), - visit_block: |b| vfn(b.node.id), - visit_stmt: |s| vfn(ast_util::stmt_id(s)), - visit_arm: |_| {}, - visit_pat: |p| vfn(p.id), - visit_decl: |_| {}, - - visit_expr: |e| { - vfn(e.callee_id); - vfn(e.id); + visit_local: |l, t, vt| { + vfn(l.node.id, t); + visit::visit_local(l, t, vt); + }, + visit_block: |b, t, vt| { + vfn(b.node.id, t); + visit::visit_block(b, t, vt); + }, + visit_stmt: |s, t, vt| { + vfn(ast_util::stmt_id(s), t); + visit::visit_stmt(s, t, vt); + }, + visit_pat: |p, t, vt| { + vfn(p.id, t); + visit::visit_pat(p, t, vt); }, - visit_expr_post: |_| {}, + visit_expr: |e, t, vt| { + vfn(e.callee_id, t); + vfn(e.id, t); + visit::visit_expr(e, t, vt); + }, - visit_ty: |t| { - match t.node { - ty_path(_, id) => vfn(id), + visit_ty: |ty, t, vt| { + match ty.node { + ty_path(_, id) => vfn(id, t), _ => { /* fall through */ } } + visit::visit_ty(ty, t, vt); }, - visit_generics: visit_generics, + visit_generics: |generics, t, vt| { + visit_generics(generics, t); + visit::visit_generics(generics, t, vt); + }, - visit_fn: |fk, d, _, _, id| { - vfn(id); + visit_fn: |fk, d, a, b, id, t, vt| { + vfn(id, t); match *fk { visit::fk_item_fn(_, generics, _, _) => { - visit_generics(generics); + visit_generics(generics, t); } visit::fk_method(_, generics, m) => { - vfn(m.self_id); - visit_generics(generics); + vfn(m.self_id, t); + visit_generics(generics, t); } visit::fk_anon(_) | visit::fk_fn_block => { @@ -469,20 +490,22 @@ pub fn id_visitor(vfn: @fn(node_id)) -> visit::vt<()> { } for d.inputs.each |arg| { - vfn(arg.id) + vfn(arg.id, t) } + visit::visit_fn(fk, d, a, b, id, t, vt); + }, + + visit_struct_field: |f, t, vt| { + vfn(f.node.id, t); + visit::visit_struct_field(f, t, vt); }, - visit_ty_method: |_| {}, - visit_trait_method: |_| {}, - visit_struct_def: |_, _, _, _| {}, - visit_struct_field: |f| vfn(f.node.id), - visit_struct_method: |_| {} + .. *visit::default_visitor() }) } pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(node_id)) { - item.accept((), id_visitor(vfn)); + item.accept((), id_visitor(|id, ()| vfn(id))); } pub fn compute_id_range(visit_ids_fn: &fn(@fn(node_id))) -> id_range {