context.rs 45.6 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 dep_graph::DepNode;
29
use middle::privacy::AccessLevels;
J
Jeffrey Seyfried 已提交
30
use middle::ty;
31
use session::{config, early_error, Session};
N
Nick Cameron 已提交
32 33
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
use lint::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject};
34
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
35
use lint::builtin;
36
use util::nodemap::FnvHashMap;
37 38

use std::cell::RefCell;
39
use std::cmp;
40
use std::default::Default as StdDefault;
41
use std::mem;
42
use syntax::ast_util::{self, IdVisitingOperation};
43
use syntax::attr::{self, AttrMetaMethods};
44
use syntax::codemap::Span;
45
use syntax::errors::DiagnosticBuilder;
46
use syntax::parse::token::InternedString;
47 48
use syntax::ast;
use syntax::attr::ThinAttributesExt;
M
Manish Goregaokar 已提交
49
use rustc_front::hir;
50
use rustc_front::util;
51
use rustc_front::intravisit as hir_visit;
52
use syntax::visit as ast_visit;
53 54 55 56 57 58 59 60 61 62 63

/// 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.
64 65
    /// This is only `None` while iterating over the objects. See the definition
    /// of run_lints.
N
Nick Cameron 已提交
66 67
    early_passes: Option<Vec<EarlyLintPassObject>>,
    late_passes: Option<Vec<LateLintPassObject>>,
68 69

    /// Lints indexed by name.
70
    by_name: FnvHashMap<String, TargetLint>,
71 72

    /// Current levels of each lint, and where they were set.
73
    levels: FnvHashMap<LintId, LevelSource>,
74 75 76

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

79 80 81 82
    /// Extra info for future incompatibility lints, descibing the
    /// issue or RFC that caused the incompatibility.
    future_incompatible: FnvHashMap<LintId, FutureIncompatibleInfo>,

83 84
    /// Maximum level a lint can be
    lint_cap: Option<Level>,
85 86
}

87 88 89 90 91 92 93 94
/// Extra information for a future incompatibility lint. See the call
/// to `register_future_incompatible` in `librustc_lint/lib.rs` for
/// guidelines.
pub struct FutureIncompatibleInfo {
    pub id: LintId,
    pub reference: &'static str // e.g., a URL for an issue/PR/RFC or error code
}

95 96 97 98 99 100 101
/// 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),
102 103 104 105 106 107 108 109 110

    /// 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
111 112
}

113 114
impl LintStore {
    fn get_level_source(&self, lint: LintId) -> LevelSource {
115
        match self.levels.get(&lint) {
116 117 118 119 120
            Some(&s) => s,
            None => (Allow, Default),
        }
    }

121 122 123 124
    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 已提交
125
        if lvlsrc.0 == Allow {
126 127 128 129 130 131 132 133 134
            self.levels.remove(&lint);
        } else {
            self.levels.insert(lint, lvlsrc);
        }
    }

    pub fn new() -> LintStore {
        LintStore {
            lints: vec!(),
N
Nick Cameron 已提交
135 136
            early_passes: Some(vec!()),
            late_passes: Some(vec!()),
137 138
            by_name: FnvHashMap(),
            levels: FnvHashMap(),
139
            future_incompatible: FnvHashMap(),
140
            lint_groups: FnvHashMap(),
141
            lint_cap: None,
142 143 144 145
        }
    }

    pub fn get_lints<'t>(&'t self) -> &'t [(&'static Lint, bool)] {
146
        &self.lints
147 148
    }

149
    pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
150
        self.lint_groups.iter().map(|(k, v)| (*k,
J
Jorge Aparicio 已提交
151 152
                                              v.0.clone(),
                                              v.1)).collect()
153 154
    }

N
Nick Cameron 已提交
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    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>) {
176
        for &lint in pass.get_lints() {
177
            self.lints.push((*lint, from_plugin));
178

179
            let id = LintId::of(*lint);
180
            if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
181
                let msg = format!("duplicate specification of lint {}", lint.name_lower());
182 183 184
                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.
185
                    (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
186
                    (Some(sess), false) => sess.bug(&msg[..]),
187 188

                    // A duplicate name from a plugin is a user error.
189
                    (Some(sess), true)  => sess.err(&msg[..]),
190 191 192 193 194 195 196 197 198
                }
            }

            if lint.default_level != Allow {
                self.levels.insert(id, (lint.default_level, Default));
            }
        }
    }

199 200 201 202 203 204 205 206 207 208 209 210 211 212
    pub fn register_future_incompatible(&mut self,
                                        sess: Option<&Session>,
                                        lints: Vec<FutureIncompatibleInfo>) {
        let ids = lints.iter().map(|f| f.id).collect();
        self.register_group(sess, false, "future_incompatible", ids);
        for info in lints {
            self.future_incompatible.insert(info.id, info);
        }
    }

    pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
        self.future_incompatible.get(&id)
    }

213 214 215
    pub fn register_group(&mut self, sess: Option<&Session>,
                          from_plugin: bool, name: &'static str,
                          to: Vec<LintId>) {
216
        let new = self.lint_groups.insert(name, (to, from_plugin)).is_none();
217 218 219 220 221 222

        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.
223
                (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
224
                (Some(sess), false) => sess.bug(&msg[..]),
225 226

                // A duplicate name from a plugin is a user error.
227
                (Some(sess), true)  => sess.err(&msg[..]),
228 229 230 231
            }
        }
    }

232
    pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
A
Aaron Turon 已提交
233
        let target = match self.by_name.get(new_name) {
234
            Some(&Id(lint_id)) => lint_id.clone(),
S
Steve Klabnik 已提交
235
            _ => panic!("invalid lint renaming of {} to {}", old_name, new_name)
236 237 238 239
        };
        self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
    }

