context.rs 26.3 KB
Newer Older
1
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of lint checking.
//!
//! The lint checking is mostly consolidated into one pass which runs just
//! before translation to LLVM bytecode. Throughout compilation, lint warnings
//! can be added via the `add_lint` method on the Session structure. This
//! requires a span and an id of the node that the lint is being added to. The
//! lint isn't actually emitted at that time because it is unknown what the
//! actual lint level at that location is.
//!
//! To actually emit lint warnings/errors, a separate pass is used just before
//! translation. A context keeps track of the current state of all lint levels.
//! Upon entering a node of the ast which can modify the lint settings, the
//! previous lint state is pushed onto a stack and the ast is then recursed
//! upon.  As the ast is traversed, this keeps track of the current lint level
//! for all lint attributes.
S
Steven Fackler 已提交
26
use self::TargetLint::*;
27 28

use middle::privacy::ExportedItems;
29
use middle::ty::{self, Ty};
30
use session::{early_error, Session};
31
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass, LintPassObject};
32
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
33
use lint::builtin;
34
use util::nodemap::FnvHashMap;
35 36

use std::cell::RefCell;
37
use std::cmp;
38 39
use std::mem;
use syntax::ast_util::IdVisitingOperation;
M
Manish Goregaokar 已提交
40 41
use rustc_front::attr::{self, AttrMetaMethods};
use rustc_front::util;
42
use syntax::codemap::Span;
43
use syntax::parse::token::InternedString;
M
Manish Goregaokar 已提交
44 45 46 47
use syntax::ast;
use rustc_front::hir;
use rustc_front::visit::{self, Visitor, FnKind};
use syntax::visit::Visitor as SyntaxVisitor;
48
use syntax::diagnostic;
49 50 51 52 53 54 55 56 57 58 59

/// Information about the registered lints.
///
/// This is basically the subset of `Context` that we can
/// build early in the compile pipeline.
pub struct LintStore {
    /// Registered lints. The bool is true if the lint was
    /// added by a plugin.
    lints: Vec<(&'static Lint, bool)>,

    /// Trait objects for each lint pass.
60 61 62
    /// This is only `None` while iterating over the objects. See the definition
    /// of run_lints.
    passes: Option<Vec<LintPassObject>>,
63 64

    /// Lints indexed by name.
65
    by_name: FnvHashMap<String, TargetLint>,
66 67

    /// Current levels of each lint, and where they were set.
68
    levels: FnvHashMap<LintId, LevelSource>,
69 70 71

    /// Map of registered lint groups to what lints they expand to. The bool
    /// is true if the lint group was added by a plugin.
72
    lint_groups: FnvHashMap<&'static str, (Vec<LintId>, bool)>,
73 74 75

    /// Maximum level a lint can be
    lint_cap: Option<Level>,
76 77
}

78 79 80 81 82 83 84
/// The targed of the `by_name` map, which accounts for renaming/deprecation.
enum TargetLint {
    /// A direct lint target
    Id(LintId),

    /// Temporary renaming, used for easing migration pain; see #16545
    Renamed(String, LintId),
85 86 87 88 89 90 91 92 93

    /// Lint with this name existed previously, but has been removed/deprecated.
    /// The string argument is the reason for removal.
    Removed(String),
}

enum FindLintError {
    NotFound,
    Removed
94 95
}

96 97
impl LintStore {
    fn get_level_source(&self, lint: LintId) -> LevelSource {
98
        match self.levels.get(&lint) {
99 100 101 102 103
            Some(&s) => s,
            None => (Allow, Default),
        }
    }

104 105 106 107
    fn set_level(&mut self, lint: LintId, mut lvlsrc: LevelSource) {
        if let Some(cap) = self.lint_cap {
            lvlsrc.0 = cmp::min(lvlsrc.0, cap);
        }
J
Jorge Aparicio 已提交
108
        if lvlsrc.0 == Allow {
109 110 111 112 113 114 115 116 117
            self.levels.remove(&lint);
        } else {
            self.levels.insert(lint, lvlsrc);
        }
    }

