]> git.lizzy.rs Git - rust.git/blob - src/librustc/lint/context.rs
4a082944010b2838fb73d12cc26d84f9d7bea0eb
[rust.git] / src / librustc / lint / context.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Implementation of lint checking.
12 //!
13 //! The lint checking is mostly consolidated into one pass which runs just
14 //! before translation to LLVM bytecode. Throughout compilation, lint warnings
15 //! can be added via the `add_lint` method on the Session structure. This
16 //! requires a span and an id of the node that the lint is being added to. The
17 //! lint isn't actually emitted at that time because it is unknown what the
18 //! actual lint level at that location is.
19 //!
20 //! To actually emit lint warnings/errors, a separate pass is used just before
21 //! translation. A context keeps track of the current state of all lint levels.
22 //! Upon entering a node of the ast which can modify the lint settings, the
23 //! previous lint state is pushed onto a stack and the ast is then recursed
24 //! upon.  As the ast is traversed, this keeps track of the current lint level
25 //! for all lint attributes.
26 use self::TargetLint::*;
27
28 use dep_graph::DepNode;
29 use middle::privacy::AccessLevels;
30 use ty::TyCtxt;
31 use session::{config, early_error, Session};
32 use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource};
33 use lint::{EarlyLintPassObject, LateLintPassObject};
34 use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
35 use lint::builtin;
36 use util::nodemap::FxHashMap;
37
38 use std::cmp;
39 use std::default::Default as StdDefault;
40 use std::mem;
41 use std::fmt;
42 use syntax::attr;
43 use syntax::ast;
44 use syntax_pos::{MultiSpan, Span};
45 use errors::{self, Diagnostic, DiagnosticBuilder};
46 use hir;
47 use hir::intravisit as hir_visit;
48 use syntax::visit as ast_visit;
49
50 /// Information about the registered lints.
51 ///
52 /// This is basically the subset of `Context` that we can
53 /// build early in the compile pipeline.
54 pub struct LintStore {
55     /// Registered lints. The bool is true if the lint was
56     /// added by a plugin.
57     lints: Vec<(&'static Lint, bool)>,
58
59     /// Trait objects for each lint pass.
60     /// This is only `None` while iterating over the objects. See the definition
61     /// of run_lints.
62     early_passes: Option<Vec<EarlyLintPassObject>>,
63     late_passes: Option<Vec<LateLintPassObject>>,
64
65     /// Lints indexed by name.
66     by_name: FxHashMap<String, TargetLint>,
67
68     /// Current levels of each lint, and where they were set.
69     levels: FxHashMap<LintId, LevelSource>,
70
71     /// Map of registered lint groups to what lints they expand to. The bool
72     /// is true if the lint group was added by a plugin.
73     lint_groups: FxHashMap<&'static str, (Vec<LintId>, bool)>,
74
75     /// Extra info for future incompatibility lints, descibing the
76     /// issue or RFC that caused the incompatibility.
77     future_incompatible: FxHashMap<LintId, FutureIncompatibleInfo>,
78
79     /// Maximum level a lint can be
80     lint_cap: Option<Level>,
81 }
82
83 /// When you call `add_lint` on the session, you wind up storing one
84 /// of these, which records a "potential lint" at a particular point.
85 #[derive(PartialEq)]
86 pub struct EarlyLint {
87     /// what lint is this? (e.g., `dead_code`)
88     pub id: LintId,
89
90     /// the main message
91     pub diagnostic: Diagnostic,
92 }
93
94 impl fmt::Debug for EarlyLint {
95     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96         f.debug_struct("EarlyLint")
97             .field("id", &self.id)
98             .field("span", &self.diagnostic.span)
99             .field("diagnostic", &self.diagnostic)
100             .finish()
101     }
102 }
103
104 pub trait IntoEarlyLint {
105     fn into_early_lint(self, id: LintId) -> EarlyLint;
106 }
107
108 impl<'a, S: Into<MultiSpan>> IntoEarlyLint for (S, &'a str) {
109     fn into_early_lint(self, id: LintId) -> EarlyLint {
110         let (span, msg) = self;
111         let mut diagnostic = Diagnostic::new(errors::Level::Warning, msg);
112         diagnostic.set_span(span);
113         EarlyLint { id: id, diagnostic: diagnostic }
114     }
115 }
116
117 impl IntoEarlyLint for Diagnostic {
118     fn into_early_lint(self, id: LintId) -> EarlyLint {
119         EarlyLint { id: id, diagnostic: self }
120     }
121 }
122
123 /// Extra information for a future incompatibility lint. See the call
124 /// to `register_future_incompatible` in `librustc_lint/lib.rs` for
125 /// guidelines.
126 pub struct FutureIncompatibleInfo {
127     pub id: LintId,
128     pub reference: &'static str // e.g., a URL for an issue/PR/RFC or error code
129 }
130
131 /// The targed of the `by_name` map, which accounts for renaming/deprecation.
132 enum TargetLint {
133     /// A direct lint target
134     Id(LintId),
135
136     /// Temporary renaming, used for easing migration pain; see #16545
137     Renamed(String, LintId),
138
139     /// Lint with this name existed previously, but has been removed/deprecated.
140     /// The string argument is the reason for removal.
141     Removed(String),
142 }
143
144 enum FindLintError {
145     NotFound,
146     Removed
147 }
148
149 impl LintStore {
150     fn get_level_source(&self, lint: LintId) -> LevelSource {
151         match self.levels.get(&lint) {
152             Some(&s) => s,
153             None => (Allow, Default),
154         }
155     }
156
157     fn set_level(&mut self, lint: LintId, mut lvlsrc: LevelSource) {
158         if let Some(cap) = self.lint_cap {
159             lvlsrc.0 = cmp::min(lvlsrc.0, cap);
160         }
161         if lvlsrc.0 == Allow {
162             self.levels.remove(&lint);
163         } else {
164             self.levels.insert(lint, lvlsrc);
165         }
166     }
167
168     pub fn new() -> LintStore {
169         LintStore {
170             lints: vec![],
171             early_passes: Some(vec![]),
172             late_passes: Some(vec![]),
173             by_name: FxHashMap(),
174             levels: FxHashMap(),
175             future_incompatible: FxHashMap(),
176             lint_groups: FxHashMap(),
177             lint_cap: None,
178         }
179     }
180
181     pub fn get_lints<'t>(&'t self) -> &'t [(&'static Lint, bool)] {
182         &self.lints
183     }
184
185     pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
186         self.lint_groups.iter().map(|(k, v)| (*k,
187                                               v.0.clone(),
188                                               v.1)).collect()
189     }
190
191     pub fn register_early_pass(&mut self,
192                                sess: Option<&Session>,
193                                from_plugin: bool,
194                                pass: EarlyLintPassObject) {
195         self.push_pass(sess, from_plugin, &pass);
196         self.early_passes.as_mut().unwrap().push(pass);
197     }
198
199     pub fn register_late_pass(&mut self,
200                               sess: Option<&Session>,
201                               from_plugin: bool,
202                               pass: LateLintPassObject) {
203         self.push_pass(sess, from_plugin, &pass);
204         self.late_passes.as_mut().unwrap().push(pass);
205     }
206
207     // Helper method for register_early/late_pass
208     fn push_pass<P: LintPass + ?Sized + 'static>(&mut self,
209                                         sess: Option<&Session>,
210                                         from_plugin: bool,
211                                         pass: &Box<P>) {
212         for &lint in pass.get_lints() {
213             self.lints.push((*lint, from_plugin));
214
215             let id = LintId::of(*lint);
216             if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
217                 let msg = format!("duplicate specification of lint {}", lint.name_lower());
218                 match (sess, from_plugin) {
219                     // We load builtin lints first, so a duplicate is a compiler bug.
220                     // Use early_error when handling -W help with no crate.
221                     (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
222                     (Some(_), false) => bug!("{}", msg),
223
224                     // A duplicate name from a plugin is a user error.
225                     (Some(sess), true)  => sess.err(&msg[..]),
226                 }
227             }
228
229             if lint.default_level != Allow {
230                 self.levels.insert(id, (lint.default_level, Default));
231             }
232         }
233     }
234
235     pub fn register_future_incompatible(&mut self,
236                                         sess: Option<&Session>,
237                                         lints: Vec<FutureIncompatibleInfo>) {
238         let ids = lints.iter().map(|f| f.id).collect();
239         self.register_group(sess, false, "future_incompatible", ids);
240         for info in lints {
241             self.future_incompatible.insert(info.id, info);
242         }
243     }
244
245     pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
246         self.future_incompatible.get(&id)
247     }
248
249     pub fn register_group(&mut self, sess: Option<&Session>,
250                           from_plugin: bool, name: &'static str,
251                           to: Vec<LintId>) {
252         let new = self.lint_groups.insert(name, (to, from_plugin)).is_none();
253
254         if !new {
255             let msg = format!("duplicate specification of lint group {}", name);
256             match (sess, from_plugin) {
257                 // We load builtin lints first, so a duplicate is a compiler bug.
258                 // Use early_error when handling -W help with no crate.
259                 (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
260                 (Some(_), false) => bug!("{}", msg),
261
262                 // A duplicate name from a plugin is a user error.
263                 (Some(sess), true)  => sess.err(&msg[..]),
264             }
265         }
266     }
267
268     pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
269         let target = match self.by_name.get(new_name) {
270             Some(&Id(lint_id)) => lint_id.clone(),
271             _ => bug!("invalid lint renaming of {} to {}", old_name, new_name)
272         };
273         self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
274     }
275
276     pub fn register_removed(&mut self, name: &str, reason: &str) {
277         self.by_name.insert(name.into(), Removed(reason.into()));
278     }
279
280     #[allow(unused_variables)]
281     fn find_lint(&self, lint_name: &str, sess: &Session, span: Option<Span>)
282                  -> Result<LintId, FindLintError>
283     {
284         match self.by_name.get(lint_name) {
285             Some(&Id(lint_id)) => Ok(lint_id),
286             Some(&Renamed(_, lint_id)) => {
287                 Ok(lint_id)
288             },
289             Some(&Removed(ref reason)) => {
290                 Err(FindLintError::Removed)
291             },
292             None => Err(FindLintError::NotFound)
293         }
294     }
295
296     pub fn process_command_line(&mut self, sess: &Session) {
297         for &(ref lint_name, level) in &sess.opts.lint_opts {
298             check_lint_name_cmdline(sess, self,
299                                     &lint_name[..], level);
300
301             match self.find_lint(&lint_name[..], sess, None) {
302                 Ok(lint_id) => self.set_level(lint_id, (level, CommandLine)),
303                 Err(FindLintError::Removed) => { }
304                 Err(_) => {
305                     match self.lint_groups.iter().map(|(&x, pair)| (x, pair.0.clone()))
306                                                  .collect::<FxHashMap<&'static str,
307                                                                       Vec<LintId>>>()
308                                                  .get(&lint_name[..]) {
309                         Some(v) => {
310                             v.iter()
311                              .map(|lint_id: &LintId|
312                                      self.set_level(*lint_id, (level, CommandLine)))
313                              .collect::<Vec<()>>();
314                         }
315                         None => {
316                             // The lint or lint group doesn't exist.
317                             // This is an error, but it was handled
318                             // by check_lint_name_cmdline.
319                         }
320                     }
321                 }
322             }
323         }
324
325         self.lint_cap = sess.opts.lint_cap;
326         if let Some(cap) = self.lint_cap {
327             for level in self.levels.iter_mut().map(|p| &mut (p.1).0) {
328                 *level = cmp::min(*level, cap);
329             }
330         }
331     }
332 }
333
334 /// Context for lint checking after type checking.
335 pub struct LateContext<'a, 'tcx: 'a> {
336     /// Type context we're checking in.
337     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
338
339     /// The crate being checked.
340     pub krate: &'a hir::Crate,
341
342     /// Items accessible from the crate being checked.
343     pub access_levels: &'a AccessLevels,
344
345     /// The store of registered lints.
346     lints: LintStore,
347
348     /// When recursing into an attributed node of the ast which modifies lint
349     /// levels, this stack keeps track of the previous lint levels of whatever
350     /// was modified.
351     level_stack: Vec<(LintId, LevelSource)>,
352 }
353
354 /// Context for lint checking of the AST, after expansion, before lowering to
355 /// HIR.
356 pub struct EarlyContext<'a> {
357     /// Type context we're checking in.
358     pub sess: &'a Session,
359
360     /// The crate being checked.
361     pub krate: &'a ast::Crate,
362
363     /// The store of registered lints.
364     lints: LintStore,
365
366     /// When recursing into an attributed node of the ast which modifies lint
367     /// levels, this stack keeps track of the previous lint levels of whatever
368     /// was modified.
369     level_stack: Vec<(LintId, LevelSource)>,
370 }
371
372 /// Convenience macro for calling a `LintPass` method on every pass in the context.
373 macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({
374     // Move the vector of passes out of `$cx` so that we can
375     // iterate over it mutably while passing `$cx` to the methods.
376     let mut passes = $cx.mut_lints().$ps.take().unwrap();
377     for obj in &mut passes {
378         obj.$f($cx, $($args),*);
379     }
380     $cx.mut_lints().$ps = Some(passes);
381 }) }
382
383 /// Parse the lint attributes into a vector, with `Err`s for malformed lint
384 /// attributes. Writing this as an iterator is an enormous mess.
385 // See also the hir version just below.
386 pub fn gather_attrs(attrs: &[ast::Attribute]) -> Vec<Result<(ast::Name, Level, Span), Span>> {
387     let mut out = vec![];
388     for attr in attrs {
389         let r = gather_attr(attr);
390         out.extend(r.into_iter());
391     }
392     out
393 }
394
395 pub fn gather_attr(attr: &ast::Attribute) -> Vec<Result<(ast::Name, Level, Span), Span>> {
396     let mut out = vec![];
397
398     let level = match Level::from_str(&attr.name().as_str()) {
399         None => return out,
400         Some(lvl) => lvl,
401     };
402
403     attr::mark_used(attr);
404
405     let meta = &attr.value;
406     let metas = if let Some(metas) = meta.meta_item_list() {
407         metas
408     } else {
409         out.push(Err(meta.span));
410         return out;
411     };
412
413     for li in metas {
414         out.push(li.word().map_or(Err(li.span), |word| Ok((word.name(), level, word.span))));
415     }
416
417     out
418 }
419
420 /// Emit a lint as a warning or an error (or not at all)
421 /// according to `level`.
422 ///
423 /// This lives outside of `Context` so it can be used by checks
424 /// in trans that run after the main lint pass is finished. Most
425 /// lints elsewhere in the compiler should call
426 /// `Session::add_lint()` instead.
427 pub fn raw_emit_lint<S: Into<MultiSpan>>(sess: &Session,
428                                          lints: &LintStore,
429                                          lint: &'static Lint,
430                                          lvlsrc: LevelSource,
431                                          span: Option<S>,
432                                          msg: &str) {
433     raw_struct_lint(sess, lints, lint, lvlsrc, span, msg).emit();
434 }
435
436 pub fn raw_struct_lint<'a, S>(sess: &'a Session,
437                               lints: &LintStore,
438                               lint: &'static Lint,
439                               lvlsrc: LevelSource,
440                               span: Option<S>,
441                               msg: &str)
442                               -> DiagnosticBuilder<'a>
443     where S: Into<MultiSpan>
444 {
445     let (mut level, source) = lvlsrc;
446     if level == Allow {
447         return sess.diagnostic().struct_dummy();
448     }
449
450     let name = lint.name_lower();
451     let mut def = None;
452     let msg = match source {
453         Default => {
454             format!("{}, #[{}({})] on by default", msg,
455                     level.as_str(), name)
456         },
457         CommandLine => {
458             format!("{} [-{} {}]", msg,
459                     match level {
460                         Warn => 'W', Deny => 'D', Forbid => 'F',
461                         Allow => bug!()
462                     }, name.replace("_", "-"))
463         },
464         Node(src) => {
465             def = Some(src);
466             msg.to_string()
467         }
468     };
469
470     // For purposes of printing, we can treat forbid as deny.
471     if level == Forbid { level = Deny; }
472
473     let mut err = match (level, span) {
474         (Warn, Some(sp)) => sess.struct_span_warn(sp, &msg[..]),
475         (Warn, None)     => sess.struct_warn(&msg[..]),
476         (Deny, Some(sp)) => sess.struct_span_err(sp, &msg[..]),
477         (Deny, None)     => sess.struct_err(&msg[..]),
478         _ => bug!("impossible level in raw_emit_lint"),
479     };
480
481     // Check for future incompatibility lints and issue a stronger warning.
482     if let Some(future_incompatible) = lints.future_incompatible(LintId::of(lint)) {
483         let explanation = format!("this was previously accepted by the compiler \
484                                    but is being phased out; \
485                                    it will become a hard error in a future release!");
486         let citation = format!("for more information, see {}",
487                                future_incompatible.reference);
488         err.warn(&explanation);
489         err.note(&citation);
490     }
491
492     if let Some(span) = def {
493         sess.diag_span_note_once(&mut err, lint, span, "lint level defined here");
494     }
495
496     err
497 }
498
499 pub trait LintContext: Sized {
500     fn sess(&self) -> &Session;
501     fn lints(&self) -> &LintStore;
502     fn mut_lints(&mut self) -> &mut LintStore;
503     fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)>;
504     fn enter_attrs(&mut self, attrs: &[ast::Attribute]);
505     fn exit_attrs(&mut self, attrs: &[ast::Attribute]);
506
507     /// Get the level of `lint` at the current position of the lint
508     /// traversal.
509     fn current_level(&self, lint: &'static Lint) -> Level {
510         self.lints().levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
511     }
512
513     fn level_src(&self, lint: &'static Lint) -> Option<LevelSource> {
514         self.lints().levels.get(&LintId::of(lint)).map(|ls| match ls {
515             &(Warn, _) => {
516                 let lint_id = LintId::of(builtin::WARNINGS);
517                 let warn_src = self.lints().get_level_source(lint_id);
518                 if warn_src.0 != Warn {
519                     warn_src
520                 } else {
521                     *ls
522                 }
523             }
524             _ => *ls
525         })
526     }
527
528     fn lookup_and_emit<S: Into<MultiSpan>>(&self,
529                                            lint: &'static Lint,
530                                            span: Option<S>,
531                                            msg: &str) {
532         let (level, src) = match self.level_src(lint) {
533             None => return,
534             Some(pair) => pair,
535         };
536
537         raw_emit_lint(&self.sess(), self.lints(), lint, (level, src), span, msg);
538     }
539
540     fn lookup<S: Into<MultiSpan>>(&self,
541                                   lint: &'static Lint,
542                                   span: Option<S>,
543                                   msg: &str)
544                                   -> DiagnosticBuilder {
545         let (level, src) = match self.level_src(lint) {
546             None => return self.sess().diagnostic().struct_dummy(),
547             Some(pair) => pair,
548         };
549
550         raw_struct_lint(&self.sess(), self.lints(), lint, (level, src), span, msg)
551     }
552
553     /// Emit a lint at the appropriate level, for a particular span.
554     fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
555         self.lookup_and_emit(lint, Some(span), msg);
556     }
557
558     fn early_lint(&self, early_lint: EarlyLint) {
559         let span = early_lint.diagnostic.span.primary_span().expect("early lint w/o primary span");
560         let mut err = self.struct_span_lint(early_lint.id.lint,
561                                             span,
562                                             &early_lint.diagnostic.message);
563         err.copy_details_not_message(&early_lint.diagnostic);
564         err.emit();
565     }
566
567     fn struct_span_lint<S: Into<MultiSpan>>(&self,
568                                             lint: &'static Lint,
569                                             span: S,
570                                             msg: &str)
571                                             -> DiagnosticBuilder {
572         self.lookup(lint, Some(span), msg)
573     }
574
575     /// Emit a lint and note at the appropriate level, for a particular span.
576     fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str,
577                       note_span: Span, note: &str) {
578         let mut err = self.lookup(lint, Some(span), msg);
579         if self.current_level(lint) != Level::Allow {
580             if note_span == span {
581                 err.note(note);
582             } else {
583                 err.span_note(note_span, note);
584             }
585         }
586         err.emit();
587     }
588
589     /// Emit a lint and help at the appropriate level, for a particular span.
590     fn span_lint_help(&self, lint: &'static Lint, span: Span,
591                       msg: &str, help: &str) {
592         let mut err = self.lookup(lint, Some(span), msg);
593         self.span_lint(lint, span, msg);
594         if self.current_level(lint) != Level::Allow {
595             err.span_help(span, help);
596         }
597         err.emit();
598     }
599
600     /// Emit a lint at the appropriate level, with no associated span.
601     fn lint(&self, lint: &'static Lint, msg: &str) {
602         self.lookup_and_emit(lint, None as Option<Span>, msg);
603     }
604
605     /// Merge the lints specified by any lint attributes into the
606     /// current lint context, call the provided function, then reset the
607     /// lints in effect to their previous state.
608     fn with_lint_attrs<F>(&mut self,
609                           attrs: &[ast::Attribute],
610                           f: F)
611         where F: FnOnce(&mut Self),
612     {
613         // Parse all of the lint attributes, and then add them all to the
614         // current dictionary of lint information. Along the way, keep a history
615         // of what we changed so we can roll everything back after invoking the
616         // specified closure
617         let mut pushed = 0;
618
619         for result in gather_attrs(attrs) {
620             let v = match result {
621                 Err(span) => {
622                     span_err!(self.sess(), span, E0452,
623                               "malformed lint attribute");
624                     continue;
625                 }
626                 Ok((lint_name, level, span)) => {
627                     match self.lints().find_lint(&lint_name.as_str(), &self.sess(), Some(span)) {
628                         Ok(lint_id) => vec![(lint_id, level, span)],
629                         Err(FindLintError::NotFound) => {
630                             match self.lints().lint_groups.get(&*lint_name.as_str()) {
631                                 Some(&(ref v, _)) => v.iter()
632                                                       .map(|lint_id: &LintId|
633                                                            (*lint_id, level, span))
634                                                       .collect(),
635                                 None => {
636                                     // The lint or lint group doesn't exist.
637                                     // This is an error, but it was handled
638                                     // by check_lint_name_attribute.
639                                     continue;
640                                 }
641                             }
642                         },
643                         Err(FindLintError::Removed) => { continue; }
644                     }
645                 }
646             };
647
648             for (lint_id, level, span) in v {
649                 let (now, now_source) = self.lints().get_level_source(lint_id);
650                 if now == Forbid && level != Forbid {
651                     let lint_name = lint_id.to_string();
652                     let mut diag_builder = struct_span_err!(self.sess(), span, E0453,
653                                                             "{}({}) overruled by outer forbid({})",
654                                                             level.as_str(), lint_name,
655                                                             lint_name);
656                     diag_builder.span_label(span, &format!("overruled by previous forbid"));
657                     match now_source {
658                         LintSource::Default => &mut diag_builder,
659                         LintSource::Node(forbid_source_span) => {
660                             diag_builder.span_label(forbid_source_span,
661                                                     &format!("`forbid` level set here"))
662                         },
663                         LintSource::CommandLine => {
664                             diag_builder.note("`forbid` lint level was set on command line")
665                         }
666                     }.emit()
667                 } else if now != level {
668                     let src = self.lints().get_level_source(lint_id).1;
669                     self.level_stack().push((lint_id, (now, src)));
670                     pushed += 1;
671                     self.mut_lints().set_level(lint_id, (level, Node(span)));
672                 }
673             }
674         }
675
676         self.enter_attrs(attrs);
677         f(self);
678         self.exit_attrs(attrs);
679
680         // rollback
681         for _ in 0..pushed {
682             let (lint, lvlsrc) = self.level_stack().pop().unwrap();
683             self.mut_lints().set_level(lint, lvlsrc);
684         }
685     }
686 }
687
688
689 impl<'a> EarlyContext<'a> {
690     fn new(sess: &'a Session,
691            krate: &'a ast::Crate) -> EarlyContext<'a> {
692         // We want to own the lint store, so move it out of the session. Remember
693         // to put it back later...
694         let lint_store = mem::replace(&mut *sess.lint_store.borrow_mut(),
695                                       LintStore::new());
696         EarlyContext {
697             sess: sess,
698             krate: krate,
699             lints: lint_store,
700             level_stack: vec![],
701         }
702     }
703 }
704
705 impl<'a, 'tcx> LateContext<'a, 'tcx> {
706     fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
707            krate: &'a hir::Crate,
708            access_levels: &'a AccessLevels) -> LateContext<'a, 'tcx> {
709         // We want to own the lint store, so move it out of the session.
710         let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
711                                       LintStore::new());
712
713         LateContext {
714             tcx: tcx,
715             krate: krate,
716             access_levels: access_levels,
717             lints: lint_store,
718             level_stack: vec![],
719         }
720     }
721
722     fn visit_ids<F>(&mut self, f: F)
723         where F: FnOnce(&mut IdVisitor)
724     {
725         let mut v = IdVisitor {
726             cx: self
727         };
728         f(&mut v);
729     }
730 }
731
732 impl<'a, 'tcx> LintContext for LateContext<'a, 'tcx> {
733     /// Get the overall compiler `Session` object.
734     fn sess(&self) -> &Session {
735         &self.tcx.sess
736     }
737
738     fn lints(&self) -> &LintStore {
739         &self.lints
740     }
741
742     fn mut_lints(&mut self) -> &mut LintStore {
743         &mut self.lints
744     }
745
746     fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> {
747         &mut self.level_stack
748     }
749
750     fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
751         debug!("late context: enter_attrs({:?})", attrs);
752         run_lints!(self, enter_lint_attrs, late_passes, attrs);
753     }
754
755     fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
756         debug!("late context: exit_attrs({:?})", attrs);
757         run_lints!(self, exit_lint_attrs, late_passes, attrs);
758     }
759 }
760
761 impl<'a> LintContext for EarlyContext<'a> {
762     /// Get the overall compiler `Session` object.
763     fn sess(&self) -> &Session {
764         &self.sess
765     }
766
767     fn lints(&self) -> &LintStore {
768         &self.lints
769     }
770
771     fn mut_lints(&mut self) -> &mut LintStore {
772         &mut self.lints
773     }
774
775     fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> {
776         &mut self.level_stack
777     }
778
779     fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
780         debug!("early context: enter_attrs({:?})", attrs);
781         run_lints!(self, enter_lint_attrs, early_passes, attrs);
782     }
783
784     fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
785         debug!("early context: exit_attrs({:?})", attrs);
786         run_lints!(self, exit_lint_attrs, early_passes, attrs);
787     }
788 }
789
790 impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
791     /// Because lints are scoped lexically, we want to walk nested
792     /// items in the context of the outer item, so enable
793     /// deep-walking.
794     fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'tcx>> {
795         Some(&self.tcx.map)
796     }
797
798     fn visit_item(&mut self, it: &'tcx hir::Item) {
799         self.with_lint_attrs(&it.attrs, |cx| {
800             run_lints!(cx, check_item, late_passes, it);
801             cx.visit_ids(|v| v.visit_item(it));
802             hir_visit::walk_item(cx, it);
803             run_lints!(cx, check_item_post, late_passes, it);
804         })
805     }
806
807     fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
808         self.with_lint_attrs(&it.attrs, |cx| {
809             run_lints!(cx, check_foreign_item, late_passes, it);
810             hir_visit::walk_foreign_item(cx, it);
811             run_lints!(cx, check_foreign_item_post, late_passes, it);
812         })
813     }
814
815     fn visit_pat(&mut self, p: &'tcx hir::Pat) {
816         run_lints!(self, check_pat, late_passes, p);
817         hir_visit::walk_pat(self, p);
818     }
819
820     fn visit_expr(&mut self, e: &'tcx hir::Expr) {
821         self.with_lint_attrs(&e.attrs, |cx| {
822             run_lints!(cx, check_expr, late_passes, e);
823             hir_visit::walk_expr(cx, e);
824         })
825     }
826
827     fn visit_stmt(&mut self, s: &'tcx hir::Stmt) {
828         // statement attributes are actually just attributes on one of
829         // - item
830         // - local
831         // - expression
832         // so we keep track of lint levels there
833         run_lints!(self, check_stmt, late_passes, s);
834         hir_visit::walk_stmt(self, s);
835     }
836
837     fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
838                 body: &'tcx hir::Expr, span: Span, id: ast::NodeId) {
839         run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
840         hir_visit::walk_fn(self, fk, decl, body, span, id);
841         run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
842     }
843
844     fn visit_variant_data(&mut self,
845                         s: &'tcx hir::VariantData,
846                         name: ast::Name,
847                         g: &'tcx hir::Generics,
848                         item_id: ast::NodeId,
849                         _: Span) {
850         run_lints!(self, check_struct_def, late_passes, s, name, g, item_id);
851         hir_visit::walk_struct_def(self, s);
852         run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id);
853     }
854
855     fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
856         self.with_lint_attrs(&s.attrs, |cx| {
857             run_lints!(cx, check_struct_field, late_passes, s);
858             hir_visit::walk_struct_field(cx, s);
859         })
860     }
861
862     fn visit_variant(&mut self,
863                      v: &'tcx hir::Variant,
864                      g: &'tcx hir::Generics,
865                      item_id: ast::NodeId) {
866         self.with_lint_attrs(&v.node.attrs, |cx| {
867             run_lints!(cx, check_variant, late_passes, v, g);
868             hir_visit::walk_variant(cx, v, g, item_id);
869             run_lints!(cx, check_variant_post, late_passes, v, g);
870         })
871     }
872
873     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
874         run_lints!(self, check_ty, late_passes, t);
875         hir_visit::walk_ty(self, t);
876     }
877
878     fn visit_name(&mut self, sp: Span, name: ast::Name) {
879         run_lints!(self, check_name, late_passes, sp, name);
880     }
881
882     fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) {
883         run_lints!(self, check_mod, late_passes, m, s, n);
884         hir_visit::walk_mod(self, m, n);
885         run_lints!(self, check_mod_post, late_passes, m, s, n);
886     }
887
888     fn visit_local(&mut self, l: &'tcx hir::Local) {
889         self.with_lint_attrs(&l.attrs, |cx| {
890             run_lints!(cx, check_local, late_passes, l);
891             hir_visit::walk_local(cx, l);
892         })
893     }
894
895     fn visit_block(&mut self, b: &'tcx hir::Block) {
896         run_lints!(self, check_block, late_passes, b);
897         hir_visit::walk_block(self, b);
898         run_lints!(self, check_block_post, late_passes, b);
899     }
900
901     fn visit_arm(&mut self, a: &'tcx hir::Arm) {
902         run_lints!(self, check_arm, late_passes, a);
903         hir_visit::walk_arm(self, a);
904     }
905
906     fn visit_decl(&mut self, d: &'tcx hir::Decl) {
907         run_lints!(self, check_decl, late_passes, d);
908         hir_visit::walk_decl(self, d);
909     }
910
911     fn visit_expr_post(&mut self, e: &'tcx hir::Expr) {
912         run_lints!(self, check_expr_post, late_passes, e);
913     }
914
915     fn visit_generics(&mut self, g: &'tcx hir::Generics) {
916         run_lints!(self, check_generics, late_passes, g);
917         hir_visit::walk_generics(self, g);
918     }
919
920     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
921         self.with_lint_attrs(&trait_item.attrs, |cx| {
922             run_lints!(cx, check_trait_item, late_passes, trait_item);
923             cx.visit_ids(|v| hir_visit::walk_trait_item(v, trait_item));
924             hir_visit::walk_trait_item(cx, trait_item);
925             run_lints!(cx, check_trait_item_post, late_passes, trait_item);
926         });
927     }
928
929     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
930         self.with_lint_attrs(&impl_item.attrs, |cx| {
931             run_lints!(cx, check_impl_item, late_passes, impl_item);
932             cx.visit_ids(|v| hir_visit::walk_impl_item(v, impl_item));
933             hir_visit::walk_impl_item(cx, impl_item);
934             run_lints!(cx, check_impl_item_post, late_passes, impl_item);
935         });
936     }
937
938     fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
939         run_lints!(self, check_lifetime, late_passes, lt);
940     }
941
942     fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) {
943         run_lints!(self, check_lifetime_def, late_passes, lt);
944     }
945
946     fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) {
947         run_lints!(self, check_path, late_passes, p, id);
948         hir_visit::walk_path(self, p);
949     }
950
951     fn visit_path_list_item(&mut self, prefix: &'tcx hir::Path, item: &'tcx hir::PathListItem) {
952         run_lints!(self, check_path_list_item, late_passes, item);
953         hir_visit::walk_path_list_item(self, prefix, item);
954     }
955
956     fn visit_attribute(&mut self, attr: &ast::Attribute) {
957         check_lint_name_attribute(self, attr);
958         run_lints!(self, check_attribute, late_passes, attr);
959     }
960 }
961
962 impl<'a> ast_visit::Visitor for EarlyContext<'a> {
963     fn visit_item(&mut self, it: &ast::Item) {
964         self.with_lint_attrs(&it.attrs, |cx| {
965             run_lints!(cx, check_item, early_passes, it);
966             ast_visit::walk_item(cx, it);
967             run_lints!(cx, check_item_post, early_passes, it);
968         })
969     }
970
971     fn visit_foreign_item(&mut self, it: &ast::ForeignItem) {
972         self.with_lint_attrs(&it.attrs, |cx| {
973             run_lints!(cx, check_foreign_item, early_passes, it);
974             ast_visit::walk_foreign_item(cx, it);
975             run_lints!(cx, check_foreign_item_post, early_passes, it);
976         })
977     }
978
979     fn visit_pat(&mut self, p: &ast::Pat) {
980         run_lints!(self, check_pat, early_passes, p);
981         ast_visit::walk_pat(self, p);
982     }
983
984     fn visit_expr(&mut self, e: &ast::Expr) {
985         self.with_lint_attrs(&e.attrs, |cx| {
986             run_lints!(cx, check_expr, early_passes, e);
987             ast_visit::walk_expr(cx, e);
988         })
989     }
990
991     fn visit_stmt(&mut self, s: &ast::Stmt) {
992         run_lints!(self, check_stmt, early_passes, s);
993         ast_visit::walk_stmt(self, s);
994     }
995
996     fn visit_fn(&mut self, fk: ast_visit::FnKind, decl: &ast::FnDecl,
997                 span: Span, id: ast::NodeId) {
998         run_lints!(self, check_fn, early_passes, fk, decl, span, id);
999         ast_visit::walk_fn(self, fk, decl, span);
1000         run_lints!(self, check_fn_post, early_passes, fk, decl, span, id);
1001     }
1002
1003     fn visit_variant_data(&mut self,
1004                         s: &ast::VariantData,
1005                         ident: ast::Ident,
1006                         g: &ast::Generics,
1007                         item_id: ast::NodeId,
1008                         _: Span) {
1009         run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id);
1010         ast_visit::walk_struct_def(self, s);
1011         run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id);
1012     }
1013
1014     fn visit_struct_field(&mut self, s: &ast::StructField) {
1015         self.with_lint_attrs(&s.attrs, |cx| {
1016             run_lints!(cx, check_struct_field, early_passes, s);
1017             ast_visit::walk_struct_field(cx, s);
1018         })
1019     }
1020
1021     fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics, item_id: ast::NodeId) {
1022         self.with_lint_attrs(&v.node.attrs, |cx| {
1023             run_lints!(cx, check_variant, early_passes, v, g);
1024             ast_visit::walk_variant(cx, v, g, item_id);
1025             run_lints!(cx, check_variant_post, early_passes, v, g);
1026         })
1027     }
1028
1029     fn visit_ty(&mut self, t: &ast::Ty) {
1030         run_lints!(self, check_ty, early_passes, t);
1031         ast_visit::walk_ty(self, t);
1032     }
1033
1034     fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
1035         run_lints!(self, check_ident, early_passes, sp, id);
1036     }
1037
1038     fn visit_mod(&mut self, m: &ast::Mod, s: Span, n: ast::NodeId) {
1039         run_lints!(self, check_mod, early_passes, m, s, n);
1040         ast_visit::walk_mod(self, m);
1041         run_lints!(self, check_mod_post, early_passes, m, s, n);
1042     }
1043
1044     fn visit_local(&mut self, l: &ast::Local) {
1045         self.with_lint_attrs(&l.attrs, |cx| {
1046             run_lints!(cx, check_local, early_passes, l);
1047             ast_visit::walk_local(cx, l);
1048         })
1049     }
1050
1051     fn visit_block(&mut self, b: &ast::Block) {
1052         run_lints!(self, check_block, early_passes, b);
1053         ast_visit::walk_block(self, b);
1054         run_lints!(self, check_block_post, early_passes, b);
1055     }
1056
1057     fn visit_arm(&mut self, a: &ast::Arm) {
1058         run_lints!(self, check_arm, early_passes, a);
1059         ast_visit::walk_arm(self, a);
1060     }
1061
1062     fn visit_expr_post(&mut self, e: &ast::Expr) {
1063         run_lints!(self, check_expr_post, early_passes, e);
1064     }
1065
1066     fn visit_generics(&mut self, g: &ast::Generics) {
1067         run_lints!(self, check_generics, early_passes, g);
1068         ast_visit::walk_generics(self, g);
1069     }
1070
1071     fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
1072         self.with_lint_attrs(&trait_item.attrs, |cx| {
1073             run_lints!(cx, check_trait_item, early_passes, trait_item);
1074             ast_visit::walk_trait_item(cx, trait_item);
1075             run_lints!(cx, check_trait_item_post, early_passes, trait_item);
1076         });
1077     }
1078
1079     fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
1080         self.with_lint_attrs(&impl_item.attrs, |cx| {
1081             run_lints!(cx, check_impl_item, early_passes, impl_item);
1082             ast_visit::walk_impl_item(cx, impl_item);
1083             run_lints!(cx, check_impl_item_post, early_passes, impl_item);
1084         });
1085     }
1086
1087     fn visit_lifetime(&mut self, lt: &ast::Lifetime) {
1088         run_lints!(self, check_lifetime, early_passes, lt);
1089     }
1090
1091     fn visit_lifetime_def(&mut self, lt: &ast::LifetimeDef) {
1092         run_lints!(self, check_lifetime_def, early_passes, lt);
1093     }
1094
1095     fn visit_path(&mut self, p: &ast::Path, id: ast::NodeId) {
1096         run_lints!(self, check_path, early_passes, p, id);
1097         ast_visit::walk_path(self, p);
1098     }
1099
1100     fn visit_path_list_item(&mut self, prefix: &ast::Path, item: &ast::PathListItem) {
1101         run_lints!(self, check_path_list_item, early_passes, item);
1102         ast_visit::walk_path_list_item(self, prefix, item);
1103     }
1104
1105     fn visit_attribute(&mut self, attr: &ast::Attribute) {
1106         run_lints!(self, check_attribute, early_passes, attr);
1107     }
1108 }
1109
1110 struct IdVisitor<'a, 'b: 'a, 'tcx: 'a+'b> {
1111     cx: &'a mut LateContext<'b, 'tcx>
1112 }
1113
1114 // Output any lints that were previously added to the session.
1115 impl<'a, 'b, 'tcx, 'v> hir_visit::Visitor<'v> for IdVisitor<'a, 'b, 'tcx> {
1116     fn visit_id(&mut self, id: ast::NodeId) {
1117         if let Some(lints) = self.cx.sess().lints.borrow_mut().remove(&id) {
1118             debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
1119             for early_lint in lints {
1120                 self.cx.early_lint(early_lint);
1121             }
1122         }
1123     }
1124
1125     fn visit_trait_item(&mut self, _ti: &hir::TraitItem) {
1126         // Do not recurse into trait or impl items automatically. These are
1127         // processed separately by calling hir_visit::walk_trait_item()
1128     }
1129
1130     fn visit_impl_item(&mut self, _ii: &hir::ImplItem) {
1131         // See visit_trait_item()
1132     }
1133 }
1134
1135 enum CheckLintNameResult {
1136     Ok,
1137     // Lint doesn't exist
1138     NoLint,
1139     // The lint is either renamed or removed. This is the warning
1140     // message.
1141     Warning(String)
1142 }
1143
1144 /// Checks the name of a lint for its existence, and whether it was
1145 /// renamed or removed. Generates a DiagnosticBuilder containing a
1146 /// warning for renamed and removed lints. This is over both lint
1147 /// names from attributes and those passed on the command line. Since
1148 /// it emits non-fatal warnings and there are *two* lint passes that
1149 /// inspect attributes, this is only run from the late pass to avoid
1150 /// printing duplicate warnings.
1151 fn check_lint_name(lint_cx: &LintStore,
1152                    lint_name: &str) -> CheckLintNameResult {
1153     match lint_cx.by_name.get(lint_name) {
1154         Some(&Renamed(ref new_name, _)) => {
1155             CheckLintNameResult::Warning(
1156                 format!("lint {} has been renamed to {}", lint_name, new_name)
1157             )
1158         },
1159         Some(&Removed(ref reason)) => {
1160             CheckLintNameResult::Warning(
1161                 format!("lint {} has been removed: {}", lint_name, reason)
1162             )
1163         },
1164         None => {
1165             match lint_cx.lint_groups.get(lint_name) {
1166                 None => {
1167                     CheckLintNameResult::NoLint
1168                 }
1169                 Some(_) => {
1170                     /* lint group exists */
1171                     CheckLintNameResult::Ok
1172                 }
1173             }
1174         }
1175         Some(_) => {
1176             /* lint exists */
1177             CheckLintNameResult::Ok
1178         }
1179     }
1180 }
1181
1182 // Checks the validity of lint names derived from attributes
1183 fn check_lint_name_attribute(cx: &LateContext, attr: &ast::Attribute) {
1184     for result in gather_attr(attr) {
1185         match result {
1186             Err(_) => {
1187                 // Malformed lint attr. Reported by with_lint_attrs
1188                 continue;
1189             }
1190             Ok((lint_name, _, span)) => {
1191                 match check_lint_name(&cx.lints, &lint_name.as_str()) {
1192                     CheckLintNameResult::Ok => (),
1193                     CheckLintNameResult::Warning(ref msg) => {
1194                         cx.span_lint(builtin::RENAMED_AND_REMOVED_LINTS,
1195                                      span, msg);
1196                     }
1197                     CheckLintNameResult::NoLint => {
1198                         cx.span_lint(builtin::UNKNOWN_LINTS, span,
1199                                      &format!("unknown lint: `{}`",
1200                                               lint_name));
1201                     }
1202                 }
1203             }
1204         }
1205     }
1206 }
1207
1208 // Checks the validity of lint names derived from the command line
1209 fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore,
1210                            lint_name: &str, level: Level) {
1211     let db = match check_lint_name(lint_cx, lint_name) {
1212         CheckLintNameResult::Ok => None,
1213         CheckLintNameResult::Warning(ref msg) => {
1214             Some(sess.struct_warn(msg))
1215         },
1216         CheckLintNameResult::NoLint => {
1217             Some(sess.struct_err(&format!("unknown lint: `{}`", lint_name)))
1218         }
1219     };
1220
1221     if let Some(mut db) = db {
1222         let msg = format!("requested on the command line with `{} {}`",
1223                           match level {
1224                               Level::Allow => "-A",
1225                               Level::Warn => "-W",
1226                               Level::Deny => "-D",
1227                               Level::Forbid => "-F",
1228                           },
1229                           lint_name);
1230         db.note(&msg);
1231         db.emit();
1232     }
1233 }
1234
1235
1236 /// Perform lint checking on a crate.
1237 ///
1238 /// Consumes the `lint_store` field of the `Session`.
1239 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1240                              access_levels: &AccessLevels) {
1241     let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck);
1242
1243     let krate = tcx.map.krate();
1244     let mut cx = LateContext::new(tcx, krate, access_levels);
1245
1246     // Visit the whole crate.
1247     cx.with_lint_attrs(&krate.attrs, |cx| {
1248         cx.visit_ids(|v| {
1249             hir_visit::walk_crate(v, krate);
1250         });
1251
1252         // since the root module isn't visited as an item (because it isn't an
1253         // item), warn for it here.
1254         run_lints!(cx, check_crate, late_passes, krate);
1255
1256         hir_visit::walk_crate(cx, krate);
1257
1258         run_lints!(cx, check_crate_post, late_passes, krate);
1259     });
1260
1261     // If we missed any lints added to the session, then there's a bug somewhere
1262     // in the iteration code.
1263     for (id, v) in tcx.sess.lints.borrow().iter() {
1264         for early_lint in v {
1265             span_bug!(early_lint.diagnostic.span.clone(),
1266                       "unprocessed lint {:?} at {}",
1267                       early_lint, tcx.map.node_to_string(*id));
1268         }
1269     }
1270
1271     // Put the lint store back in the session.
1272     mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), cx.lints);
1273 }
1274
1275 pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
1276     let mut cx = EarlyContext::new(sess, krate);
1277
1278     // Visit the whole crate.
1279     cx.with_lint_attrs(&krate.attrs, |cx| {
1280         // Lints may be assigned to the whole crate.
1281         if let Some(lints) = cx.sess.lints.borrow_mut().remove(&ast::CRATE_NODE_ID) {
1282             for early_lint in lints {
1283                 cx.early_lint(early_lint);
1284             }
1285         }
1286
1287         // since the root module isn't visited as an item (because it isn't an
1288         // item), warn for it here.
1289         run_lints!(cx, check_crate, early_passes, krate);
1290
1291         ast_visit::walk_crate(cx, krate);
1292
1293         run_lints!(cx, check_crate_post, early_passes, krate);
1294     });
1295
1296     // Put the lint store back in the session.
1297     mem::replace(&mut *sess.lint_store.borrow_mut(), cx.lints);
1298
1299     // If we missed any lints added to the session, then there's a bug somewhere
1300     // in the iteration code.
1301     for (_, v) in sess.lints.borrow().iter() {
1302         for early_lint in v {
1303             span_bug!(early_lint.diagnostic.span.clone(), "unprocessed lint {:?}", early_lint);
1304         }
1305     }
1306 }