240 241 242 243
    pub fn register_removed(&mut self, name: &str, reason: &str) {
        self.by_name.insert(name.into(), Removed(reason.into()));
    }

A
Alex Crichton 已提交
244
    #[allow(unused_variables)]
245
    fn find_lint(&self, lint_name: &str, sess: &Session, span: Option<Span>)
246
                 -> Result<LintId, FindLintError>
247
    {
A
Aaron Turon 已提交
248
        match self.by_name.get(lint_name) {
249
            Some(&Id(lint_id)) => Ok(lint_id),
250
            Some(&Renamed(_, lint_id)) => {
251 252 253 254 255 256
                Ok(lint_id)
            },
            Some(&Removed(ref reason)) => {
                Err(FindLintError::Removed)
            },
            None => Err(FindLintError::NotFound)
257
        }
258 259 260
    }

    pub fn process_command_line(&mut self, sess: &Session) {
261
        for &(ref lint_name, level) in &sess.opts.lint_opts {
262 263 264
            check_lint_name_cmdline(sess, self,
                                    &lint_name[..], level);

265
            match self.find_lint(&lint_name[..], sess, None) {
266
                Ok(lint_id) => self.set_level(lint_id, (level, CommandLine)),
267
                Err(FindLintError::Removed) => { }
268
                Err(_) => {
J
Jorge Aparicio 已提交
269
                    match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone()))
270 271
                                                 .collect::<FnvHashMap<&'static str,
                                                                       Vec<LintId>>>()
272
                                                 .get(&lint_name[..]) {
273 274 275 276 277 278
                        Some(v) => {
                            v.iter()
                             .map(|lint_id: &LintId|
                                     self.set_level(*lint_id, (level, CommandLine)))
                             .collect::<Vec<()>>();
                        }
279 280 281 282 283
                        None => {
                            // The lint or lint group doesn't exist.
                            // This is an error, but it was handled
                            // by check_lint_name_cmdline.
                        }
284 285
                    }
                }
286 287
            }
        }
288 289 290 291 292 293 294

        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);
            }
        }
295 296 297
    }
}

298 299
/// Context for lint checking after type checking.
pub struct LateContext<'a, 'tcx: 'a> {
300
    /// Type context we're checking in.
301
    pub tcx: &'a ty::ctxt<'tcx>,
302

303
    /// The crate being checked.
M
Manish Goregaokar 已提交
304
    pub krate: &'a hir::Crate,
305

306 307
    /// Items accessible from the crate being checked.
    pub access_levels: &'a AccessLevels,
308

309 310 311 312 313 314 315 316 317 318
    /// 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.
319
    node_levels: RefCell<FnvHashMap<(ast::NodeId, LintId), LevelSource>>,
320 321
}

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
/// 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)>,
}

340
/// Convenience macro for calling a `LintPass` method on every pass in the context.
N
Nick Cameron 已提交
341
macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({
342 343
    // Move the vector of passes out of `$cx` so that we can
    // iterate over it mutably while passing `$cx` to the methods.
N
Nick Cameron 已提交
344
    let mut passes = $cx.mut_lints().$ps.take().unwrap();
345
    for obj in &mut passes {
346
        obj.$f($cx, $($args),*);
347
    }
N
Nick Cameron 已提交
348
    $cx.mut_lints().$ps = Some(passes);
349
}) }
350

351 352
/// Parse the lint attributes into a vector, with `Err`s for malformed lint
/// attributes. Writing this as an iterator is an enormous mess.
353
// See also the hir version just below.
354
pub fn gather_attrs(attrs: &[ast::Attribute])
355 356
                    -> Vec<Result<(InternedString, Level, Span), Span>> {
    let mut out = vec!();
357
    for attr in attrs {
358 359 360 361 362
        let r = gather_attr(attr);
        out.extend(r.into_iter());
    }
    out
}
363

364 365 366
pub fn gather_attr(attr: &ast::Attribute)
                   -> Vec<Result<(InternedString, Level, Span), Span>> {
    let mut out = vec!();
367

368 369 370 371
    let level = match Level::from_str(&attr.name()) {
        None => return out,
        Some(lvl) => lvl,
    };
372

373 374 375 376
    attr::mark_used(attr);

    let meta = &attr.node.value;
    let metas = match meta.node {
377
        ast::MetaItemKind::List(_, ref metas) => metas,
378 379 380
        _ => {
            out.push(Err(meta.span));
            return out;
381
        }
382 383 384 385
    };

    for meta in metas {
        out.push(match meta.node {
386
            ast::MetaItemKind::Word(ref lint_name) => Ok((lint_name.clone(), level, meta.span)),
387 388
            _ => Err(meta.span),
        });
389
    }
390

391 392
    out
}
393

394 395 396 397 398 399 400
/// 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.
N
Nick Cameron 已提交
401
pub fn raw_emit_lint(sess: &Session,
402
                     lints: &LintStore,
N
Nick Cameron 已提交
403 404 405 406
                     lint: &'static Lint,
                     lvlsrc: LevelSource,
                     span: Option<Span>,
                     msg: &str) {
407
    raw_struct_lint(sess, lints, lint, lvlsrc, span, msg).emit();
N
Nick Cameron 已提交
408 409 410
}

pub fn raw_struct_lint<'a>(sess: &'a Session,
411
                           lints: &LintStore,
N
Nick Cameron 已提交
412 413 414 415
                           lint: &'static Lint,
                           lvlsrc: LevelSource,
                           span: Option<Span>,
                           msg: &str)