    pub fn new() -> LintStore {
        LintStore {
            lints: vec!(),
118
            passes: Some(vec!()),
119 120 121
            by_name: FnvHashMap(),
            levels: FnvHashMap(),
            lint_groups: FnvHashMap(),
122
            lint_cap: None,
123 124 125 126
        }
    }

    pub fn get_lints<'t>(&'t self) -> &'t [(&'static Lint, bool)] {
127
        &self.lints
128 129
    }

130
    pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
131
        self.lint_groups.iter().map(|(k, v)| (*k,
J
Jorge Aparicio 已提交
132 133
                                              v.0.clone(),
                                              v.1)).collect()
134 135
    }

136 137
    pub fn register_pass(&mut self, sess: Option<&Session>,
                         from_plugin: bool, pass: LintPassObject) {
138
        for &lint in pass.get_lints() {
139
            self.lints.push((*lint, from_plugin));
140

141
            let id = LintId::of(*lint);
142
            if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
143
                let msg = format!("duplicate specification of lint {}", lint.name_lower());
144 145 146
                match (sess, from_plugin) {
                    // We load builtin lints first, so a duplicate is a compiler bug.
                    // Use early_error when handling -W help with no crate.
147
                    (None, _) => early_error(diagnostic::Auto, &msg[..]),
148
                    (Some(sess), false) => sess.bug(&msg[..]),
149 150

                    // A duplicate name from a plugin is a user error.
151
                    (Some(sess), true)  => sess.err(&msg[..]),
152 153 154 155 156 157 158
                }
            }

            if lint.default_level != Allow {
                self.levels.insert(id, (lint.default_level, Default));
            }
        }
159
        self.passes.as_mut().unwrap().push(pass);
160 161
    }

162 163 164
    pub fn register_group(&mut self, sess: Option<&Session>,
                          from_plugin: bool, name: &'static str,
                          to: Vec<LintId>) {
165
        let new = self.lint_groups.insert(name, (to, from_plugin)).is_none();
166 167 168 169 170 171

        if !new {
            let msg = format!("duplicate specification of lint group {}", name);
            match (sess, from_plugin) {
                // We load builtin lints first, so a duplicate is a compiler bug.
                // Use early_error when handling -W help with no crate.
172
                (None, _) => early_error(diagnostic::Auto, &msg[..]),
173
                (Some(sess), false) => sess.bug(&msg[..]),
174 175

                // A duplicate name from a plugin is a user error.
176
                (Some(sess), true)  => sess.err(&msg[..]),
177 178 179 180
            }
        }
    }

181
    pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
A
Aaron Turon 已提交
182
        let target = match self.by_name.get(new_name) {
183
            Some(&Id(lint_id)) => lint_id.clone(),
S
Steve Klabnik 已提交
184
            _ => panic!("invalid lint renaming of {} to {}", old_name, new_name)
185 186 187 188
        };
        self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
    }

189 190 191 192
    pub fn register_removed(&mut self, name: &str, reason: &str) {
        self.by_name.insert(name.into(), Removed(reason.into()));
    }

A
Alex Crichton 已提交
193
    #[allow(unused_variables)]
194
    fn find_lint(&self, lint_name: &str, sess: &Session, span: Option<Span>)
195
                 -> Result<LintId, FindLintError>
