]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/lint/context.rs
Fill in some missing parts in the default AST visitor
[rust.git] / src / librustc / lint / context.rs
index afc33c0a12c7d10514f3e706b03688b51552e6e1..f47c709e03aa2f5ebb771d26a157ae919070fbac 100644 (file)
@@ -28,7 +28,8 @@
 use middle::privacy::ExportedItems;
 use middle::ty::{self, Ty};
 use session::{early_error, Session};
-use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass, LintPassObject};
+use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
+use lint::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject};
 use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
 use lint::builtin;
 use util::nodemap::FnvHashMap;
 use std::cell::RefCell;
 use std::cmp;
 use std::mem;
-use syntax::ast_util::IdVisitingOperation;
+use syntax::ast_util::{self, IdVisitingOperation};
 use syntax::attr::{self, AttrMetaMethods};
 use syntax::codemap::Span;
 use syntax::parse::token::InternedString;
 use syntax::ast;
 use rustc_front::hir;
-use rustc_front::visit::{self, Visitor, FnKind};
 use rustc_front::util;
-use syntax::visit::Visitor as SyntaxVisitor;
+use rustc_front::visit as hir_visit;
+use syntax::visit as ast_visit;
 use syntax::diagnostic;
 
 /// Information about the registered lints.
@@ -59,7 +60,8 @@ pub struct LintStore {
     /// Trait objects for each lint pass.
     /// This is only `None` while iterating over the objects. See the definition
     /// of run_lints.
-    passes: Option<Vec<LintPassObject>>,
+    early_passes: Option<Vec<EarlyLintPassObject>>,
+    late_passes: Option<Vec<LateLintPassObject>>,
 
     /// Lints indexed by name.
     by_name: FnvHashMap<String, TargetLint>,
@@ -115,7 +117,8 @@ fn set_level(&mut self, lint: LintId, mut lvlsrc: LevelSource) {
     pub fn new() -> LintStore {
         LintStore {
             lints: vec!(),
-            passes: Some(vec!()),
+            early_passes: Some(vec!()),
+            late_passes: Some(vec!()),
             by_name: FnvHashMap(),
             levels: FnvHashMap(),
             lint_groups: FnvHashMap(),
@@ -133,8 +136,27 @@ pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
                                               v.1)).collect()
     }
 
-    pub fn register_pass(&mut self, sess: Option<&Session>,
-                         from_plugin: bool, pass: LintPassObject) {
+    pub fn register_early_pass(&mut self,
+                               sess: Option<&Session>,
+                               from_plugin: bool,
+                               pass: EarlyLintPassObject) {
+        self.push_pass(sess, from_plugin, &pass);
+        self.early_passes.as_mut().unwrap().push(pass);
+    }
+
+    pub fn register_late_pass(&mut self,
+                              sess: Option<&Session>,
+                              from_plugin: bool,
+                              pass: LateLintPassObject) {
+        self.push_pass(sess, from_plugin, &pass);
+        self.late_passes.as_mut().unwrap().push(pass);
+    }
+
+    // Helper method for register_early/late_pass
+    fn push_pass<P: LintPass + ?Sized + 'static>(&mut self,
+                                        sess: Option<&Session>,
+                                        from_plugin: bool,
+                                        pass: &Box<P>) {
         for &lint in pass.get_lints() {
             self.lints.push((*lint, from_plugin));
 
@@ -156,7 +178,6 @@ pub fn register_pass(&mut self, sess: Option<&Session>,
                 self.levels.insert(id, (lint.default_level, Default));
             }
         }
-        self.passes.as_mut().unwrap().push(pass);
     }
 
     pub fn register_group(&mut self, sess: Option<&Session>,
@@ -248,8 +269,8 @@ pub fn process_command_line(&mut self, sess: &Session) {
     }
 }
 
-/// Context for lint checking.
-pub struct Context<'a, 'tcx: 'a> {
+/// Context for lint checking after type checking.
+pub struct LateContext<'a, 'tcx: 'a> {
     /// Type context we're checking in.
     pub tcx: &'a ty::ctxt<'tcx>,
 
@@ -272,15 +293,33 @@ pub struct Context<'a, 'tcx: 'a> {
     node_levels: RefCell<FnvHashMap<(ast::NodeId, LintId), LevelSource>>,
 }
 