N
Nick Cameron 已提交
416
                           -> DiagnosticBuilder<'a> {
417
    let (mut level, source) = lvlsrc;
N
Nick Cameron 已提交
418
    if level == Allow {
N
Nick Cameron 已提交
419
        return sess.diagnostic().struct_dummy();
N
Nick Cameron 已提交
420
    }
421

422
    let name = lint.name_lower();
B
Brian Anderson 已提交
423
    let mut def = None;
424 425 426
    let msg = match source {
        Default => {
            format!("{}, #[{}({})] on by default", msg,
427
                    level.as_str(), name)
428 429 430
        },
        CommandLine => {
            format!("{} [-{} {}]", msg,
431 432
                    match level {
                        Warn => 'W', Deny => 'D', Forbid => 'F',
S
Steve Klabnik 已提交
433
                        Allow => panic!()
434
                    }, name.replace("_", "-"))
435 436
        },
        Node(src) => {
B
Brian Anderson 已提交
437 438 439
            def = Some(src);
            msg.to_string()
        }
440 441 442 443 444
    };

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

N
Nick Cameron 已提交
445 446 447 448 449
    let mut err = match (level, span) {
        (Warn, Some(sp)) => sess.struct_span_warn(sp, &msg[..]),
        (Warn, None)     => sess.struct_warn(&msg[..]),
        (Deny, Some(sp)) => sess.struct_span_err(sp, &msg[..]),
        (Deny, None)     => sess.struct_err(&msg[..]),
450
        _ => sess.bug("impossible level in raw_emit_lint"),
N
Nick Cameron 已提交
451
    };
452

453
    // Check for future incompatibility lints and issue a stronger warning.
454 455
    if let Some(future_incompatible) = lints.future_incompatible(LintId::of(lint)) {
        let explanation = format!("this was previously accepted by the compiler \
N
Niko Matsakis 已提交
456 457
                                   but is being phased out; \
                                   it will become a hard error in a future release!");
458 459
        let citation = format!("for more information, see {}",
                               future_incompatible.reference);
460
        if let Some(sp) = span {
461 462
            err.fileline_warn(sp, &explanation);
            err.fileline_note(sp, &citation);
463
        } else {
464 465
            err.warn(&explanation);
            err.note(&citation);
466 467 468
        }
    }

469
    if let Some(span) = def {
N
Nick Cameron 已提交
470
        err.span_note(span, "lint level defined here");
471
    }
N
Nick Cameron 已提交
472 473

    err
474 475
}

476 477 478 479 480
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)>;
N
Nick Cameron 已提交
481 482
    fn enter_attrs(&mut self, attrs: &[ast::Attribute]);
    fn exit_attrs(&mut self, attrs: &[ast::Attribute]);
483

484 485
    /// Get the level of `lint` at the current position of the lint
    /// traversal.
486 487
    fn current_level(&self, lint: &'static Lint) -> Level {
        self.lints().levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
488 489
    }

N
Nick Cameron 已提交
490 491 492
    fn level_src(&self, lint: &'static Lint) -> Option<LevelSource> {
        self.lints().levels.get(&LintId::of(lint)).map(|ls| match ls {
            &(Warn, src) => {
493
                let lint_id = LintId::of(builtin::WARNINGS);
494
                (self.lints().get_level_source(lint_id).0, src)
495
            }
N
Nick Cameron 已提交
496 497 498 499 500 501 502 503
            _ => *ls
        })
    }

    fn lookup_and_emit(&self, lint: &'static Lint, span: Option<Span>, msg: &str) {
        let (level, src) = match self.level_src(lint) {
            None => return,
            Some(pair) => pair,
504 505
        };

506
        raw_emit_lint(&self.sess(), self.lints(), lint, (level, src), span, msg);
507 508
    }

N
Nick Cameron 已提交
509 510 511 512
    fn lookup(&self,
              lint: &'static Lint,
              span: Option<Span>,
              msg: &str)
N
Nick Cameron 已提交
513
              -> DiagnosticBuilder {
N
Nick Cameron 已提交
514
        let (level, src) = match self.level_src(lint) {
N
Nick Cameron 已提交
515
            None => return self.sess().diagnostic().struct_dummy(),
N
Nick Cameron 已提交
516 517 518
            Some(pair) => pair,
        };

519
        raw_struct_lint(&self.sess(), self.lints(), lint, (level, src), span, msg)
N
Nick Cameron 已提交
520 521
    }

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

N
Nick Cameron 已提交
527 528 529 530
    fn struct_span_lint(&self,
                        lint: &'static Lint,
                        span: Span,
                        msg: &str)
N
Nick Cameron 已提交
531
                        -> DiagnosticBuilder {
N
Nick Cameron 已提交
532 533 534
        self.lookup(lint, Some(span), msg)
    }

535 536 537
    /// Emit a lint and note at the appropriate level, for a particular span.
    fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str,
                      note_span: Span, note: &str) {
N
Nick Cameron 已提交
538
        let mut err = self.lookup(lint, Some(span), msg);
539 540
        if self.current_level(lint) != Level::Allow {
            if note_span == span {
N
Nick Cameron 已提交
541
                err.fileline_note(note_span, note);
542
            } else {
N
Nick Cameron 已提交
543
                err.span_note(note_span, note);
544 545
            }
        }
N
Nick Cameron 已提交
546
        err.emit();
547 548 549 550 551
    }

    /// Emit a lint and help at the appropriate level, for a particular span.
    fn span_lint_help(&self, lint: &'static Lint, span: Span,
                      msg: &str, help: &str) {
N
Nick Cameron 已提交
552
        let mut err = self.lookup(lint, Some(span), msg);
553 554
        self.span_lint(lint, span, msg);
        if self.current_level(lint) != Level::Allow {
N
Nick Cameron 已提交
555
            err.span_help(span, help);
556
        }
N
Nick Cameron 已提交
557
        err.emit();
558 559
    }

