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 rustc_front::attr::{self, AttrMetaMethods};
-use rustc_front::util;
+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 syntax::visit::Visitor as SyntaxVisitor;
+use rustc_front::util;
+use rustc_front::visit as hir_visit;
+use syntax::visit as ast_visit;
use syntax::diagnostic;
/// Information about the registered lints.
/// 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>,
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(),
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));
self.levels.insert(id, (lint.default_level, Default));
}
}
- self.passes.as_mut().unwrap().push(pass);
}
pub fn register_group(&mut self, sess: Option<&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>,
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
/// attributes. Writing this as an iterator is an enormous mess.
// See also the hir version just below.
-pub fn gather_attrs(attrs: &[hir::Attribute])
+pub fn gather_attrs(attrs: &[ast::Attribute])
-> Vec<Result<(InternedString, Level, Span), Span>> {
let mut out = vec!();
for attr in attrs {
let meta = &attr.node.value;
let metas = match meta.node {
- hir::MetaList(_, ref metas) => metas,
+ ast::MetaList(_, ref metas) => metas,
_ => {
out.push(Err(meta.span));
continue;
for meta in metas {
out.push(match meta.node {
- hir::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)),
- _ => Err(meta.span),
- });
- }
- }
- out
-}
-// Copy-pasted from the above function :-(
-pub fn gather_attrs_from_hir(attrs: &[::rustc_front::hir::Attribute])
- -> Vec<Result<(InternedString, Level, Span), Span>> {
- use ::rustc_front::attr::AttrMetaMethods;
-
- let mut out = vec!();
- for attr in attrs {
- let level = match Level::from_str(&attr.name()) {
- None => continue,
- Some(lvl) => lvl,
- };
-
- ::rustc_front::attr::mark_used(attr);
-
- let meta = &attr.node.value;
- let metas = match meta.node {
- ::rustc_front::hir::MetaList(_, ref metas) => metas,
- _ => {
- out.push(Err(meta.span));
- continue;
- }
- };
-
- for meta in metas {
- out.push(match meta.node {
- ::rustc_front::hir::MetaWord(ref lint_name) => {
- Ok((lint_name.clone(), level, meta.span))
- }
+ ast::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)),
_ => Err(meta.span),
});
}
}
}
-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: &[hir::Attribute],
- f: F) where
- F: FnOnce(&mut Context),
+ attrs: &[ast::Attribute],
+ 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
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))
};
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);
}
}
+}
+
- fn visit_ids<F>(&mut self, f: F) where
- F: FnOnce(&mut util::IdVisitor<Context>)
+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<LateContext>)
{
let mut v = util::IdVisitor {
operation: self,
}
}
-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_attribute(&mut self, attr: &hir::Attribute) {
- run_lints!(self, check_attribute, attr);
+ 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, 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 {
}
}
-// 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`.
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);
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
*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))
+ }
+ }
+}