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

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

28
use 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
            run_lints!(cx, check_foreign_item_post, late_passes, it);
770 771 772
        })
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

893 894
    fn visit_lifetime(&mut self, lt: &hir::Lifetime) {
        run_lints!(self, check_lifetime, late_passes, lt);
895 896
    }

M
Manish Goregaokar 已提交
897
    fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) {
N
Nick Cameron 已提交
898
        run_lints!(self, check_lifetime_def, late_passes, lt);
899 900
    }

M
Manish Goregaokar 已提交
901
    fn visit_explicit_self(&mut self, es: &hir::ExplicitSelf) {
N
Nick Cameron 已提交
902
        run_lints!(self, check_explicit_self, late_passes, es);
903
        hir_visit::walk_explicit_self(self, es);
904 905
    }

M
Manish Goregaokar 已提交
906
    fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) {
N
Nick Cameron 已提交
907
        run_lints!(self, check_path, late_passes, p, id);
908
        hir_visit::walk_path(self, p);
909 910
    }

V
Vadim Petrochenkov 已提交
911 912 913 914 915
    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);
    }

916
    fn visit_attribute(&mut self, attr: &ast::Attribute) {
917
        check_lint_name_attribute(self, attr);
N
Nick Cameron 已提交
918
        run_lints!(self, check_attribute, late_passes, attr);
919 920 921
    }
}

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

    fn visit_foreign_item(&mut self, it: &ast::ForeignItem) {
N
Nick Cameron 已提交
933
        self.with_lint_attrs(&it.attrs, |cx| {
N
Nick Cameron 已提交
934
            run_lints!(cx, check_foreign_item, early_passes, it);
935
            ast_visit::walk_foreign_item(cx, it);
936
            run_lints!(cx, check_foreign_item_post, early_passes, it);
937 938 939 940
        })
    }

    fn visit_pat(&mut self, p: &ast::Pat) {
N
Nick Cameron 已提交
941
        run_lints!(self, check_pat, early_passes, p);
942 943 944 945
        ast_visit::walk_pat(self, p);
    }

    fn visit_expr(&mut self, e: &ast::Expr) {
946 947 948 949
        self.with_lint_attrs(e.attrs.as_attr_slice(), |cx| {
            run_lints!(cx, check_expr, early_passes, e);
            ast_visit::walk_expr(cx, e);
        })
950 951 952
    }

    fn visit_stmt(&mut self, s: &ast::Stmt) {
N
Nick Cameron 已提交
953
        run_lints!(self, check_stmt, early_passes, s);
954 955 956 957 958
        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 已提交
959
        run_lints!(self, check_fn, early_passes, fk, decl, body, span, id);
960
        ast_visit::walk_fn(self, fk, decl, body, span);
961
        run_lints!(self, check_fn_post, early_passes, fk, decl, body, span, id);
962 963
    }

964 965
    fn visit_variant_data(&mut self,
                        s: &ast::VariantData,
966 967
                        ident: ast::Ident,
                        g: &ast::Generics,
968 969
                        item_id: ast::NodeId,
                        _: Span) {
970
        run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id);
971
        ast_visit::walk_struct_def(self, s);
972
        run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id);
973 974 975
    }

    fn visit_struct_field(&mut self, s: &ast::StructField) {
N
Nick Cameron 已提交
976
        self.with_lint_attrs(&s.node.attrs, |cx| {
N
Nick Cameron 已提交
977
            run_lints!(cx, check_struct_field, early_passes, s);
978 979 980 981
            ast_visit::walk_struct_field(cx, s);
        })
    }

982
    fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics, item_id: ast::NodeId) {
N
Nick Cameron 已提交
983
        self.with_lint_attrs(&v.node.attrs, |cx| {
N
Nick Cameron 已提交
984
            run_lints!(cx, check_variant, early_passes, v, g);
985
            ast_visit::walk_variant(cx, v, g, item_id);
N
Nick Cameron 已提交
986
            run_lints!(cx, check_variant_post, early_passes, v, g);
987 988 989 990
        })
    }

    fn visit_ty(&mut self, t: &ast::Ty) {
N
Nick Cameron 已提交
991
        run_lints!(self, check_ty, early_passes, t);
992 993 994 995
        ast_visit::walk_ty(self, t);
    }

    fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