560 561 562 563 564
    /// 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);
    }

S
Steve Klabnik 已提交
565 566 567
    /// 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 已提交
568
    fn with_lint_attrs<F>(&mut self,
569
                          attrs: &[ast::Attribute],
570 571
                          f: F)
        where F: FnOnce(&mut Self),
J
Jorge Aparicio 已提交
572
    {
573 574 575 576
        // 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
577
        let mut pushed = 0;
578

579
        for result in gather_attrs(attrs) {
580
            let v = match result {
581
                Err(span) => {
582
                    span_err!(self.sess(), span, E0452,
583
                              "malformed lint attribute");
584 585 586
                    continue;
                }
                Ok((lint_name, level, span)) => {
587
                    match self.lints().find_lint(&lint_name, &self.sess(), Some(span)) {
588 589
                        Ok(lint_id) => vec![(lint_id, level, span)],
                        Err(FindLintError::NotFound) => {
590
                            match self.lints().lint_groups.get(&lint_name[..]) {
591 592 593 594 595
                                Some(&(ref v, _)) => v.iter()
                                                      .map(|lint_id: &LintId|
                                                           (*lint_id, level, span))
                                                      .collect(),
                                None => {
596 597 598
                                    // The lint or lint group doesn't exist.
                                    // This is an error, but it was handled
                                    // by check_lint_name_attribute.
599 600 601
                                    continue;
                                }
                            }
602 603
                        },
                        Err(FindLintError::Removed) => { continue; }
604 605 606 607
                    }
                }
            };

608
            for (lint_id, level, span) in v {
609
                let now = self.lints().get_level_source(lint_id).0;
610 611
                if now == Forbid && level != Forbid {
                    let lint_name = lint_id.as_str();
612
                    span_err!(self.sess(), span, E0453,
613 614 615
                              "{}({}) overruled by outer forbid({})",
                              level.as_str(), lint_name,
                              lint_name);
616
                } else if now != level {
617 618
                    let src = self.lints().get_level_source(lint_id).1;
                    self.level_stack().push((lint_id, (now, src)));
619
                    pushed += 1;
620
                    self.mut_lints().set_level(lint_id, (level, Node(span)));
621
                }
622 623 624
            }
        }

625
        self.enter_attrs(attrs);
626
        f(self);
627
        self.exit_attrs(attrs);
628 629

        // rollback
630
        for _ in 0..pushed {
631 632 633 634 635 636 637 638 639 640
            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> {
N
Nick Cameron 已提交
641 642
        // We want to own the lint store, so move it out of the session. Remember
        // to put it back later...
643 644 645 646 647 648 649
        let lint_store = mem::replace(&mut *sess.lint_store.borrow_mut(),
                                      LintStore::new());
        EarlyContext {
            sess: sess,
            krate: krate,
            lints: lint_store,
            level_stack: vec![],
650 651 652
        }
    }

653 654 655 656 657 658 659 660 661 662 663 664 665 666
    fn visit_ids<F>(&mut self, f: F)
        where F: FnOnce(&mut ast_util::IdVisitor<EarlyContext>)
    {
        let mut v = ast_util::IdVisitor {
            operation: self,
            visited_outermost: false,
        };
        f(&mut v);
    }
}

impl<'a, 'tcx> LateContext<'a, 'tcx> {
    fn new(tcx: &'a ty::ctxt<'tcx>,
           krate: &'a hir::Crate,
667
           access_levels: &'a AccessLevels) -> LateContext<'a, 'tcx> {
668 669 670 671 672 673 674
        // 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,
675
            access_levels: access_levels,
676 677 678 679 680 681 682 683
            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>)
J
Jorge Aparicio 已提交
684
    {
685
        let mut v = util::IdVisitor::new(self);
686 687 688 689
        f(&mut v);
    }
}

690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
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
    }

N
Nick Cameron 已提交
708
    fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
709
        debug!("late context: enter_attrs({:?})", attrs);
N
Nick Cameron 已提交
710
        run_lints!(self, enter_lint_attrs, late_passes, attrs);
711 712
    }

N
Nick Cameron 已提交
713
    fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
714
        debug!("late context: exit_attrs({:?})", attrs);
N
Nick Cameron 已提交
715
        run_lints!(self, exit_lint_attrs, late_passes, attrs);
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
    }
}

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
    }

N
Nick Cameron 已提交
737
    fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
738
        debug!("early context: enter_attrs({:?})", attrs);
N
Nick Cameron 已提交
739
        run_lints!(self, enter_lint_attrs, early_passes, attrs);
740 741
    }

N
Nick Cameron 已提交
742
    fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
743
        debug!("early context: exit_attrs({:?})", attrs);
N
Nick Cameron 已提交
744
        run_lints!(self, exit_lint_attrs, early_passes, attrs);
745 746 747 748
    }
}

impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
749 750 751 752 753 754 755
    /// Because lints are scoped lexically, we want to walk nested
    /// items in the context of the outer item, so enable
    /// deep-walking.
    fn visit_nested_item(&mut self, item: hir::ItemId) {
        self.visit_item(self.tcx.map.expect_item(item.id))
    }