196
    {
A
Aaron Turon 已提交
197
        match self.by_name.get(lint_name) {
198
            Some(&Id(lint_id)) => Ok(lint_id),
199
            Some(&Renamed(ref new_name, lint_id)) => {
200 201 202
                let warning = format!("lint {} has been renamed to {}",
                                      lint_name, new_name);
                match span {
203 204
                    Some(span) => sess.span_warn(span, &warning[..]),
                    None => sess.warn(&warning[..]),
205
                };
206 207 208 209 210 211 212 213 214 215 216
                Ok(lint_id)
            },
            Some(&Removed(ref reason)) => {
                let warning = format!("lint {} has been removed: {}", lint_name, reason);
                match span {
                    Some(span) => sess.span_warn(span, &warning[..]),
                    None => sess.warn(&warning[..])
                }
                Err(FindLintError::Removed)
            },
            None => Err(FindLintError::NotFound)
217
        }
218 219 220
    }

    pub fn process_command_line(&mut self, sess: &Session) {
221
        for &(ref lint_name, level) in &sess.opts.lint_opts {
222
            match self.find_lint(&lint_name[..], sess, None) {
223 224
                Ok(lint_id) => self.set_level(lint_id, (level, CommandLine)),
                Err(_) => {
J
Jorge Aparicio 已提交
225
                    match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone()))
226 227
                                                 .collect::<FnvHashMap<&'static str,
                                                                       Vec<LintId>>>()
228
                                                 .get(&lint_name[..]) {
229 230 231 232 233 234
                        Some(v) => {
                            v.iter()
                             .map(|lint_id: &LintId|
                                     self.set_level(*lint_id, (level, CommandLine)))
                             .collect::<Vec<()>>();
                        }
J
Jorge Aparicio 已提交
235
                        None => sess.err(&format!("unknown {} flag: {}",
236
                                                 level.as_str(), lint_name)),
237 238
                    }
                }
239 240
            }
        }
241 242 243 244 245 246 247

        self.lint_cap = sess.opts.lint_cap;
        if let Some(cap) = self.lint_cap {
            for level in self.levels.iter_mut().map(|p| &mut (p.1).0) {
                *level = cmp::min(*level, cap);
            }
        }
248 249 250 251
    }
}

/// Context for lint checking.
252
pub struct Context<'a, 'tcx: 'a> {
253
    /// Type context we're checking in.
254
    pub tcx: &'a ty::ctxt<'tcx>,
255

256
    /// The crate being checked.
M
Manish Goregaokar 已提交
257
    pub krate: &'a hir::Crate,
258 259 260 261

    /// Items exported from the crate being checked.
    pub exported_items: &'a ExportedItems,

262 263 264 265 266 267 268 269 270 271
    /// 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)>,

    /// Level of lints for certain NodeIds, stored here because the body of
    /// the lint needs to run in trans.
272
    node_levels: RefCell<FnvHashMap<(ast::NodeId, LintId), LevelSource>>,
273 274 275
}

/// Convenience macro for calling a `LintPass` method on every pass in the context.
276
macro_rules! run_lints { ($cx:expr, $f:ident, $($args:expr),*) => ({
277 278
    // Move the vector of passes out of `$cx` so that we can
    // iterate over it mutably while passing `$cx` to the methods.
279
    let mut passes = $cx.lints.passes.take().unwrap();
280
    for obj in &mut passes {
281
        obj.$f($cx, $($args),*);
282
    }
283
    $cx.lints.passes = Some(passes);
284
}) }
285

286 287
/// Parse the lint attributes into a vector, with `Err`s for malformed lint
/// attributes. Writing this as an iterator is an enormous mess.
288
// See also the hir version just below.
M
Manish Goregaokar 已提交
289
pub fn gather_attrs(attrs: &[hir::Attribute])
290 291
                    -> Vec<Result<(InternedString, Level, Span), Span>> {
    let mut out = vec!();
292
    for attr in attrs {
293
        let level = match Level::from_str(&attr.name()) {
294 295 296 297 298 299
            None => continue,
            Some(lvl) => lvl,
        };

        attr::mark_used(attr);

300
        let meta = &attr.node.value;
301
        let metas = match meta.node {
M
Manish Goregaokar 已提交
302
            hir::MetaList(_, ref metas) => metas,
303 304 305 306 307 308
            _ => {
                out.push(Err(meta.span));
                continue;
            }
        };

309
        for meta in metas {
310
            out.push(match meta.node {
M
Manish Goregaokar 已提交
311
                hir::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)),
312 313 314 315 316 317
                _ => Err(meta.span),
            });
        }
    }
    out
}
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
// 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))
                }
                _ => Err(meta.span),
            });
        }
    }
    out
}
352