+/// Context for lint checking of the AST, after expansion, before lowering to
+/// HIR.
+pub struct EarlyContext<'a> {
+    /// Type context we're checking in.
+    pub sess: &'a Session,
+
+    /// The crate being checked.
+    pub krate: &'a ast::Crate,
+
+    /// The store of registered lints.
+    lints: LintStore,
+
+    /// When recursing into an attributed node of the ast which modifies lint
+    /// levels, this stack keeps track of the previous lint levels of whatever
+    /// was modified.
+    level_stack: Vec<(LintId, LevelSource)>,
+}
+
 /// Convenience macro for calling a `LintPass` method on every pass in the context.
-macro_rules! run_lints { ($cx:expr, $f:ident, $($args:expr),*) => ({
+macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({
     // Move the vector of passes out of `$cx` so that we can
     // iterate over it mutably while passing `$cx` to the methods.
-    let mut passes = $cx.lints.passes.take().unwrap();
+    let mut passes = $cx.mut_lints().$ps.take().unwrap();
     for obj in &mut passes {
         obj.$f($cx, $($args),*);
     }
-    $cx.lints.passes = Some(passes);
+    $cx.mut_lints().$ps = Some(passes);
 }) }
 
 /// Parse the lint attributes into a vector, with `Err`s for malformed lint
@@ -364,65 +403,50 @@ pub fn raw_emit_lint(sess: &Session, lint: &'static Lint,
     }
 }
 
-impl<'a, 'tcx> Context<'a, 'tcx> {
-    fn new(tcx: &'a ty::ctxt<'tcx>,
-           krate: &'a hir::Crate,
-           exported_items: &'a ExportedItems) -> Context<'a, 'tcx> {
-        // We want to own the lint store, so move it out of the session.
-        let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
-                                      LintStore::new());
-
-        Context {
-            tcx: tcx,
-            krate: krate,
-            exported_items: exported_items,
-            lints: lint_store,
-            level_stack: vec![],
-            node_levels: RefCell::new(FnvHashMap()),
-        }
-    }
-
-    /// Get the overall compiler `Session` object.
-    pub fn sess(&'a self) -> &'a Session {
-        &self.tcx.sess
-    }
+pub trait LintContext: Sized {
+    fn sess(&self) -> &Session;
+    fn lints(&self) -> &LintStore;
+    fn mut_lints(&mut self) -> &mut LintStore;
+    fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)>;
+    fn enter_attrs(&mut self, attrs: &[ast::Attribute]);
+    fn exit_attrs(&mut self, attrs: &[ast::Attribute]);
 
     /// Get the level of `lint` at the current position of the lint
     /// traversal.
-    pub fn current_level(&self, lint: &'static Lint) -> Level {
-        self.lints.levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
+    fn current_level(&self, lint: &'static Lint) -> Level {
+        self.lints().levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
     }
 
     fn lookup_and_emit(&self, lint: &'static Lint, span: Option<Span>, msg: &str) {
-        let (level, src) = match self.lints.levels.get(&LintId::of(lint)) {
+        let (level, src) = match self.lints().levels.get(&LintId::of(lint)) {
             None => return,
             Some(&(Warn, src)) => {
                 let lint_id = LintId::of(builtin::WARNINGS);
-                (self.lints.get_level_source(lint_id).0, src)
+                (self.lints().get_level_source(lint_id).0, src)
             }
             Some(&pair) => pair,
         };
 
-        raw_emit_lint(&self.tcx.sess, lint, (level, src), span, msg);
-    }
-
-    /// Emit a lint at the appropriate level, with no associated span.
-    pub fn lint(&self, lint: &'static Lint, msg: &str) {
-        self.lookup_and_emit(lint, None, msg);
+        raw_emit_lint(&self.sess(), lint, (level, src), span, msg);
     }
 
     /// Emit a lint at the appropriate level, for a particular span.
-    pub fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) {
+    fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) {
         self.lookup_and_emit(lint, Some(span), msg);
     }
 
+    /// Emit a lint at the appropriate level, with no associated span.
+    fn lint(&self, lint: &'static Lint, msg: &str) {
+        self.lookup_and_emit(lint, None, msg);
+    }
+
     /// Merge the lints specified by any lint attributes into the
     /// current lint context, call the provided function, then reset the
     /// lints in effect to their previous state.
     fn with_lint_attrs<F>(&mut self,
                           attrs: &[ast::Attribute],
-                          f: F) where
-        F: FnOnce(&mut Context),
+                          f: F)
+        where F: FnOnce(&mut Self),
     {
         // Parse all of the lint attributes, and then add them all to the
         // current dictionary of lint information. Along the way, keep a history
@@ -433,14 +457,15 @@ fn with_lint_attrs<F>(&mut self,
         for result in gather_attrs(attrs) {
             let v = match result {
                 Err(span) => {
-                    self.tcx.sess.span_err(span, "malformed lint attribute");
+                    span_err!(self.sess(), span, E0452,
+                              "malformed lint attribute");
                     continue;
                 }
                 Ok((lint_name, level, span)) => {
-                    match self.lints.find_lint(&lint_name, &self.tcx.sess, Some(span)) {
+                    match self.lints().find_lint(&lint_name, &self.sess(), Some(span)) {
                         Ok(lint_id) => vec![(lint_id, level, span)],
                         Err(FindLintError::NotFound) => {
-                            match self.lints.lint_groups.get(&lint_name[..]) {
+                            match self.lints().lint_groups.get(&lint_name[..]) {
                                 Some(&(ref v, _)) => v.iter()
                                                       .map(|lint_id: &LintId|
                                                            (*lint_id, level, span))
@@ -459,35 +484,82 @@ fn with_lint_attrs<F>(&mut self,
             };
 
             for (lint_id, level, span) in v {
-                let now = self.lints.get_level_source(lint_id).0;
+                let now = self.lints().get_level_source(lint_id).0;
                 if now == Forbid && level != Forbid {
                     let lint_name = lint_id.as_str();
-                    self.tcx.sess.span_err(span,
-                                           &format!("{}({}) overruled by outer forbid({})",
-                                                   level.as_str(), lint_name,
-                                                   lint_name));
+                    span_err!(self.sess(), span, E0453,
+                              "{}({}) overruled by outer forbid({})",
+                              level.as_str(), lint_name,
+                              lint_name);
                 } else if now != level {
-                    let src = self.lints.get_level_source(lint_id).1;
-                    self.level_stack.push((lint_id, (now, src)));
+                    let src = self.lints().get_level_source(lint_id).1;
+                    self.level_stack().push((lint_id, (now, src)));
                     pushed += 1;
-                    self.lints.set_level(lint_id, (level, Node(span)));
+                    self.mut_lints().set_level(lint_id, (level, Node(span)));
                 }
             }
         }
 
-        run_lints!(self, enter_lint_attrs, attrs);
+        self.enter_attrs(attrs);
         f(self);
-        run_lints!(self, exit_lint_attrs, attrs);
+        self.exit_attrs(attrs);
 
         // rollback
         for _ in 0..pushed {
-            let (lint, lvlsrc) = self.level_stack.pop().unwrap();
-            self.lints.set_level(lint, lvlsrc);
+            let (lint, lvlsrc) = self.level_stack().pop().unwrap();
+            self.mut_lints().set_level(lint, lvlsrc);
+        }
+    }
+}
+
+
+impl<'a> EarlyContext<'a> {
+    fn new(sess: &'a Session,
+           krate: &'a ast::Crate) -> EarlyContext<'a> {
+        // We want to own the lint store, so move it out of the session. Remember
+        // to put it back later...
+        let lint_store = mem::replace(&mut *sess.lint_store.borrow_mut(),
+                                      LintStore::new());
+        EarlyContext {
+            sess: sess,
+            krate: krate,
+            lints: lint_store,
+            level_stack: vec![],
+        }
+    }
+
+    fn visit_ids<F>(&mut self, f: F)
+        where F: FnOnce(&mut ast_util::IdVisitor<EarlyContext>)
+    {
+        let mut v = ast_util::IdVisitor {
+            operation: self,
+            pass_through_items: false,
+            visited_outermost: false,
+        };
+        f(&mut v);
+    }
+}
+
+impl<'a, 'tcx> LateContext<'a, 'tcx> {
+    fn new(tcx: &'a ty::ctxt<'tcx>,
+           krate: &'a hir::Crate,
+           exported_items: &'a ExportedItems) -> LateContext<'a, 'tcx> {
+        // We want to own the lint store, so move it out of the session.
+        let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
+                                      LintStore::new());
+
+        LateContext {
+            tcx: tcx,
+            krate: krate,
+            exported_items: exported_items,
+            lints: lint_store,
+            level_stack: vec![],
+            node_levels: RefCell::new(FnvHashMap()),
         }
     }
 
-    fn visit_ids<F>(&mut self, f: F) where
-        F: FnOnce(&mut util::IdVisitor<Context>)
+    fn visit_ids<F>(&mut self, f: F)
+        where F: FnOnce(&mut util::IdVisitor<LateContext>)
     {
         let mut v = util::IdVisitor {
             operation: self,
@@ -498,158 +570,378 @@ fn visit_ids<F>(&mut self, f: F) where
     }
 }
 
-impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
+impl<'a, 'tcx> LintContext for LateContext<'a, 'tcx> {
+    /// Get the overall compiler `Session` object.
+    fn sess(&self) -> &Session {
+        &self.tcx.sess
+    }
+
+    fn lints(&self) -> &LintStore {
+        &self.lints
+    }
+
+    fn mut_lints(&mut self) -> &mut LintStore {
+        &mut self.lints
+    }
+
+    fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> {
+        &mut self.level_stack
+    }
+
+    fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
+        run_lints!(self, enter_lint_attrs, late_passes, attrs);
+    }
+
+    fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
+        run_lints!(self, exit_lint_attrs, late_passes, attrs);
+    }
+}
+
+impl<'a> LintContext for EarlyContext<'a> {
+    /// Get the overall compiler `Session` object.
+    fn sess(&self) -> &Session {
+        &self.sess
+    }
+
+    fn lints(&self) -> &LintStore {
+        &self.lints
+    }
+
+    fn mut_lints(&mut self) -> &mut LintStore {
+        &mut self.lints
+    }
+
+    fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> {
+        &mut self.level_stack
+    }
+
+    fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
+        run_lints!(self, enter_lint_attrs, early_passes, attrs);
+    }
+
+    fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
+        run_lints!(self, exit_lint_attrs, early_passes, attrs);
+    }
+}
+
+impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
     fn visit_item(&mut self, it: &hir::Item) {
         self.with_lint_attrs(&it.attrs, |cx| {
-            run_lints!(cx, check_item, it);
+            run_lints!(cx, check_item, late_passes, it);
             cx.visit_ids(|v| v.visit_item(it));
-            visit::walk_item(cx, it);
+            hir_visit::walk_item(cx, it);
         })
     }
 
     fn visit_foreign_item(&mut self, it: &hir::ForeignItem) {
         self.with_lint_attrs(&it.attrs, |cx| {
-            run_lints!(cx, check_foreign_item, it);
-            visit::walk_foreign_item(cx, it);
+            run_lints!(cx, check_foreign_item, late_passes, it);
+            hir_visit::walk_foreign_item(cx, it);
         })
     }
 
     fn visit_pat(&mut self, p: &hir::Pat) {
-        run_lints!(self, check_pat, p);
-        visit::walk_pat(self, p);
+        run_lints!(self, check_pat, late_passes, p);
+        hir_visit::walk_pat(self, p);
     }
 
     fn visit_expr(&mut self, e: &hir::Expr) {
-        run_lints!(self, check_expr, e);
-        visit::walk_expr(self, e);
+        run_lints!(self, check_expr, late_passes, e);
+        hir_visit::walk_expr(self, e);
     }
 
     fn visit_stmt(&mut self, s: &hir::Stmt) {
-        run_lints!(self, check_stmt, s);
-        visit::walk_stmt(self, s);
+        run_lints!(self, check_stmt, late_passes, s);
+        hir_visit::walk_stmt(self, s);
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl,
+    fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
                 body: &'v hir::Block, span: Span, id: ast::NodeId) {
-        run_lints!(self, check_fn, fk, decl, body, span, id);
-        visit::walk_fn(self, fk, decl, body, span);
+        run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
+        hir_visit::walk_fn(self, fk, decl, body, span);
     }
 
     fn visit_struct_def(&mut self,
                         s: &hir::StructDef,
-                        ident: ast::Ident,
+                        name: ast::Name,
                         g: &hir::Generics,
                         id: ast::NodeId) {
-        run_lints!(self, check_struct_def, s, ident, g, id);
-        visit::walk_struct_def(self, s);
-        run_lints!(self, check_struct_def_post, s, ident, g, id);
+        run_lints!(self, check_struct_def, late_passes, s, name, g, id);
+        hir_visit::walk_struct_def(self, s);
+        run_lints!(self, check_struct_def_post, late_passes, s, name, g, id);
     }
 
     fn visit_struct_field(&mut self, s: &hir::StructField) {
         self.with_lint_attrs(&s.node.attrs, |cx| {
-            run_lints!(cx, check_struct_field, s);
-            visit::walk_struct_field(cx, s);
+            run_lints!(cx, check_struct_field, late_passes, s);
+            hir_visit::walk_struct_field(cx, s);
         })
     }
 
     fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics) {
         self.with_lint_attrs(&v.node.attrs, |cx| {
-            run_lints!(cx, check_variant, v, g);
-            visit::walk_variant(cx, v, g);
-            run_lints!(cx, check_variant_post, v, g);
+            run_lints!(cx, check_variant, late_passes, v, g);
+            hir_visit::walk_variant(cx, v, g);
+            run_lints!(cx, check_variant_post, late_passes, v, g);
         })
     }
 
     fn visit_ty(&mut self, t: &hir::Ty) {
-        run_lints!(self, check_ty, t);
-        visit::walk_ty(self, t);
+        run_lints!(self, check_ty, late_passes, t);
+        hir_visit::walk_ty(self, t);
     }
 
-    fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
-        run_lints!(self, check_ident, sp, id);
+    fn visit_name(&mut self, sp: Span, name: ast::Name) {
+        run_lints!(self, check_name, late_passes, sp, name);
     }
 
     fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) {
-        run_lints!(self, check_mod, m, s, n);
-        visit::walk_mod(self, m);
+        run_lints!(self, check_mod, late_passes, m, s, n);
+        hir_visit::walk_mod(self, m);
     }
 
     fn visit_local(&mut self, l: &hir::Local) {
-        run_lints!(self, check_local, l);
-        visit::walk_local(self, l);
+        run_lints!(self, check_local, late_passes, l);
+        hir_visit::walk_local(self, l);
     }
 
     fn visit_block(&mut self, b: &hir::Block) {
-        run_lints!(self, check_block, b);
-        visit::walk_block(self, b);
+        run_lints!(self, check_block, late_passes, b);
+        hir_visit::walk_block(self, b);
     }
 
     fn visit_arm(&mut self, a: &hir::Arm) {
-        run_lints!(self, check_arm, a);
-        visit::walk_arm(self, a);
+        run_lints!(self, check_arm, late_passes, a);
+        hir_visit::walk_arm(self, a);
     }
 
     fn visit_decl(&mut self, d: &hir::Decl) {
-        run_lints!(self, check_decl, d);
-        visit::walk_decl(self, d);
+        run_lints!(self, check_decl, late_passes, d);
+        hir_visit::walk_decl(self, d);
     }
 
     fn visit_expr_post(&mut self, e: &hir::Expr) {
-        run_lints!(self, check_expr_post, e);
+        run_lints!(self, check_expr_post, late_passes, e);
     }
 
     fn visit_generics(&mut self, g: &hir::Generics) {
-        run_lints!(self, check_generics, g);
-        visit::walk_generics(self, g);
+        run_lints!(self, check_generics, late_passes, g);
+        hir_visit::walk_generics(self, g);
     }
 
     fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
         self.with_lint_attrs(&trait_item.attrs, |cx| {
-            run_lints!(cx, check_trait_item, trait_item);
+            run_lints!(cx, check_trait_item, late_passes, trait_item);
             cx.visit_ids(|v| v.visit_trait_item(trait_item));
-            visit::walk_trait_item(cx, trait_item);
+            hir_visit::walk_trait_item(cx, trait_item);
         });
     }
 
     fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
         self.with_lint_attrs(&impl_item.attrs, |cx| {
-            run_lints!(cx, check_impl_item, impl_item);
+            run_lints!(cx, check_impl_item, late_passes, impl_item);
             cx.visit_ids(|v| v.visit_impl_item(impl_item));
-            visit::walk_impl_item(cx, impl_item);
+            hir_visit::walk_impl_item(cx, impl_item);
         });
     }
 
     fn visit_opt_lifetime_ref(&mut self, sp: Span, lt: &Option<hir::Lifetime>) {
-        run_lints!(self, check_opt_lifetime_ref, sp, lt);
+        run_lints!(self, check_opt_lifetime_ref, late_passes, sp, lt);
     }
 
     fn visit_lifetime_ref(&mut self, lt: &hir::Lifetime) {
-        run_lints!(self, check_lifetime_ref, lt);
+        run_lints!(self, check_lifetime_ref, late_passes, lt);
     }
 
     fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) {
-        run_lints!(self, check_lifetime_def, lt);
+        run_lints!(self, check_lifetime_def, late_passes, lt);
     }
 
     fn visit_explicit_self(&mut self, es: &hir::ExplicitSelf) {
-        run_lints!(self, check_explicit_self, es);
-        visit::walk_explicit_self(self, es);
+        run_lints!(self, check_explicit_self, late_passes, es);
+        hir_visit::walk_explicit_self(self, es);
     }
 
     fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) {
-        run_lints!(self, check_path, p, id);
-        visit::walk_path(self, p);
+        run_lints!(self, check_path, late_passes, p, id);
+        hir_visit::walk_path(self, p);
+    }
+
+    fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
+        run_lints!(self, check_path_list_item, late_passes, item);
+        hir_visit::walk_path_list_item(self, prefix, item);
+    }
+
+    fn visit_attribute(&mut self, attr: &ast::Attribute) {
+        run_lints!(self, check_attribute, late_passes, attr);
+    }
+}
+
+impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
+    fn visit_item(&mut self, it: &ast::Item) {
+        self.with_lint_attrs(&it.attrs, |cx| {
+            run_lints!(cx, check_item, early_passes, it);
+            cx.visit_ids(|v| v.visit_item(it));
+            ast_visit::walk_item(cx, it);
+        })
+    }
+
+    fn visit_foreign_item(&mut self, it: &ast::ForeignItem) {
+        self.with_lint_attrs(&it.attrs, |cx| {
+            run_lints!(cx, check_foreign_item, early_passes, it);
+            ast_visit::walk_foreign_item(cx, it);
+        })
+    }
+
+    fn visit_pat(&mut self, p: &ast::Pat) {
+        run_lints!(self, check_pat, early_passes, p);
+        ast_visit::walk_pat(self, p);
+    }
+
+    fn visit_expr(&mut self, e: &ast::Expr) {
+        run_lints!(self, check_expr, early_passes, e);
+        ast_visit::walk_expr(self, e);
+    }
+
+    fn visit_stmt(&mut self, s: &ast::Stmt) {
+        run_lints!(self, check_stmt, early_passes, s);
+        ast_visit::walk_stmt(self, s);
+    }
+
+    fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, decl: &'v ast::FnDecl,
+                body: &'v ast::Block, span: Span, id: ast::NodeId) {
+        run_lints!(self, check_fn, early_passes, fk, decl, body, span, id);
+        ast_visit::walk_fn(self, fk, decl, body, span);
+    }
+
+    fn visit_struct_def(&mut self,
+                        s: &ast::StructDef,
+                        ident: ast::Ident,
+                        g: &ast::Generics,
+                        id: ast::NodeId) {
+        run_lints!(self, check_struct_def, early_passes, s, ident, g, id);
+        ast_visit::walk_struct_def(self, s);
+        run_lints!(self, check_struct_def_post, early_passes, s, ident, g, id);
+    }
+
+    fn visit_struct_field(&mut self, s: &ast::StructField) {
+        self.with_lint_attrs(&s.node.attrs, |cx| {
+            run_lints!(cx, check_struct_field, early_passes, s);
+            ast_visit::walk_struct_field(cx, s);
+        })
+    }
+
+    fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics) {
+        self.with_lint_attrs(&v.node.attrs, |cx| {
+            run_lints!(cx, check_variant, early_passes, v, g);
+            ast_visit::walk_variant(cx, v, g);
+            run_lints!(cx, check_variant_post, early_passes, v, g);
+        })
+    }
+
+    fn visit_ty(&mut self, t: &ast::Ty) {
+        run_lints!(self, check_ty, early_passes, t);
+        ast_visit::walk_ty(self, t);
+    }
+
+    fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
+        run_lints!(self, check_ident, early_passes, sp, id);
+    }
+
+    fn visit_mod(&mut self, m: &ast::Mod, s: Span, n: ast::NodeId) {
+        run_lints!(self, check_mod, early_passes, m, s, n);
+        ast_visit::walk_mod(self, m);
+    }
+
+    fn visit_local(&mut self, l: &ast::Local) {
+        run_lints!(self, check_local, early_passes, l);
+        ast_visit::walk_local(self, l);
+    }
+
+    fn visit_block(&mut self, b: &ast::Block) {
+        run_lints!(self, check_block, early_passes, b);
+        ast_visit::walk_block(self, b);
+    }
+
+    fn visit_arm(&mut self, a: &ast::Arm) {
+        run_lints!(self, check_arm, early_passes, a);
+        ast_visit::walk_arm(self, a);
+    }
+
+    fn visit_decl(&mut self, d: &ast::Decl) {
+        run_lints!(self, check_decl, early_passes, d);
+        ast_visit::walk_decl(self, d);
+    }
+
+    fn visit_expr_post(&mut self, e: &ast::Expr) {
+        run_lints!(self, check_expr_post, early_passes, e);
+    }
+
+    fn visit_generics(&mut self, g: &ast::Generics) {
+        run_lints!(self, check_generics, early_passes, g);
+        ast_visit::walk_generics(self, g);
+    }
+
+    fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
+        self.with_lint_attrs(&trait_item.attrs, |cx| {
+            run_lints!(cx, check_trait_item, early_passes, trait_item);
+            cx.visit_ids(|v| v.visit_trait_item(trait_item));
+            ast_visit::walk_trait_item(cx, trait_item);
+        });
+    }
+
+    fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
+        self.with_lint_attrs(&impl_item.attrs, |cx| {
+            run_lints!(cx, check_impl_item, early_passes, impl_item);
+            cx.visit_ids(|v| v.visit_impl_item(impl_item));
+            ast_visit::walk_impl_item(cx, impl_item);
+        });
+    }
+
+    fn visit_lifetime(&mut self, lt: &ast::Lifetime) {
+        run_lints!(self, check_lifetime, early_passes, lt);
+    }
+
+    fn visit_lifetime_def(&mut self, lt: &ast::LifetimeDef) {
+        run_lints!(self, check_lifetime_def, early_passes, lt);
+    }
+
+    fn visit_explicit_self(&mut self, es: &ast::ExplicitSelf) {
+        run_lints!(self, check_explicit_self, early_passes, es);
+        ast_visit::walk_explicit_self(self, es);
+    }
+
+    fn visit_path(&mut self, p: &ast::Path, id: ast::NodeId) {
+        run_lints!(self, check_path, early_passes, p, id);
+        ast_visit::walk_path(self, p);
+    }
+
+    fn visit_path_list_item(&mut self, prefix: &ast::Path, item: &ast::PathListItem) {
+        run_lints!(self, check_path_list_item, early_passes, item);
+        ast_visit::walk_path_list_item(self, prefix, item);
     }
 
     fn visit_attribute(&mut self, attr: &ast::Attribute) {
-        run_lints!(self, check_attribute, attr);
+        run_lints!(self, check_attribute, early_passes, attr);
     }
 }
 
 // Output any lints that were previously added to the session.