M
Manish Goregaokar 已提交
756
    fn visit_item(&mut self, it: &hir::Item) {
757
        self.with_lint_attrs(&it.attrs, |cx| {
N
Nick Cameron 已提交
758
            run_lints!(cx, check_item, late_passes, it);
759
            cx.visit_ids(|v| v.visit_item(it));
760
            hir_visit::walk_item(cx, it);
L
llogiq 已提交
761
            run_lints!(cx, check_item_post, late_passes, it);
762 763 764
        })
    }

M
Manish Goregaokar 已提交
765
    fn visit_foreign_item(&mut self, it: &hir::ForeignItem) {
766
        self.with_lint_attrs(&it.attrs, |cx| {
N
Nick Cameron 已提交
767
            run_lints!(cx, check_foreign_item, late_passes, it);
768
            hir_visit::walk_foreign_item(cx, it);
769 770 771
        })
    }

M
Manish Goregaokar 已提交
772
    fn visit_pat(&mut self, p: &hir::Pat) {
N
Nick Cameron 已提交
773
        run_lints!(self, check_pat, late_passes, p);
774
        hir_visit::walk_pat(self, p);
775 776
    }

M
Manish Goregaokar 已提交
777
    fn visit_expr(&mut self, e: &hir::Expr) {
778
        self.with_lint_attrs(e.attrs.as_attr_slice(), |cx| {
779 780 781
            run_lints!(cx, check_expr, late_passes, e);
            hir_visit::walk_expr(cx, e);
        })
782 783
    }

M
Manish Goregaokar 已提交
784
    fn visit_stmt(&mut self, s: &hir::Stmt) {
785 786 787 788 789
        // statement attributes are actually just attributes on one of
        // - item
        // - local
        // - expression
        // so we keep track of lint levels there
N
Nick Cameron 已提交
790
        run_lints!(self, check_stmt, late_passes, s);
791
        hir_visit::walk_stmt(self, s);
792 793
    }

794
    fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
M
Manish Goregaokar 已提交
795
                body: &'v hir::Block, span: Span, id: ast::NodeId) {
N
Nick Cameron 已提交
796
        run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
797
        hir_visit::walk_fn(self, fk, decl, body, span);
798 799
    }

800 801
    fn visit_variant_data(&mut self,
                        s: &hir::VariantData,
802
                        name: ast::Name,
M
Manish Goregaokar 已提交
803
                        g: &hir::Generics,
804 805
                        item_id: ast::NodeId,
                        _: Span) {
806
        run_lints!(self, check_struct_def, late_passes, s, name, g, item_id);
807
        hir_visit::walk_struct_def(self, s);
808
        run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id);
809 810
    }

M
Manish Goregaokar 已提交
811
    fn visit_struct_field(&mut self, s: &hir::StructField) {
812
        self.with_lint_attrs(&s.node.attrs, |cx| {
N
Nick Cameron 已提交
813
            run_lints!(cx, check_struct_field, late_passes, s);
814
            hir_visit::walk_struct_field(cx, s);
815 816 817
        })
    }

818
    fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
819
        self.with_lint_attrs(&v.node.attrs, |cx| {
N
Nick Cameron 已提交
820
            run_lints!(cx, check_variant, late_passes, v, g);
821
            hir_visit::walk_variant(cx, v, g, item_id);
N
Nick Cameron 已提交
822
            run_lints!(cx, check_variant_post, late_passes, v, g);
823 824 825
        })
    }

M
Manish Goregaokar 已提交
826
    fn visit_ty(&mut self, t: &hir::Ty) {
N
Nick Cameron 已提交
827
        run_lints!(self, check_ty, late_passes, t);
828
        hir_visit::walk_ty(self, t);
829 830
    }

831 832
    fn visit_name(&mut self, sp: Span, name: ast::Name) {
        run_lints!(self, check_name, late_passes, sp, name);
833 834
    }

M
Manish Goregaokar 已提交
835
    fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) {
N
Nick Cameron 已提交
836
        run_lints!(self, check_mod, late_passes, m, s, n);
837
        hir_visit::walk_mod(self, m);
838 839
    }

M
Manish Goregaokar 已提交
840
    fn visit_local(&mut self, l: &hir::Local) {
841
        self.with_lint_attrs(l.attrs.as_attr_slice(), |cx| {
842 843 844
            run_lints!(cx, check_local, late_passes, l);
            hir_visit::walk_local(cx, l);
        })
845 846
    }

M
Manish Goregaokar 已提交
847
    fn visit_block(&mut self, b: &hir::Block) {
N
Nick Cameron 已提交
848
        run_lints!(self, check_block, late_passes, b);
849
        hir_visit::walk_block(self, b);
L
llogiq 已提交
850
        run_lints!(self, check_block_post, late_passes, b);
851 852
    }

M
Manish Goregaokar 已提交
853
    fn visit_arm(&mut self, a: &hir::Arm) {
N
Nick Cameron 已提交
854
        run_lints!(self, check_arm, late_passes, a);
855
        hir_visit::walk_arm(self, a);
856 857
    }

M
Manish Goregaokar 已提交
858
    fn visit_decl(&mut self, d: &hir::Decl) {
N
Nick Cameron 已提交
859
        run_lints!(self, check_decl, late_passes, d);
860
        hir_visit::walk_decl(self, d);
861 862
    }

M
Manish Goregaokar 已提交
863
    fn visit_expr_post(&mut self, e: &hir::Expr) {
N
Nick Cameron 已提交
864
        run_lints!(self, check_expr_post, late_passes, e);
865 866
    }

M
Manish Goregaokar 已提交
867
    fn visit_generics(&mut self, g: &hir::Generics) {
N
Nick Cameron 已提交
868
        run_lints!(self, check_generics, late_passes, g);
869
        hir_visit::walk_generics(self, g);
870 871
    }

M
Manish Goregaokar 已提交
872
    fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