353 354 355 356 357 358 359 360 361 362 363 364
/// Emit a lint as a warning or an error (or not at all)
/// according to `level`.
///
/// This lives outside of `Context` so it can be used by checks
/// in trans that run after the main lint pass is finished. Most
/// lints elsewhere in the compiler should call
/// `Session::add_lint()` instead.
pub fn raw_emit_lint(sess: &Session, lint: &'static Lint,
                     lvlsrc: LevelSource, span: Option<Span>, msg: &str) {
    let (mut level, source) = lvlsrc;
    if level == Allow { return }

365
    let name = lint.name_lower();
B
Brian Anderson 已提交
366
    let mut def = None;
367 368 369
    let msg = match source {
        Default => {
            format!("{}, #[{}({})] on by default", msg,
370
                    level.as_str(), name)
371 372 373
        },
        CommandLine => {
            format!("{} [-{} {}]", msg,
374 375
                    match level {
                        Warn => 'W', Deny => 'D', Forbid => 'F',
S
Steve Klabnik 已提交
376
                        Allow => panic!()
377
                    }, name.replace("_", "-"))
378 379
        },
        Node(src) => {
B
Brian Anderson 已提交
380 381 382
            def = Some(src);
            msg.to_string()
        }
383 384 385 386 387 388
    };

    // For purposes of printing, we can treat forbid as deny.
    if level == Forbid { level = Deny; }

    match (level, span) {
389 390 391 392
        (Warn, Some(sp)) => sess.span_warn(sp, &msg[..]),
        (Warn, None)     => sess.warn(&msg[..]),
        (Deny, Some(sp)) => sess.span_err(sp, &msg[..]),
        (Deny, None)     => sess.err(&msg[..]),
393 394 395
        _ => sess.bug("impossible level in raw_emit_lint"),
    }

396
    if let Some(span) = def {
397 398 399 400
        sess.span_note(span, "lint level defined here");
    }
}

401 402
impl<'a, 'tcx> Context<'a, 'tcx> {
    fn new(tcx: &'a ty::ctxt<'tcx>,
M
Manish Goregaokar 已提交
403
           krate: &'a hir::Crate,
404
           exported_items: &'a ExportedItems) -> Context<'a, 'tcx> {
405 406
        // 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(),
407
                                      LintStore::new());
408 409 410

        Context {
            tcx: tcx,
411 412 413
            krate: krate,
            exported_items: exported_items,
            lints: lint_store,
414
            level_stack: vec![],
415
            node_levels: RefCell::new(FnvHashMap()),
416 417 418 419 420 421 422 423
        }
    }

    /// Get the overall compiler `Session` object.
    pub fn sess(&'a self) -> &'a Session {
        &self.tcx.sess
    }

424 425 426
    /// Get the level of `lint` at the current position of the lint
    /// traversal.
    pub fn current_level(&self, lint: &'static Lint) -> Level {
427
        self.lints.levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
428 429
    }

430
    fn lookup_and_emit(&self, lint: &'static Lint, span: Option<Span>, msg: &str) {
431
        let (level, src) = match self.lints.levels.get(&LintId::of(lint)) {
432 433
            None => return,
            Some(&(Warn, src)) => {
434
                let lint_id = LintId::of(builtin::WARNINGS);
J
Jorge Aparicio 已提交
435
                (self.lints.get_level_source(lint_id).0, src)
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
            }
            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);
    }

    /// Emit a lint at the appropriate level, for a particular span.
    pub fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) {
        self.lookup_and_emit(lint, Some(span), msg);
    }

S
Steve Klabnik 已提交
453 454 455
    /// 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.
