context.rs 45.2 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);
849 850
    }

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

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

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

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

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

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

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

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

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

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

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

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

915 916
impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
    fn visit_item(&mut self, it: &ast::Item) {
N
Nick Cameron 已提交
917
        self.with_lint_attrs(&it.attrs, |cx| {
N
Nick Cameron 已提交
918
            run_lints!(cx, check_item, early_passes, it);
919 920 921 922 923 924
            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 已提交
925
        self.with_lint_attrs(&it.attrs, |cx| {
N
Nick Cameron 已提交
926
            run_lints!(cx, check_foreign_item, early_passes, it);
927 928 929 930 931
            ast_visit::walk_foreign_item(cx, it);
        })
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1101
pub struct GatherNodeLevels;
1102 1103 1104 1105 1106

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

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

1128 1129 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
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();
    }
}


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

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

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

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

1255
        hir_visit::walk_crate(cx, krate);
1256 1257 1258 1259
    });

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

1268
    *tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
1269
}
1270 1271 1272 1273 1274

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

    // Visit the whole crate.
N
Nick Cameron 已提交
1275
    cx.with_lint_attrs(&krate.attrs, |cx| {
1276 1277 1278 1279 1280 1281 1282 1283
        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 已提交
1284
        run_lints!(cx, check_crate, early_passes, krate);
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301

        ast_visit::walk_crate(cx, krate);
    });

    // Put the lint store back in the session.
    mem::replace(&mut *sess.lint_store.borrow_mut(), cx.lints);

    // If we missed any lints added to the session, then there's a bug somewhere
    // in the iteration code.
    for (_, v) in sess.lints.borrow().iter() {
        for &(lint, span, ref msg) in v {
            sess.span_bug(span,
                          &format!("unprocessed lint {}: {}",
                                   lint.as_str(), *msg))
        }
    }
}