873
        self.with_lint_attrs(&trait_item.attrs, |cx| {
N
Nick Cameron 已提交
874
            run_lints!(cx, check_trait_item, late_passes, trait_item);
875
            cx.visit_ids(|v| v.visit_trait_item(trait_item));
876
            hir_visit::walk_trait_item(cx, trait_item);
877 878 879
        });
    }

M
Manish Goregaokar 已提交
880
    fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
881
        self.with_lint_attrs(&impl_item.attrs, |cx| {
N
Nick Cameron 已提交
882
            run_lints!(cx, check_impl_item, late_passes, impl_item);
883
            cx.visit_ids(|v| v.visit_impl_item(impl_item));
884
            hir_visit::walk_impl_item(cx, impl_item);
885
        });
886 887
    }

888 889
    fn visit_lifetime(&mut self, lt: &hir::Lifetime) {
        run_lints!(self, check_lifetime, late_passes, lt);
890 891
    }

M
Manish Goregaokar 已提交
892
    fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) {
N
Nick Cameron 已提交
893
        run_lints!(self, check_lifetime_def, late_passes, lt);
894 895
    }

M
Manish Goregaokar 已提交
896
    fn visit_explicit_self(&mut self, es: &hir::ExplicitSelf) {
N
Nick Cameron 已提交
897
        run_lints!(self, check_explicit_self, late_passes, es);
898
        hir_visit::walk_explicit_self(self, es);
899 900
    }

M
Manish Goregaokar 已提交
901
    fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) {
N
Nick Cameron 已提交
902
        run_lints!(self, check_path, late_passes, p, id);
903
        hir_visit::walk_path(self, p);
904 905
    }

V
Vadim Petrochenkov 已提交
906 907 908 909 910
    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);
    }

911
    fn visit_attribute(&mut self, attr: &ast::Attribute) {
912
        check_lint_name_attribute(self, attr);
N
Nick Cameron 已提交
913
        run_lints!(self, check_attribute, late_passes, attr);
914 915 916
    }
}

917 918
impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
    fn visit_item(&mut self, it: &ast::Item) {
N
Nick Cameron 已提交
919
        self.with_lint_attrs(&it.attrs, |cx| {
N
Nick Cameron 已提交
920
            run_lints!(cx, check_item, early_passes, it);
921 922
            cx.visit_ids(|v| v.visit_item(it));
            ast_visit::walk_item(cx, it);
L
llogiq 已提交
923
            run_lints!(cx, check_item_post, early_passes, it);
924 925 926 927
        })
    }

    fn visit_foreign_item(&mut self, it: &ast::ForeignItem) {
N
Nick Cameron 已提交
928
        self.with_lint_attrs(&it.attrs, |cx| {
N
Nick Cameron 已提交
929
            run_lints!(cx, check_foreign_item, early_passes, it);
930 931 932 933 934
            ast_visit::walk_foreign_item(cx, it);
        })
    }

    fn visit_pat(&mut self, p: &ast::Pat) {
N
Nick Cameron 已提交
935
        run_lints!(self, check_pat, early_passes, p);
936 937 938 939
        ast_visit::walk_pat(self, p);
    }

    fn visit_expr(&mut self, e: &ast::Expr) {
940 941 942 943
        self.with_lint_attrs(e.attrs.as_attr_slice(), |cx| {
            run_lints!(cx, check_expr, early_passes, e);
            ast_visit::walk_expr(cx, e);
        })
944 945 946
    }

    fn visit_stmt(&mut self, s: &ast::Stmt) {
N
Nick Cameron 已提交
947
        run_lints!(self, check_stmt, early_passes, s);
948 949 950 951 952
        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) {
N
Nick Cameron 已提交
953
        run_lints!(self, check_fn, early_passes, fk, decl, body, span, id);
954 955 956
        ast_visit::walk_fn(self, fk, decl, body, span);
    }

957 958
    fn visit_variant_data(&mut self,
                        s: &ast::VariantData,
959 960
                        ident: ast::Ident,
                        g: &ast::Generics,
961 962
                        item_id: ast::NodeId,
                        _: Span) {
963
        run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id);
964
        ast_visit::walk_struct_def(self, s);
965
        run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id);
966 967 968
    }

    fn visit_struct_field(&mut self, s: &ast::StructField) {
N
Nick Cameron 已提交
969
        self.with_lint_attrs(&s.node.attrs, |cx| {
N
Nick Cameron 已提交
970
            run_lints!(cx, check_struct_field, early_passes, s);
971 972 973 974
            ast_visit::walk_struct_field(cx, s);
        })
    }

975
    fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics, item_id: ast::NodeId) {
N
Nick Cameron 已提交
976
        self.with_lint_attrs(&v.node.attrs, |cx| {
N
Nick Cameron 已提交
977
            run_lints!(cx, check_variant, early_passes, v, g);
978
            ast_visit::walk_variant(cx, v, g, item_id);
N
Nick Cameron 已提交
979
            run_lints!(cx, check_variant_post, early_passes, v, g);
980 981 982 983
        })
    }

    fn visit_ty(&mut self, t: &ast::Ty) {
N
Nick Cameron 已提交
984
        run_lints!(self, check_ty, early_passes, t);
985 986 987 988
        ast_visit::walk_ty(self, t);
    }

    fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
N
Nick Cameron 已提交
989
        run_lints!(self, check_ident, early_passes, sp, id);