J
Jorge Aparicio 已提交
456
    fn with_lint_attrs<F>(&mut self,
M
Manish Goregaokar 已提交
457
                          attrs: &[hir::Attribute],
J
Jorge Aparicio 已提交
458 459 460
                          f: F) where
        F: FnOnce(&mut Context),
    {
461 462 463 464
        // Parse all of the lint attributes, and then add them all to the
        // current dictionary of lint information. Along the way, keep a history
        // of what we changed so we can roll everything back after invoking the
        // specified closure
465
        let mut pushed = 0;
466

467
        for result in gather_attrs(attrs) {
468
            let v = match result {
469 470 471 472 473
                Err(span) => {
                    self.tcx.sess.span_err(span, "malformed lint attribute");
                    continue;
                }
                Ok((lint_name, level, span)) => {
474
                    match self.lints.find_lint(&lint_name, &self.tcx.sess, Some(span)) {
475 476
                        Ok(lint_id) => vec![(lint_id, level, span)],
                        Err(FindLintError::NotFound) => {
477
                            match self.lints.lint_groups.get(&lint_name[..]) {
478 479 480 481 482
                                Some(&(ref v, _)) => v.iter()
                                                      .map(|lint_id: &LintId|
                                                           (*lint_id, level, span))
                                                      .collect(),
                                None => {
A
Aaron Turon 已提交
483
                                    self.span_lint(builtin::UNKNOWN_LINTS, span,
484 485
                                                   &format!("unknown `{}` attribute: `{}`",
                                                            level.as_str(), lint_name));
486 487 488
                                    continue;
                                }
                            }
489 490
                        },
                        Err(FindLintError::Removed) => { continue; }
491 492 493 494
                    }
                }
            };

495
            for (lint_id, level, span) in v {
J
Jorge Aparicio 已提交
496
                let now = self.lints.get_level_source(lint_id).0;
497 498 499
                if now == Forbid && level != Forbid {
                    let lint_name = lint_id.as_str();
                    self.tcx.sess.span_err(span,
J
Jorge Aparicio 已提交
500
                                           &format!("{}({}) overruled by outer forbid({})",
501
                                                   level.as_str(), lint_name,
502
                                                   lint_name));
503
                } else if now != level {
J
Jorge Aparicio 已提交
504
                    let src = self.lints.get_level_source(lint_id).1;
505 506 507 508
                    self.level_stack.push((lint_id, (now, src)));
                    pushed += 1;
                    self.lints.set_level(lint_id, (level, Node(span)));
                }
509 510 511 512 513 514 515 516
            }
        }

        run_lints!(self, enter_lint_attrs, attrs);
        f(self);
        run_lints!(self, exit_lint_attrs, attrs);

        // rollback
517
        for _ in 0..pushed {
518 519 520 521 522
            let (lint, lvlsrc) = self.level_stack.pop().unwrap();
            self.lints.set_level(lint, lvlsrc);
        }
    }

J
Jorge Aparicio 已提交
523
    fn visit_ids<F>(&mut self, f: F) where
M
Manish Goregaokar 已提交
524
        F: FnOnce(&mut util::IdVisitor<Context>)
J
Jorge Aparicio 已提交
525
    {
M
Manish Goregaokar 已提交
526
        let mut v = util::IdVisitor {
527 528 529 530 531 532 533 534
            operation: self,
            pass_through_items: false,
            visited_outermost: false,
        };
        f(&mut v);
    }
}

535
impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
M
Manish Goregaokar 已提交
536
    fn visit_item(&mut self, it: &hir::Item) {
537
        self.with_lint_attrs(&it.attrs, |cx| {
538
            run_lints!(cx, check_item, it);
539 540
            cx.visit_ids(|v| v.visit_item(it));
            visit::walk_item(cx, it);
541 542 543
        })
    }

M
Manish Goregaokar 已提交
544
    fn visit_foreign_item(&mut self, it: &hir::ForeignItem) {
545
        self.with_lint_attrs(&it.attrs, |cx| {
546
            run_lints!(cx, check_foreign_item, it);
547
            visit::walk_foreign_item(cx, it);
548 549 550
        })
    }

M
Manish Goregaokar 已提交
551
    fn visit_pat(&mut self, p: &hir::Pat) {
552
        run_lints!(self, check_pat, p);
553
        visit::walk_pat(self, p);
554 555
    }

M
Manish Goregaokar 已提交
556
    fn visit_expr(&mut self, e: &hir::Expr) {
557
        run_lints!(self, check_expr, e);
558
        visit::walk_expr(self, e);
559 560
    }

M
Manish Goregaokar 已提交
561
    fn visit_stmt(&mut self, s: &hir::Stmt) {
562
        run_lints!(self, check_stmt, s);
563
        visit::walk_stmt(self, s);
564 565
    }