N
Nick Cameron 已提交
996
        run_lints!(self, check_ident, early_passes, sp, id);
997 998 999
    }

    fn visit_mod(&mut self, m: &ast::Mod, s: Span, n: ast::NodeId) {
N
Nick Cameron 已提交
1000
        run_lints!(self, check_mod, early_passes, m, s, n);
1001
        ast_visit::walk_mod(self, m);
1002
        run_lints!(self, check_mod_post, early_passes, m, s, n);
1003 1004 1005
    }

    fn visit_local(&mut self, l: &ast::Local) {
1006 1007 1008 1009
        self.with_lint_attrs(l.attrs.as_attr_slice(), |cx| {
            run_lints!(cx, check_local, early_passes, l);
            ast_visit::walk_local(cx, l);
        })
1010 1011 1012
    }

    fn visit_block(&mut self, b: &ast::Block) {
N
Nick Cameron 已提交
1013
        run_lints!(self, check_block, early_passes, b);
1014
        ast_visit::walk_block(self, b);
L
llogiq 已提交
1015
        run_lints!(self, check_block_post, early_passes, b);
1016 1017 1018
    }

    fn visit_arm(&mut self, a: &ast::Arm) {
N
Nick Cameron 已提交
1019
        run_lints!(self, check_arm, early_passes, a);
1020 1021 1022 1023
        ast_visit::walk_arm(self, a);
    }

    fn visit_decl(&mut self, d: &ast::Decl) {
N
Nick Cameron 已提交
1024
        run_lints!(self, check_decl, early_passes, d);
1025 1026 1027 1028
        ast_visit::walk_decl(self, d);
    }

    fn visit_expr_post(&mut self, e: &ast::Expr) {
N
Nick Cameron 已提交
1029
        run_lints!(self, check_expr_post, early_passes, e);
1030 1031 1032
    }

    fn visit_generics(&mut self, g: &ast::Generics) {
N
Nick Cameron 已提交
1033
        run_lints!(self, check_generics, early_passes, g);
1034 1035 1036 1037
        ast_visit::walk_generics(self, g);
    }

    fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
N
Nick Cameron 已提交
1038
        self.with_lint_attrs(&trait_item.attrs, |cx| {
N
Nick Cameron 已提交
1039
            run_lints!(cx, check_trait_item, early_passes, trait_item);
1040 1041
            cx.visit_ids(|v| v.visit_trait_item(trait_item));
            ast_visit::walk_trait_item(cx, trait_item);
1042
            run_lints!(cx, check_trait_item_post, early_passes, trait_item);
1043 1044 1045 1046
        });
    }

    fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
N
Nick Cameron 已提交
1047
        self.with_lint_attrs(&impl_item.attrs, |cx| {
N
Nick Cameron 已提交
1048
            run_lints!(cx, check_impl_item, early_passes, impl_item);
1049 1050
            cx.visit_ids(|v| v.visit_impl_item(impl_item));
            ast_visit::walk_impl_item(cx, impl_item);
1051
            run_lints!(cx, check_impl_item_post, early_passes, impl_item);
1052 1053 1054
        });
    }

1055 1056
    fn visit_lifetime(&mut self, lt: &ast::Lifetime) {
        run_lints!(self, check_lifetime, early_passes, lt);
1057 1058 1059
    }

    fn visit_lifetime_def(&mut self, lt: &ast::LifetimeDef) {
N
Nick Cameron 已提交
1060
        run_lints!(self, check_lifetime_def, early_passes, lt);
1061 1062 1063
    }

    fn visit_explicit_self(&mut self, es: &ast::ExplicitSelf) {
N
Nick Cameron 已提交
1064
        run_lints!(self, check_explicit_self, early_passes, es);
1065 1066 1067 1068
        ast_visit::walk_explicit_self(self, es);
    }

    fn visit_path(&mut self, p: &ast::Path, id: ast::NodeId) {
N
Nick Cameron 已提交
1069
        run_lints!(self, check_path, early_passes, p, id);
1070 1071 1072
        ast_visit::walk_path(self, p);
    }