990 991 992
    }

    fn visit_mod(&mut self, m: &ast::Mod, s: Span, n: ast::NodeId) {
N
Nick Cameron 已提交
993
        run_lints!(self, check_mod, early_passes, m, s, n);
994 995 996 997
        ast_visit::walk_mod(self, m);
    }

    fn visit_local(&mut self, l: &ast::Local) {
998 999 1000 1001
        self.with_lint_attrs(l.attrs.as_attr_slice(), |cx| {
            run_lints!(cx, check_local, early_passes, l);
            ast_visit::walk_local(cx, l);
        })
1002 1003 1004
    }

    fn visit_block(&mut self, b: &ast::Block) {
N
Nick Cameron 已提交
1005
        run_lints!(self, check_block, early_passes, b);
1006
        ast_visit::walk_block(self, b);
L
llogiq 已提交
1007
        run_lints!(self, check_block_post, early_passes, b);
1008 1009 1010
    }

    fn visit_arm(&mut self, a: &ast::Arm) {
N
Nick Cameron 已提交
1011
        run_lints!(self, check_arm, early_passes, a);
1012 1013 1014 1015
        ast_visit::walk_arm(self, a);
    }

    fn visit_decl(&mut self, d: &ast::Decl) {
N
Nick Cameron 已提交
1016
        run_lints!(self, check_decl, early_passes, d);
1017 1018 1019 1020
        ast_visit::walk_decl(self, d);
    }

    fn visit_expr_post(&mut self, e: &ast::Expr) {
N
Nick Cameron 已提交
1021
        run_lints!(self, check_expr_post, early_passes, e);
1022 1023 1024
    }

    fn visit_generics(&mut self, g: &ast::Generics) {
N
Nick Cameron 已提交
1025
        run_lints!(self, check_generics, early_passes, g);
1026 1027 1028 1029
        ast_visit::walk_generics(self, g);
    }

    fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
N
Nick Cameron 已提交
1030
        self.with_lint_attrs(&trait_item.attrs, |cx| {
N
Nick Cameron 已提交
1031
            run_lints!(cx, check_trait_item, early_passes, trait_item);
1032 1033 1034 1035 1036 1037
            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) {
N
Nick Cameron 已提交
1038
        self.with_lint_attrs(&impl_item.attrs, |cx| {
N
Nick Cameron 已提交
1039
            run_lints!(cx, check_impl_item, early_passes, impl_item);
1040 1041 1042 1043 1044
            cx.visit_ids(|v| v.visit_impl_item(impl_item));
            ast_visit::walk_impl_item(cx, impl_item);
        });
    }

1045 1046
    fn visit_lifetime(&mut self, lt: &ast::Lifetime) {
        run_lints!(self, check_lifetime, early_passes, lt);
1047 1048 1049
    }

    fn visit_lifetime_def(&mut self, lt: &ast::LifetimeDef) {
N
Nick Cameron 已提交
1050
        run_lints!(self, check_lifetime_def, early_passes, lt);
1051 1052 1053
    }

    fn visit_explicit_self(&mut self, es: &ast::ExplicitSelf) {
N
Nick Cameron 已提交
1054
        run_lints!(self, check_explicit_self, early_passes, es);
1055 1056 1057 1058
        ast_visit::walk_explicit_self(self, es);
    }

    fn visit_path(&mut self, p: &ast::Path, id: ast::NodeId) {
N
Nick Cameron 已提交
1059
        run_lints!(self, check_path, early_passes, p, id);
1060 1061 1062
        ast_visit::walk_path(self, p);
    }

V
Vadim Petrochenkov 已提交
1063 1064 1065
    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);
1066 1067
    }

1068
    fn visit_attribute(&mut self, attr: &ast::Attribute) {
N
Nick Cameron 已提交
1069
        run_lints!(self, check_attribute, early_passes, attr);
1070 1071 1072
    }
}

1073
// Output any lints that were previously added to the session.
1074 1075 1076 1077 1078
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) => {
1079
                debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
1080 1081 1082 1083 1084 1085 1086 1087
                for (lint_id, span, msg) in lints {
                    self.span_lint(lint_id.lint, span, &msg[..])
                }
            }
        }
    }
}
impl<'a> IdVisitingOperation for EarlyContext<'a> {
A
Ariel Ben-Yehuda 已提交
1088
    fn visit_id(&mut self, id: ast::NodeId) {
1089
        match self.sess.lints.borrow_mut().remove(&id) {
1090 1091
            None => {}
            Some(lints) => {
1092
                for (lint_id, span, msg) in lints {
1093
                    self.span_lint(lint_id.lint, span, &msg[..])
1094 1095 1096 1097 1098 1099
                }
            }
        }
    }
}

1100
// This lint pass is defined here because it touches parts of the `LateContext`
1101 1102 1103 1104
// 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`.

1105
pub struct GatherNodeLevels;
1106 1107 1108 1109 1110

impl LintPass for GatherNodeLevels {
    fn get_lints(&self) -> LintArray {
        lint_array!()
    }
N
Nick Cameron 已提交
1111
}
1112

N
Nick Cameron 已提交
1113
impl LateLintPass for GatherNodeLevels {
1114
    fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
1115
        match it.node {
M
Manish Goregaokar 已提交
1116
            hir::ItemEnum(..) => {
A
Aaron Turon 已提交
1117
                let lint_id = LintId::of(builtin::VARIANT_SIZE_DIFFERENCES);
1118 1119 1120
                let lvlsrc = cx.lints.get_level_source(lint_id);
                match lvlsrc {
                    (lvl, _) if lvl != Allow => {
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
                        cx.node_levels.borrow_mut()
                            .insert((it.id, lint_id), lvlsrc);
                    },
                    _ => { }
                }
            },
            _ => { }
        }
    }
}

