context.rs 45.4 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 377 378 379 380
    attr::mark_used(attr);

    let meta = &attr.node.value;
    let metas = match meta.node {
        ast::MetaList(_, ref metas) => metas,
        _ => {
            out.push(Err(meta.span));
            return out;
381
        }
382 383 384 385 386 387 388
    };

    for meta in metas {
        out.push(match meta.node {
            ast::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)),
            _ => 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);
761 762 763
        })
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1103
pub struct GatherNodeLevels;
1104 1105 1106 1107 1108

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

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

1130 1131 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
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();
    }
}


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

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

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

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

1257
        hir_visit::walk_crate(cx, krate);
L
llogiq 已提交
1258 1259

        run_lints!(cx, check_crate_post, late_passes, krate);
1260 1261 1262 1263
    });

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

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

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

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

        ast_visit::walk_crate(cx, krate);
L
llogiq 已提交
1291 1292

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

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