M
Manish Goregaokar 已提交
566 567
    fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl,
                body: &'v hir::Block, span: Span, id: ast::NodeId) {
568 569
        run_lints!(self, check_fn, fk, decl, body, span, id);
        visit::walk_fn(self, fk, decl, body, span);
570 571 572
    }

    fn visit_struct_def(&mut self,
M
Manish Goregaokar 已提交
573
                        s: &hir::StructDef,
574
                        ident: ast::Ident,
M
Manish Goregaokar 已提交
575
                        g: &hir::Generics,
576
                        id: ast::NodeId) {
577
        run_lints!(self, check_struct_def, s, ident, g, id);
578
        visit::walk_struct_def(self, s);
579 580 581
        run_lints!(self, check_struct_def_post, s, ident, g, id);
    }

M
Manish Goregaokar 已提交
582
    fn visit_struct_field(&mut self, s: &hir::StructField) {
583
        self.with_lint_attrs(&s.node.attrs, |cx| {
584
            run_lints!(cx, check_struct_field, s);
585
            visit::walk_struct_field(cx, s);
586 587 588
        })
    }

M
Manish Goregaokar 已提交
589
    fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics) {
590
        self.with_lint_attrs(&v.node.attrs, |cx| {
591
            run_lints!(cx, check_variant, v, g);
592
            visit::walk_variant(cx, v, g);
S
Steven Fackler 已提交
593
            run_lints!(cx, check_variant_post, v, g);
594 595 596
        })
    }

M
Manish Goregaokar 已提交
597
    fn visit_ty(&mut self, t: &hir::Ty) {
598
        run_lints!(self, check_ty, t);
599
        visit::walk_ty(self, t);
600 601
    }

602
    fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
603 604 605
        run_lints!(self, check_ident, sp, id);
    }

M
Manish Goregaokar 已提交
606
    fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) {
607
        run_lints!(self, check_mod, m, s, n);
608
        visit::walk_mod(self, m);
609 610
    }

M
Manish Goregaokar 已提交
611
    fn visit_local(&mut self, l: &hir::Local) {
612
        run_lints!(self, check_local, l);
613
        visit::walk_local(self, l);
614 615
    }

M
Manish Goregaokar 已提交
616
    fn visit_block(&mut self, b: &hir::Block) {
617
        run_lints!(self, check_block, b);
618
        visit::walk_block(self, b);
619 620
    }

M
Manish Goregaokar 已提交
621
    fn visit_arm(&mut self, a: &hir::Arm) {
622
        run_lints!(self, check_arm, a);
623
        visit::walk_arm(self, a);
624 625
    }

M
Manish Goregaokar 已提交
626
    fn visit_decl(&mut self, d: &hir::Decl) {
627
        run_lints!(self, check_decl, d);
628
        visit::walk_decl(self, d);
629 630
    }

M
Manish Goregaokar 已提交
631
    fn visit_expr_post(&mut self, e: &hir::Expr) {
632 633 634
        run_lints!(self, check_expr_post, e);
    }

M
Manish Goregaokar 已提交
635
    fn visit_generics(&mut self, g: &hir::Generics) {
636
        run_lints!(self, check_generics, g);
637
        visit::walk_generics(self, g);
638 639
    }

M
Manish Goregaokar 已提交
640
    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
641 642 643 644 645 646 647
        self.with_lint_attrs(&trait_item.attrs, |cx| {
            run_lints!(cx, check_trait_item, trait_item);
            cx.visit_ids(|v| v.visit_trait_item(trait_item));
            visit::walk_trait_item(cx, trait_item);
        });
    }

M
Manish Goregaokar 已提交
648
    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
649 650 651 652 653
        self.with_lint_attrs(&impl_item.attrs, |cx| {
            run_lints!(cx, check_impl_item, impl_item);
            cx.visit_ids(|v| v.visit_impl_item(impl_item));
            visit::walk_impl_item(cx, impl_item);
        });
654 655
    }