-impl<'a, 'tcx> IdVisitingOperation for Context<'a, 'tcx> {
+impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> {
+    fn visit_id(&mut self, id: ast::NodeId) {
+        match self.sess().lints.borrow_mut().remove(&id) {
+            None => {}
+            Some(lints) => {
+                for (lint_id, span, msg) in lints {
+                    self.span_lint(lint_id.lint, span, &msg[..])
+                }
+            }
+        }
+    }
+}
+impl<'a> IdVisitingOperation for EarlyContext<'a> {
     fn visit_id(&mut self, id: ast::NodeId) {
-        match self.tcx.sess.lints.borrow_mut().remove(&id) {
+        match self.sess.lints.borrow_mut().remove(&id) {
             None => {}
             Some(lints) => {
                 for (lint_id, span, msg) in lints {
@@ -660,7 +952,7 @@ fn visit_id(&mut self, id: ast::NodeId) {
     }
 }
 
-// This lint pass is defined here because it touches parts of the `Context`
+// This lint pass is defined here because it touches parts of the `LateContext`
 // that we don't want to expose. It records the lint level at certain AST
 // nodes, so that the variant size difference check in trans can call
 // `raw_emit_lint`.
@@ -671,8 +963,10 @@ impl LintPass for GatherNodeLevels {
     fn get_lints(&self) -> LintArray {
         lint_array!()
     }
+}
 
-    fn check_item(&mut self, cx: &Context, it: &hir::Item) {
+impl LateLintPass for GatherNodeLevels {
+    fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         match it.node {
             hir::ItemEnum(..) => {
                 let lint_id = LintId::of(builtin::VARIANT_SIZE_DIFFERENCES);
@@ -697,21 +991,21 @@ pub fn check_crate(tcx: &ty::ctxt,
                    krate: &hir::Crate,
                    exported_items: &ExportedItems) {
 
-    let mut cx = Context::new(tcx, krate, exported_items);
+    let mut cx = LateContext::new(tcx, krate, exported_items);
 
     // Visit the whole crate.
     cx.with_lint_attrs(&krate.attrs, |cx| {
         cx.visit_id(ast::CRATE_NODE_ID);
         cx.visit_ids(|v| {
             v.visited_outermost = true;
-            visit::walk_crate(v, krate);
+            hir_visit::walk_crate(v, krate);
         });
 
         // since the root module isn't visited as an item (because it isn't an
         // item), warn for it here.
-        run_lints!(cx, check_crate, krate);
+        run_lints!(cx, check_crate, late_passes, krate);
 
-        visit::walk_crate(cx, krate);
+        hir_visit::walk_crate(cx, krate);
     });
 
     // If we missed any lints added to the session, then there's a bug somewhere
@@ -726,3 +1020,35 @@ pub fn check_crate(tcx: &ty::ctxt,
 
     *tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
 }
+
+pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
+    let mut cx = EarlyContext::new(sess, krate);
+
+    // Visit the whole crate.
+    cx.with_lint_attrs(&krate.attrs, |cx| {
+        cx.visit_id(ast::CRATE_NODE_ID);
+        cx.visit_ids(|v| {
+            v.visited_outermost = true;
+            ast_visit::walk_crate(v, krate);
+        });
+
+        // since the root module isn't visited as an item (because it isn't an
+        // item), warn for it here.
+        run_lints!(cx, check_crate, early_passes, krate);
+
+        ast_visit::walk_crate(cx, krate);
+    });
+
+    // Put the lint store back in the session.
+    mem::replace(&mut *sess.lint_store.borrow_mut(), cx.lints);
+
+    // If we missed any lints added to the session, then there's a bug somewhere
+    // in the iteration code.
+    for (_, v) in sess.lints.borrow().iter() {
+        for &(lint, span, ref msg) in v {
+            sess.span_bug(span,
+                          &format!("unprocessed lint {}: {}",
+                                   lint.as_str(), *msg))
+        }
+    }
+}