1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238
enum CheckLintNameResult<'a> {
    Ok,
    // Lint doesn't exist
    NoLint,
    // The lint is either renamed or removed and a warning was
    // generated in the DiagnosticBuilder
    Mentioned(DiagnosticBuilder<'a>)
}

/// Checks the name of a lint for its existence, and whether it was
/// renamed or removed. Generates a DiagnosticBuilder containing a
/// warning for renamed and removed lints. This is over both lint
/// names from attributes and those passed on the command line. Since
/// it emits non-fatal warnings and there are *two* lint passes that
/// inspect attributes, this is only run from the late pass to avoid
/// printing duplicate warnings.
fn check_lint_name<'a>(sess: &'a Session,
                       lint_cx: &LintStore,
                       lint_name: &str,
                       span: Option<Span>) -> CheckLintNameResult<'a> {
    match lint_cx.by_name.get(lint_name) {
        Some(&Renamed(ref new_name, _)) => {
            let warning = format!("lint {} has been renamed to {}",
                                  lint_name, new_name);
            let db = match span {
                Some(span) => sess.struct_span_warn(span, &warning[..]),
                None => sess.struct_warn(&warning[..]),
            };
            CheckLintNameResult::Mentioned(db)
        },
        Some(&Removed(ref reason)) => {
            let warning = format!("lint {} has been removed: {}", lint_name, reason);
            let db = match span {
                Some(span) => sess.struct_span_warn(span, &warning[..]),
                None => sess.struct_warn(&warning[..])
            };
            CheckLintNameResult::Mentioned(db)
        },
        None => {
            match lint_cx.lint_groups.get(lint_name) {
                None => {
                    CheckLintNameResult::NoLint
                }
                Some(_) => {
                    /* lint group exists */
                    CheckLintNameResult::Ok
                }
            }
        }
        Some(_) => {
            /* lint exists */
            CheckLintNameResult::Ok
        }
    }
}

// Checks the validity of lint names derived from attributes
fn check_lint_name_attribute(cx: &LateContext, attr: &ast::Attribute) {
    for result in gather_attr(attr) {
        match result {
            Err(_) => {
                // Malformed lint attr. Reported by with_lint_attrs
                continue;
            }
            Ok((lint_name, _, span)) => {
                match check_lint_name(&cx.tcx.sess, &cx.lints, &lint_name[..], Some(span)) {
                    CheckLintNameResult::Ok => (),
                    CheckLintNameResult::Mentioned(mut db) => {
                        db.emit();
                    }
                    CheckLintNameResult::NoLint => {
                        cx.span_lint(builtin::UNKNOWN_LINTS, span,
                                     &format!("unknown lint: `{}`",
                                              lint_name));
                    }
                }
            }
        }
    }
}

// Checks the validity of lint names derived from the command line
fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore,
                           lint_name: &str, level: Level) {
    let db = match check_lint_name(sess, lint_cx, lint_name, None) {
        CheckLintNameResult::Ok => None,
        CheckLintNameResult::Mentioned(db) => Some(db),
        CheckLintNameResult::NoLint => {
            Some(sess.struct_err(&format!("unknown lint: `{}`", lint_name)))
        }
    };

    if let Some(mut db) = db {
        let msg = format!("requested on the command line with `{} {}`",
                          match level {
                              Level::Allow => "-A",
                              Level::Warn => "-W",
                              Level::Deny => "-D",
                              Level::Forbid => "-F",
                          },
                          lint_name);
        db.note(&msg);
        db.emit();
    }
}


1239 1240 1241
/// Perform lint checking on a crate.
///
/// Consumes the `lint_store` field of the `Session`.
1242
pub fn check_crate(tcx: &ty::ctxt, access_levels: &AccessLevels) {
1243 1244
    let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck);

1245
    let krate = tcx.map.krate();
1246
    let mut cx = LateContext::new(tcx, krate, access_levels);
1247 1248

    // Visit the whole crate.
1249
    cx.with_lint_attrs(&krate.attrs, |cx| {
1250 1251
        cx.visit_id(ast::CRATE_NODE_ID);
        cx.visit_ids(|v| {
1252
            hir_visit::walk_crate(v, krate);
1253 1254 1255 1256
        });

        // since the root module isn't visited as an item (because it isn't an
        // item), warn for it here.
N
Nick Cameron 已提交
1257
        run_lints!(cx, check_crate, late_passes, krate);
1258

1259
        hir_visit::walk_crate(cx, krate);
L
llogiq 已提交
1260 1261

        run_lints!(cx, check_crate_post, late_passes, krate);
1262 1263 1264 1265
    });

    // If we missed any lints added to the session, then there's a bug somewhere
    // in the iteration code.
1266
    for (id, v) in tcx.sess.lints.borrow().iter() {
1267
        for &(lint, span, ref msg) in v {
1268
            tcx.sess.span_bug(span,
1269 1270
                              &format!("unprocessed lint {} at {}: {}",
                                       lint.as_str(), tcx.map.node_to_string(*id), *msg))
1271 1272 1273
        }
    }

1274
    *tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
1275
}
1276 1277 1278 1279 1280

pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
    let mut cx = EarlyContext::new(sess, krate);

    // Visit the whole crate.
N
Nick Cameron 已提交
1281
    cx.with_lint_attrs(&krate.attrs, |cx| {
1282 1283 1284 1285 1286 1287 1288 1289
        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.
N
Nick Cameron 已提交
1290
        run_lints!(cx, check_crate, early_passes, krate);
1291 1292

        ast_visit::walk_crate(cx, krate);
L
llogiq 已提交
1293 1294

        run_lints!(cx, check_crate_post, early_passes, krate);
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
    });

    // 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))
        }
    }
}