M
Manish Goregaokar 已提交
656
    fn visit_opt_lifetime_ref(&mut self, sp: Span, lt: &Option<hir::Lifetime>) {
657 658 659
        run_lints!(self, check_opt_lifetime_ref, sp, lt);
    }

M
Manish Goregaokar 已提交
660
    fn visit_lifetime_ref(&mut self, lt: &hir::Lifetime) {
661 662 663
        run_lints!(self, check_lifetime_ref, lt);
    }

M
Manish Goregaokar 已提交
664
    fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) {
665
        run_lints!(self, check_lifetime_def, lt);
666 667
    }

M
Manish Goregaokar 已提交
668
    fn visit_explicit_self(&mut self, es: &hir::ExplicitSelf) {
669
        run_lints!(self, check_explicit_self, es);
670
        visit::walk_explicit_self(self, es);
671 672
    }

M
Manish Goregaokar 已提交
673
    fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) {
674
        run_lints!(self, check_path, p, id);
675
        visit::walk_path(self, p);
676 677
    }

M
Manish Goregaokar 已提交
678
    fn visit_attribute(&mut self, attr: &hir::Attribute) {
679 680 681 682 683
        run_lints!(self, check_attribute, attr);
    }
}

// Output any lints that were previously added to the session.
684
impl<'a, 'tcx> IdVisitingOperation for Context<'a, 'tcx> {
A
Ariel Ben-Yehuda 已提交
685
    fn visit_id(&mut self, id: ast::NodeId) {
686
        match self.tcx.sess.lints.borrow_mut().remove(&id) {
687 688
            None => {}
            Some(lints) => {
689
                for (lint_id, span, msg) in lints {
690
                    self.span_lint(lint_id.lint, span, &msg[..])
691 692 693 694 695 696 697 698 699 700 701
                }
            }
        }
    }
}

// This lint pass is defined here because it touches parts of the `Context`
// 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`.

702
pub struct GatherNodeLevels;
703 704 705 706 707 708

impl LintPass for GatherNodeLevels {
    fn get_lints(&self) -> LintArray {
        lint_array!()
    }

M
Manish Goregaokar 已提交
709
    fn check_item(&mut self, cx: &Context, it: &hir::Item) {
710
        match it.node {
M
Manish Goregaokar 已提交
711
            hir::ItemEnum(..) => {
A
Aaron Turon 已提交
712
                let lint_id = LintId::of(builtin::VARIANT_SIZE_DIFFERENCES);
713 714 715
                let lvlsrc = cx.lints.get_level_source(lint_id);
                match lvlsrc {
                    (lvl, _) if lvl != Allow => {
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
                        cx.node_levels.borrow_mut()
                            .insert((it.id, lint_id), lvlsrc);
                    },
                    _ => { }
                }
            },
            _ => { }
        }
    }
}

/// Perform lint checking on a crate.
///
/// Consumes the `lint_store` field of the `Session`.
pub fn check_crate(tcx: &ty::ctxt,
M
Manish Goregaokar 已提交
731
                   krate: &hir::Crate,
732
                   exported_items: &ExportedItems) {
B
Brian Anderson 已提交
733

734
    let mut cx = Context::new(tcx, krate, exported_items);
735 736

    // Visit the whole crate.
737
    cx.with_lint_attrs(&krate.attrs, |cx| {
738 739 740
        cx.visit_id(ast::CRATE_NODE_ID);
        cx.visit_ids(|v| {
            v.visited_outermost = true;
741
            visit::walk_crate(v, krate);
742 743 744 745
        });

        // since the root module isn't visited as an item (because it isn't an
        // item), warn for it here.
746
        run_lints!(cx, check_crate, krate);
747

748
        visit::walk_crate(cx, krate);
749 750 751 752
    });

    // If we missed any lints added to the session, then there's a bug somewhere
    // in the iteration code.
753
    for (id, v) in tcx.sess.lints.borrow().iter() {
754
        for &(lint, span, ref msg) in v {
755
            tcx.sess.span_bug(span,
756 757
                              &format!("unprocessed lint {} at {}: {}",
                                       lint.as_str(), tcx.map.node_to_string(*id), *msg))
758 759 760
        }
    }

761
    *tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
762
}