V
Vadim Petrochenkov 已提交
1073 1074 1075
    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);
1076 1077
    }

1078
    fn visit_attribute(&mut self, attr: &ast::Attribute) {
N
Nick Cameron 已提交
1079
        run_lints!(self, check_attribute, early_passes, attr);
1080 1081 1082
    }
}

1083
// Output any lints that were previously added to the session.
1084 1085 1086 1087 1088
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) => {
1089
                debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
1090 1091 1092 1093 1094 1095 1096 1097
                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 已提交
1098
    fn visit_id(&mut self, id: ast::NodeId) {
1099
        match self.sess.lints.borrow_mut().remove(&id) {
1100 1101
            None => {}
            Some(lints) => {
1102
                for (lint_id, span, msg) in lints {
1103
                    self.span_lint(lint_id.lint, span, &msg[..])
1104 1105 1106 1107 1108 1109
                }
            }
        }
    }
}

1110
// This lint pass is defined here because it touches parts of the `LateContext`
1111 1112 1113 1114
// 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`.

1115
pub struct GatherNodeLevels;
1116 1117 1118 1119 1120

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

N
Nick Cameron 已提交
1123
impl LateLintPass for GatherNodeLevels {
1124
    fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
1125
        match it.node {
M
Manish Goregaokar 已提交
1126
            hir::ItemEnum(..) => {
A
Aaron Turon 已提交
1127
                let lint_id = LintId::of(builtin::VARIANT_SIZE_DIFFERENCES);
1128 1129 1130
                let lvlsrc = cx.lints.get_level_source(lint_id);
                match lvlsrc {
                    (lvl, _) if lvl != Allow => {
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
                        cx.node_levels.borrow_mut()
                            .insert((it.id, lint_id), lvlsrc);
                    },
                    _ => { }
                }
            },
            _ => { }
        }
    }
}

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 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
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();
    }
}


1249 1250 1251
/// Perform lint checking on a crate.
///
/// Consumes the `lint_store` field of the `Session`.
1252
pub fn check_crate(tcx: &ty::ctxt, access_levels: &AccessLevels) {
1253 1254
    let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck);

1255
    let krate = tcx.map.krate();
1256
    let mut cx = LateContext::new(tcx, krate, access_levels);
1257 1258

    // Visit the whole crate.
1259
    cx.with_lint_attrs(&krate.attrs, |cx| {
1260 1261
        cx.visit_id(ast::CRATE_NODE_ID);
        cx.visit_ids(|v| {
1262
            hir_visit::walk_crate(v, krate);
1263 1264 1265 1266
        });

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

1269
        hir_visit::walk_crate(cx, krate);
L
llogiq 已提交
1270 1271

        run_lints!(cx, check_crate_post, late_passes, krate);
1272 1273 1274 1275
    });

    // If we missed any lints added to the session, then there's a bug somewhere
    // in the iteration code.
1276
    for (id, v) in tcx.sess.lints.borrow().iter() {
1277
        for &(lint, span, ref msg) in v {
1278
            tcx.sess.span_bug(span,
1279 1280
                              &format!("unprocessed lint {} at {}: {}",
                                       lint.as_str(), tcx.map.node_to_string(*id), *msg))
1281 1282 1283
        }
    }

1284
    *tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
1285
}
1286 1287 1288 1289 1290

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

    // Visit the whole crate.
N
Nick Cameron 已提交
1291
    cx.with_lint_attrs(&krate.attrs, |cx| {
1292 1293 1294 1295 1296 1297 1298 1299
        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 已提交
1300
        run_lints!(cx, check_crate, early_passes, krate);
1301 1302

        ast_visit::walk_crate(cx, krate);
L
llogiq 已提交
1303 1304

        run_lints!(cx, check_crate_post, early_passes, krate);
1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
    });

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