]> git.lizzy.rs Git - rust.git/blob - src/librustc/lint/context.rs
c633c0fb0360af45a71c86c4c01f4a72172f636e
[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
14 //! after all other analyses. 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.
21 //! 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
27 use self::TargetLint::*;
28
29 use std::slice;
30 use rustc_data_structures::sync::ReadGuard;
31 use lint::{EarlyLintPassObject, LateLintPassObject};
32 use lint::{Level, Lint, LintId, LintPass, LintBuffer};
33 use lint::builtin::BuiltinLintDiagnostics;
34 use lint::levels::{LintLevelSets, LintLevelsBuilder};
35 use middle::privacy::AccessLevels;
36 use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
37 use session::{config, early_error, Session};
38 use ty::{self, TyCtxt, Ty};
39 use ty::layout::{LayoutError, LayoutOf, TyLayout};
40 use util::nodemap::FxHashMap;
41
42 use std::default::Default as StdDefault;
43 use syntax::ast;
44 use syntax::edition;
45 use syntax_pos::{MultiSpan, Span, symbol::LocalInternedString};
46 use errors::DiagnosticBuilder;
47 use hir;
48 use hir::def_id::LOCAL_CRATE;
49 use hir::intravisit as hir_visit;
50 use syntax::visit as ast_visit;
51
52 /// Information about the registered lints.
53 ///
54 /// This is basically the subset of `Context` that we can
55 /// build early in the compile pipeline.
56 pub struct LintStore {
57     /// Registered lints. The bool is true if the lint was
58     /// added by a plugin.
59     lints: Vec<(&'static Lint, bool)>,
60
61     /// Trait objects for each lint pass.
62     /// This is only `None` while performing a lint pass.
63     pre_expansion_passes: Option<Vec<EarlyLintPassObject>>,
64     early_passes: Option<Vec<EarlyLintPassObject>>,
65     late_passes: Option<Vec<LateLintPassObject>>,
66
67     /// Lints indexed by name.
68     by_name: FxHashMap<String, TargetLint>,
69
70     /// Map of registered lint groups to what lints they expand to.
71     lint_groups: FxHashMap<&'static str, LintGroup>,
72
73     /// Extra info for future incompatibility lints, describing the
74     /// issue or RFC that caused the incompatibility.
75     future_incompatible: FxHashMap<LintId, FutureIncompatibleInfo>,
76 }
77
78 pub struct LintSession<'a, PassObject> {
79     /// Reference to the store of registered lints.
80     lints: ReadGuard<'a, LintStore>,
81
82     /// Trait objects for each lint pass.
83     passes: Option<Vec<PassObject>>,
84 }
85
86
87 /// Lints that are buffered up early on in the `Session` before the
88 /// `LintLevels` is calculated
89 #[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
90 pub struct BufferedEarlyLint {
91     pub lint_id: LintId,
92     pub ast_id: ast::NodeId,
93     pub span: MultiSpan,
94     pub msg: String,
95     pub diagnostic: BuiltinLintDiagnostics,
96 }
97
98 /// Extra information for a future incompatibility lint. See the call
99 /// to `register_future_incompatible` in `librustc_lint/lib.rs` for
100 /// guidelines.
101 pub struct FutureIncompatibleInfo {
102     pub id: LintId,
103     /// e.g., a URL for an issue/PR/RFC or error code
104     pub reference: &'static str,
105     /// If this is an edition fixing lint, the edition in which
106     /// this lint becomes obsolete
107     pub edition: Option<edition::Edition>,
108 }
109
110 /// The target of the `by_name` map, which accounts for renaming/deprecation.
111 enum TargetLint {
112     /// A direct lint target
113     Id(LintId),
114
115     /// Temporary renaming, used for easing migration pain; see #16545
116     Renamed(String, LintId),
117
118     /// Lint with this name existed previously, but has been removed/deprecated.
119     /// The string argument is the reason for removal.
120     Removed(String),
121 }
122
123 pub enum FindLintError {
124     NotFound,
125     Removed,
126 }
127
128 struct LintAlias {
129     name: &'static str,
130     /// Whether deprecation warnings should be suppressed for this alias.
131     silent: bool,
132 }
133
134 struct LintGroup {
135     lint_ids: Vec<LintId>,
136     from_plugin: bool,
137     depr: Option<LintAlias>,
138 }
139
140 pub enum CheckLintNameResult<'a> {
141     Ok(&'a [LintId]),
142     /// Lint doesn't exist
143     NoLint,
144     /// The lint is either renamed or removed. This is the warning
145     /// message, and an optional new name (`None` if removed).
146     Warning(String, Option<String>),
147     /// The lint is from a tool. If the Option is None, then either
148     /// the lint does not exist in the tool or the code was not
149     /// compiled with the tool and therefore the lint was never
150     /// added to the `LintStore`. Otherwise the `LintId` will be
151     /// returned as if it where a rustc lint.
152     Tool(Result<&'a [LintId], (Option<&'a [LintId]>, String)>),
153 }
154
155 impl LintStore {
156     pub fn new() -> LintStore {
157         LintStore {
158             lints: vec![],
159             pre_expansion_passes: Some(vec![]),
160             early_passes: Some(vec![]),
161             late_passes: Some(vec![]),
162             by_name: Default::default(),
163             future_incompatible: Default::default(),
164             lint_groups: Default::default(),
165         }
166     }
167
168     pub fn get_lints<'t>(&'t self) -> &'t [(&'static Lint, bool)] {
169         &self.lints
170     }
171
172     pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
173         self.lint_groups.iter()
174             .filter(|(_, LintGroup { depr, .. })| {
175                 // Don't display deprecated lint groups.
176                 depr.is_none()
177             })
178             .map(|(k, LintGroup { lint_ids, from_plugin, .. })| {
179                 (*k, lint_ids.clone(), *from_plugin)
180             })
181             .collect()
182     }
183
184     pub fn register_early_pass(&mut self,
185                                sess: Option<&Session>,
186                                from_plugin: bool,
187                                pass: EarlyLintPassObject) {
188         self.push_pass(sess, from_plugin, &pass);
189         self.early_passes.as_mut().unwrap().push(pass);
190     }
191
192     pub fn register_pre_expansion_pass(
193         &mut self,
194         sess: Option<&Session>,
195         pass: EarlyLintPassObject,
196     ) {
197         self.push_pass(sess, false, &pass);
198         self.pre_expansion_passes.as_mut().unwrap().push(pass);
199     }
200
201     pub fn register_late_pass(&mut self,
202                               sess: Option<&Session>,
203                               from_plugin: bool,
204                               pass: LateLintPassObject) {
205         self.push_pass(sess, from_plugin, &pass);
206         self.late_passes.as_mut().unwrap().push(pass);
207     }
208
209     // Helper method for register_early/late_pass
210     fn push_pass<P: LintPass + ?Sized + 'static>(&mut self,
211                                         sess: Option<&Session>,
212                                         from_plugin: bool,
213                                         pass: &Box<P>) {
214         for lint in pass.get_lints() {
215             self.lints.push((lint, from_plugin));
216
217             let id = LintId::of(lint);
218             if self.by_name.insert(lint.name_lower(), Id(id)).is_some() {
219                 let msg = format!("duplicate specification of lint {}", lint.name_lower());
220                 match (sess, from_plugin) {
221                     // We load builtin lints first, so a duplicate is a compiler bug.
222                     // Use early_error when handling -W help with no crate.
223                     (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
224                     (Some(_), false) => 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
233     pub fn register_future_incompatible(&mut self,
234                                         sess: Option<&Session>,
235                                         lints: Vec<FutureIncompatibleInfo>) {
236
237         for edition in edition::ALL_EDITIONS {
238             let lints = lints.iter().filter(|f| f.edition == Some(*edition)).map(|f| f.id)
239                              .collect::<Vec<_>>();
240             if !lints.is_empty() {
241                 self.register_group(sess, false, edition.lint_name(), None, lints)
242             }
243         }
244
245         let mut future_incompatible = Vec::with_capacity(lints.len());
246         for lint in lints {
247             future_incompatible.push(lint.id);
248             self.future_incompatible.insert(lint.id, lint);
249         }
250
251         self.register_group(
252             sess,
253             false,
254             "future_incompatible",
255             None,
256             future_incompatible,
257         );
258     }
259
260     pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
261         self.future_incompatible.get(&id)
262     }
263
264     pub fn register_group_alias(
265         &mut self,
266         lint_name: &'static str,
267         alias: &'static str,
268     ) {
269         self.lint_groups.insert(alias, LintGroup {
270             lint_ids: vec![],
271             from_plugin: false,
272             depr: Some(LintAlias { name: lint_name, silent: true }),
273         });
274     }
275
276     pub fn register_group(
277         &mut self,
278         sess: Option<&Session>,
279         from_plugin: bool,
280         name: &'static str,
281         deprecated_name: Option<&'static str>,
282         to: Vec<LintId>,
283     ) {
284         let new = self
285             .lint_groups
286             .insert(name, LintGroup {
287                 lint_ids: to,
288                 from_plugin,
289                 depr: None,
290             })
291             .is_none();
292         if let Some(deprecated) = deprecated_name {
293             self.lint_groups.insert(deprecated, LintGroup {
294                 lint_ids: vec![],
295                 from_plugin,
296                 depr: Some(LintAlias { name, silent: false }),
297             });
298         }
299
300         if !new {
301             let msg = format!("duplicate specification of lint group {}", name);
302             match (sess, from_plugin) {
303                 // We load builtin lints first, so a duplicate is a compiler bug.
304                 // Use early_error when handling -W help with no crate.
305                 (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]),
306                 (Some(_), false) => bug!("{}", msg),
307
308                 // A duplicate name from a plugin is a user error.
309                 (Some(sess), true)  => sess.err(&msg[..]),
310             }
311         }
312     }
313
314     pub fn register_renamed(&mut self, old_name: &str, new_name: &str) {
315         let target = match self.by_name.get(new_name) {
316             Some(&Id(lint_id)) => lint_id.clone(),
317             _ => bug!("invalid lint renaming of {} to {}", old_name, new_name)
318         };
319         self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target));
320     }
321
322     pub fn register_removed(&mut self, name: &str, reason: &str) {
323         self.by_name.insert(name.into(), Removed(reason.into()));
324     }
325
326     pub fn find_lints(&self, mut lint_name: &str) -> Result<Vec<LintId>, FindLintError> {
327         match self.by_name.get(lint_name) {
328             Some(&Id(lint_id)) => Ok(vec![lint_id]),
329             Some(&Renamed(_, lint_id)) => {
330                 Ok(vec![lint_id])
331             },
332             Some(&Removed(_)) => {
333                 Err(FindLintError::Removed)
334             },
335             None => {
336                 loop {
337                     return match self.lint_groups.get(lint_name) {
338                         Some(LintGroup {lint_ids, depr, .. }) => {
339                             if let Some(LintAlias { name, .. }) = depr {
340                                 lint_name = name;
341                                 continue;
342                             }
343                             Ok(lint_ids.clone())
344                         }
345                         None => Err(FindLintError::Removed)
346                     };
347                 }
348             }
349         }
350     }
351
352     /// Checks the validity of lint names derived from the command line
353     pub fn check_lint_name_cmdline(&self,
354                                    sess: &Session,
355                                    lint_name: &str,
356                                    level: Level) {
357         let db = match self.check_lint_name(lint_name, None) {
358             CheckLintNameResult::Ok(_) => None,
359             CheckLintNameResult::Warning(ref msg, _) => {
360                 Some(sess.struct_warn(msg))
361             },
362             CheckLintNameResult::NoLint => {
363                 Some(struct_err!(sess, E0602, "unknown lint: `{}`", lint_name))
364             }
365             CheckLintNameResult::Tool(result) => match result {
366                 Err((Some(_), new_name)) => Some(sess.struct_warn(&format!(
367                     "lint name `{}` is deprecated \
368                      and does not have an effect anymore. \
369                      Use: {}",
370                     lint_name, new_name
371                 ))),
372                 _ => None,
373             },
374         };
375
376         if let Some(mut db) = db {
377             let msg = format!("requested on the command line with `{} {}`",
378                               match level {
379                                   Level::Allow => "-A",
380                                   Level::Warn => "-W",
381                                   Level::Deny => "-D",
382                                   Level::Forbid => "-F",
383                               },
384                               lint_name);
385             db.note(&msg);
386             db.emit();
387         }
388     }
389
390     /// Checks the name of a lint for its existence, and whether it was
391     /// renamed or removed. Generates a DiagnosticBuilder containing a
392     /// warning for renamed and removed lints. This is over both lint
393     /// names from attributes and those passed on the command line. Since
394     /// it emits non-fatal warnings and there are *two* lint passes that
395     /// inspect attributes, this is only run from the late pass to avoid
396     /// printing duplicate warnings.
397     pub fn check_lint_name(
398         &self,
399         lint_name: &str,
400         tool_name: Option<LocalInternedString>,
401     ) -> CheckLintNameResult<'_> {
402         let complete_name = if let Some(tool_name) = tool_name {
403             format!("{}::{}", tool_name, lint_name)
404         } else {
405             lint_name.to_string()
406         };
407         // If the lint was scoped with `tool::` check if the tool lint exists
408         if let Some(_) = tool_name {
409             match self.by_name.get(&complete_name) {
410                 None => match self.lint_groups.get(&*complete_name) {
411                     None => return CheckLintNameResult::Tool(Err((None, String::new()))),
412                     Some(LintGroup { lint_ids, .. }) => {
413                         return CheckLintNameResult::Tool(Ok(&lint_ids));
414                     }
415                 },
416                 Some(&Id(ref id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))),
417                 // If the lint was registered as removed or renamed by the lint tool, we don't need
418                 // to treat tool_lints and rustc lints different and can use the code below.
419                 _ => {}
420             }
421         }
422         match self.by_name.get(&complete_name) {
423             Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning(
424                 format!(
425                     "lint `{}` has been renamed to `{}`",
426                     complete_name, new_name
427                 ),
428                 Some(new_name.to_owned()),
429             ),
430             Some(&Removed(ref reason)) => CheckLintNameResult::Warning(
431                 format!("lint `{}` has been removed: `{}`", complete_name, reason),
432                 None,
433             ),
434             None => match self.lint_groups.get(&*complete_name) {
435                 // If neither the lint, nor the lint group exists check if there is a `clippy::`
436                 // variant of this lint
437                 None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
438                 Some(LintGroup { lint_ids, depr, .. }) => {
439                     // Check if the lint group name is deprecated
440                     if let Some(LintAlias { name, silent }) = depr {
441                         let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
442                         return if *silent {
443                             CheckLintNameResult::Ok(&lint_ids)
444                         } else {
445                             CheckLintNameResult::Tool(Err((
446                                 Some(&lint_ids),
447                                 name.to_string(),
448                             )))
449                         };
450                     }
451                     CheckLintNameResult::Ok(&lint_ids)
452                 }
453             },
454             Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
455         }
456     }
457
458     fn check_tool_name_for_backwards_compat(
459         &self,
460         lint_name: &str,
461         tool_name: &str,
462     ) -> CheckLintNameResult<'_> {
463         let complete_name = format!("{}::{}", tool_name, lint_name);
464         match self.by_name.get(&complete_name) {
465             None => match self.lint_groups.get(&*complete_name) {
466                 // Now we are sure, that this lint exists nowhere
467                 None => CheckLintNameResult::NoLint,
468                 Some(LintGroup { lint_ids, depr, .. }) => {
469                     // Reaching this would be weird, but let's cover this case anyway
470                     if let Some(LintAlias { name, silent }) = depr {
471                         let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
472                         return if *silent {
473                             CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
474                         } else {
475                             CheckLintNameResult::Tool(Err((
476                                 Some(&lint_ids),
477                                 name.to_string(),
478                             )))
479                         };
480                     }
481                     CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name)))
482                 }
483             },
484             Some(&Id(ref id)) => {
485                 CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name)))
486             }
487             _ => CheckLintNameResult::NoLint,
488         }
489     }
490 }
491
492 /// Context for lint checking after type checking.
493 pub struct LateContext<'a, 'tcx: 'a> {
494     /// Type context we're checking in.
495     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
496
497     /// Side-tables for the body we are in.
498     pub tables: &'a ty::TypeckTables<'tcx>,
499
500     /// Parameter environment for the item we are in.
501     pub param_env: ty::ParamEnv<'tcx>,
502
503     /// Items accessible from the crate being checked.
504     pub access_levels: &'a AccessLevels,
505
506     /// The store of registered lints and the lint levels.
507     lint_sess: LintSession<'tcx, LateLintPassObject>,
508
509     last_ast_node_with_lint_attrs: ast::NodeId,
510
511     /// Generic type parameters in scope for the item we are in.
512     pub generics: Option<&'tcx hir::Generics>,
513 }
514
515 /// Context for lint checking of the AST, after expansion, before lowering to
516 /// HIR.
517 pub struct EarlyContext<'a> {
518     /// Type context we're checking in.
519     pub sess: &'a Session,
520
521     /// The crate being checked.
522     pub krate: &'a ast::Crate,
523
524     builder: LintLevelsBuilder<'a>,
525
526     /// The store of registered lints and the lint levels.
527     lint_sess: LintSession<'a, EarlyLintPassObject>,
528
529     buffered: LintBuffer,
530 }
531
532 /// Convenience macro for calling a `LintPass` method on every pass in the context.
533 macro_rules! run_lints { ($cx:expr, $f:ident, $($args:expr),*) => ({
534     // Move the vector of passes out of `$cx` so that we can
535     // iterate over it mutably while passing `$cx` to the methods.
536     let mut passes = $cx.lint_sess_mut().passes.take().unwrap();
537     for obj in &mut passes {
538         obj.$f($cx, $($args),*);
539     }
540     $cx.lint_sess_mut().passes = Some(passes);
541 }) }
542
543 pub trait LintPassObject: Sized {}
544
545 impl LintPassObject for EarlyLintPassObject {}
546
547 impl LintPassObject for LateLintPassObject {}
548
549
550 pub trait LintContext<'tcx>: Sized {
551     type PassObject: LintPassObject;
552
553     fn sess(&self) -> &Session;
554     fn lints(&self) -> &LintStore;
555     fn lint_sess(&self) -> &LintSession<'tcx, Self::PassObject>;
556     fn lint_sess_mut(&mut self) -> &mut LintSession<'tcx, Self::PassObject>;
557     fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]);
558     fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]);
559
560     fn lookup_and_emit<S: Into<MultiSpan>>(&self,
561                                            lint: &'static Lint,
562                                            span: Option<S>,
563                                            msg: &str) {
564         self.lookup(lint, span, msg).emit();
565     }
566
567     fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(&self,
568                                                             lint: &'static Lint,
569                                                             span: Option<S>,
570                                                             msg: &str,
571                                                             diagnostic: BuiltinLintDiagnostics) {
572         let mut db = self.lookup(lint, span, msg);
573         diagnostic.run(self.sess(), &mut db);
574         db.emit();
575     }
576
577     fn lookup<S: Into<MultiSpan>>(&self,
578                                   lint: &'static Lint,
579                                   span: Option<S>,
580                                   msg: &str)
581                                   -> DiagnosticBuilder<'_>;
582
583     /// Emit a lint at the appropriate level, for a particular span.
584     fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) {
585         self.lookup_and_emit(lint, Some(span), msg);
586     }
587
588     fn struct_span_lint<S: Into<MultiSpan>>(&self,
589                                             lint: &'static Lint,
590                                             span: S,
591                                             msg: &str)
592                                             -> DiagnosticBuilder<'_> {
593         self.lookup(lint, Some(span), msg)
594     }
595
596     /// Emit a lint and note at the appropriate level, for a particular span.
597     fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str,
598                       note_span: Span, note: &str) {
599         let mut err = self.lookup(lint, Some(span), msg);
600         if note_span == span {
601             err.note(note);
602         } else {
603             err.span_note(note_span, note);
604         }
605         err.emit();
606     }
607
608     /// Emit a lint and help at the appropriate level, for a particular span.
609     fn span_lint_help(&self, lint: &'static Lint, span: Span,
610                       msg: &str, help: &str) {
611         let mut err = self.lookup(lint, Some(span), msg);
612         self.span_lint(lint, span, msg);
613         err.span_help(span, help);
614         err.emit();
615     }
616
617     /// Emit a lint at the appropriate level, with no associated span.
618     fn lint(&self, lint: &'static Lint, msg: &str) {
619         self.lookup_and_emit(lint, None as Option<Span>, msg);
620     }
621
622     /// Merge the lints specified by any lint attributes into the
623     /// current lint context, call the provided function, then reset the
624     /// lints in effect to their previous state.
625     fn with_lint_attrs<F>(&mut self,
626                           id: ast::NodeId,
627                           attrs: &'tcx [ast::Attribute],
628                           f: F)
629         where F: FnOnce(&mut Self);
630 }
631
632
633 impl<'a> EarlyContext<'a> {
634     fn new(
635         sess: &'a Session,
636         krate: &'a ast::Crate,
637         passes: Option<Vec<EarlyLintPassObject>>,
638         buffered: LintBuffer,
639     ) -> EarlyContext<'a> {
640         EarlyContext {
641             sess,
642             krate,
643             lint_sess: LintSession {
644                 lints: sess.lint_store.borrow(),
645                 passes,
646             },
647             builder: LintLevelSets::builder(sess),
648             buffered,
649         }
650     }
651
652     fn check_id(&mut self, id: ast::NodeId) {
653         for early_lint in self.buffered.take(id) {
654             self.lookup_and_emit_with_diagnostics(early_lint.lint_id.lint,
655                                                   Some(early_lint.span.clone()),
656                                                   &early_lint.msg,
657                                                   early_lint.diagnostic);
658         }
659     }
660 }
661
662 impl<'a, 'tcx> LintContext<'tcx> for LateContext<'a, 'tcx> {
663     type PassObject = LateLintPassObject;
664
665     /// Get the overall compiler `Session` object.
666     fn sess(&self) -> &Session {
667         &self.tcx.sess
668     }
669
670     fn lints(&self) -> &LintStore {
671         &*self.lint_sess.lints
672     }
673
674     fn lint_sess(&self) -> &LintSession<'tcx, Self::PassObject> {
675         &self.lint_sess
676     }
677
678     fn lint_sess_mut(&mut self) -> &mut LintSession<'tcx, Self::PassObject> {
679         &mut self.lint_sess
680     }
681
682     fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
683         debug!("late context: enter_attrs({:?})", attrs);
684         run_lints!(self, enter_lint_attrs, attrs);
685     }
686
687     fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
688         debug!("late context: exit_attrs({:?})", attrs);
689         run_lints!(self, exit_lint_attrs, attrs);
690     }
691
692     fn lookup<S: Into<MultiSpan>>(&self,
693                                   lint: &'static Lint,
694                                   span: Option<S>,
695                                   msg: &str)
696                                   -> DiagnosticBuilder<'_> {
697         let id = self.last_ast_node_with_lint_attrs;
698         match span {
699             Some(s) => self.tcx.struct_span_lint_node(lint, id, s, msg),
700             None => self.tcx.struct_lint_node(lint, id, msg),
701         }
702     }
703
704     fn with_lint_attrs<F>(&mut self,
705                           id: ast::NodeId,
706                           attrs: &'tcx [ast::Attribute],
707                           f: F)
708         where F: FnOnce(&mut Self)
709     {
710         let prev = self.last_ast_node_with_lint_attrs;
711         self.last_ast_node_with_lint_attrs = id;
712         self.enter_attrs(attrs);
713         f(self);
714         self.exit_attrs(attrs);
715         self.last_ast_node_with_lint_attrs = prev;
716     }
717 }
718
719 impl<'a> LintContext<'a> for EarlyContext<'a> {
720     type PassObject = EarlyLintPassObject;
721
722     /// Get the overall compiler `Session` object.
723     fn sess(&self) -> &Session {
724         &self.sess
725     }
726
727     fn lints(&self) -> &LintStore {
728         &*self.lint_sess.lints
729     }
730
731     fn lint_sess(&self) -> &LintSession<'a, Self::PassObject> {
732         &self.lint_sess
733     }
734
735     fn lint_sess_mut(&mut self) -> &mut LintSession<'a, Self::PassObject> {
736         &mut self.lint_sess
737     }
738
739     fn enter_attrs(&mut self, attrs: &'a [ast::Attribute]) {
740         debug!("early context: enter_attrs({:?})", attrs);
741         run_lints!(self, enter_lint_attrs, attrs);
742     }
743
744     fn exit_attrs(&mut self, attrs: &'a [ast::Attribute]) {
745         debug!("early context: exit_attrs({:?})", attrs);
746         run_lints!(self, exit_lint_attrs, attrs);
747     }
748
749     fn lookup<S: Into<MultiSpan>>(&self,
750                                   lint: &'static Lint,
751                                   span: Option<S>,
752                                   msg: &str)
753                                   -> DiagnosticBuilder<'_> {
754         self.builder.struct_lint(lint, span.map(|s| s.into()), msg)
755     }
756
757     fn with_lint_attrs<F>(&mut self,
758                           id: ast::NodeId,
759                           attrs: &'a [ast::Attribute],
760                           f: F)
761         where F: FnOnce(&mut Self)
762     {
763         let push = self.builder.push(attrs);
764         self.check_id(id);
765         self.enter_attrs(attrs);
766         f(self);
767         self.exit_attrs(attrs);
768         self.builder.pop(push);
769     }
770 }
771
772 impl<'a, 'tcx> LateContext<'a, 'tcx> {
773     fn with_param_env<F>(&mut self, id: ast::NodeId, f: F)
774         where F: FnOnce(&mut Self),
775     {
776         let old_param_env = self.param_env;
777         self.param_env = self.tcx.param_env(self.tcx.hir().local_def_id(id));
778         f(self);
779         self.param_env = old_param_env;
780     }
781     pub fn current_lint_root(&self) -> ast::NodeId {
782         self.last_ast_node_with_lint_attrs
783     }
784 }
785
786 impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> {
787     type Ty = Ty<'tcx>;
788     type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
789
790     fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout {
791         self.tcx.layout_of(self.param_env.and(ty))
792     }
793 }
794
795 impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> {
796     /// Because lints are scoped lexically, we want to walk nested
797     /// items in the context of the outer item, so enable
798     /// deep-walking.
799     fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> {
800         hir_visit::NestedVisitorMap::All(&self.tcx.hir())
801     }
802
803     fn visit_nested_body(&mut self, body: hir::BodyId) {
804         let old_tables = self.tables;
805         self.tables = self.tcx.body_tables(body);
806         let body = self.tcx.hir().body(body);
807         self.visit_body(body);
808         self.tables = old_tables;
809     }
810
811     fn visit_body(&mut self, body: &'tcx hir::Body) {
812         run_lints!(self, check_body, body);
813         hir_visit::walk_body(self, body);
814         run_lints!(self, check_body_post, body);
815     }
816
817     fn visit_item(&mut self, it: &'tcx hir::Item) {
818         let generics = self.generics.take();
819         self.generics = it.node.generics();
820         self.with_lint_attrs(it.id, &it.attrs, |cx| {
821             cx.with_param_env(it.id, |cx| {
822                 run_lints!(cx, check_item, it);
823                 hir_visit::walk_item(cx, it);
824                 run_lints!(cx, check_item_post, it);
825             });
826         });
827         self.generics = generics;
828     }
829
830     fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) {
831         self.with_lint_attrs(it.id, &it.attrs, |cx| {
832             cx.with_param_env(it.id, |cx| {
833                 run_lints!(cx, check_foreign_item, it);
834                 hir_visit::walk_foreign_item(cx, it);
835                 run_lints!(cx, check_foreign_item_post, it);
836             });
837         })
838     }
839
840     fn visit_pat(&mut self, p: &'tcx hir::Pat) {
841         run_lints!(self, check_pat, p);
842         hir_visit::walk_pat(self, p);
843     }
844
845     fn visit_expr(&mut self, e: &'tcx hir::Expr) {
846         self.with_lint_attrs(e.id, &e.attrs, |cx| {
847             run_lints!(cx, check_expr, e);
848             hir_visit::walk_expr(cx, e);
849             run_lints!(cx, check_expr_post, e);
850         })
851     }
852
853     fn visit_stmt(&mut self, s: &'tcx hir::Stmt) {
854         // statement attributes are actually just attributes on one of
855         // - item
856         // - local
857         // - expression
858         // so we keep track of lint levels there
859         run_lints!(self, check_stmt, s);
860         hir_visit::walk_stmt(self, s);
861     }
862
863     fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
864                 body_id: hir::BodyId, span: Span, id: ast::NodeId) {
865         // Wrap in tables here, not just in visit_nested_body,
866         // in order for `check_fn` to be able to use them.
867         let old_tables = self.tables;
868         self.tables = self.tcx.body_tables(body_id);
869         let body = self.tcx.hir().body(body_id);
870         run_lints!(self, check_fn, fk, decl, body, span, id);
871         hir_visit::walk_fn(self, fk, decl, body_id, span, id);
872         run_lints!(self, check_fn_post, fk, decl, body, span, id);
873         self.tables = old_tables;
874     }
875
876     fn visit_variant_data(&mut self,
877                         s: &'tcx hir::VariantData,
878                         name: ast::Name,
879                         g: &'tcx hir::Generics,
880                         item_id: ast::NodeId,
881                         _: Span) {
882         run_lints!(self, check_struct_def, s, name, g, item_id);
883         hir_visit::walk_struct_def(self, s);
884         run_lints!(self, check_struct_def_post, s, name, g, item_id);
885     }
886
887     fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
888         self.with_lint_attrs(s.id, &s.attrs, |cx| {
889             run_lints!(cx, check_struct_field, s);
890             hir_visit::walk_struct_field(cx, s);
891         })
892     }
893
894     fn visit_variant(&mut self,
895                      v: &'tcx hir::Variant,
896                      g: &'tcx hir::Generics,
897                      item_id: ast::NodeId) {
898         self.with_lint_attrs(v.node.data.id(), &v.node.attrs, |cx| {
899             run_lints!(cx, check_variant, v, g);
900             hir_visit::walk_variant(cx, v, g, item_id);
901             run_lints!(cx, check_variant_post, v, g);
902         })
903     }
904
905     fn visit_ty(&mut self, t: &'tcx hir::Ty) {
906         run_lints!(self, check_ty, t);
907         hir_visit::walk_ty(self, t);
908     }
909
910     fn visit_name(&mut self, sp: Span, name: ast::Name) {
911         run_lints!(self, check_name, sp, name);
912     }
913
914     fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) {
915         run_lints!(self, check_mod, m, s, n);
916         hir_visit::walk_mod(self, m, n);
917         run_lints!(self, check_mod_post, m, s, n);
918     }
919
920     fn visit_local(&mut self, l: &'tcx hir::Local) {
921         self.with_lint_attrs(l.id, &l.attrs, |cx| {
922             run_lints!(cx, check_local, l);
923             hir_visit::walk_local(cx, l);
924         })
925     }
926
927     fn visit_block(&mut self, b: &'tcx hir::Block) {
928         run_lints!(self, check_block, b);
929         hir_visit::walk_block(self, b);
930         run_lints!(self, check_block_post, b);
931     }
932
933     fn visit_arm(&mut self, a: &'tcx hir::Arm) {
934         run_lints!(self, check_arm, a);
935         hir_visit::walk_arm(self, a);
936     }
937
938     fn visit_decl(&mut self, d: &'tcx hir::Decl) {
939         run_lints!(self, check_decl, d);
940         hir_visit::walk_decl(self, d);
941     }
942
943     fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) {
944         run_lints!(self, check_generic_param, p);
945         hir_visit::walk_generic_param(self, p);
946     }
947
948     fn visit_generics(&mut self, g: &'tcx hir::Generics) {
949         run_lints!(self, check_generics, g);
950         hir_visit::walk_generics(self, g);
951     }
952
953     fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate) {
954         run_lints!(self, check_where_predicate, p);
955         hir_visit::walk_where_predicate(self, p);
956     }
957
958     fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef,
959                             m: hir::TraitBoundModifier) {
960         run_lints!(self, check_poly_trait_ref, t, m);
961         hir_visit::walk_poly_trait_ref(self, t, m);
962     }
963
964     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
965         let generics = self.generics.take();
966         self.generics = Some(&trait_item.generics);
967         self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
968             cx.with_param_env(trait_item.id, |cx| {
969                 run_lints!(cx, check_trait_item, trait_item);
970                 hir_visit::walk_trait_item(cx, trait_item);
971                 run_lints!(cx, check_trait_item_post, trait_item);
972             });
973         });
974         self.generics = generics;
975     }
976
977     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
978         let generics = self.generics.take();
979         self.generics = Some(&impl_item.generics);
980         self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
981             cx.with_param_env(impl_item.id, |cx| {
982                 run_lints!(cx, check_impl_item, impl_item);
983                 hir_visit::walk_impl_item(cx, impl_item);
984                 run_lints!(cx, check_impl_item_post, impl_item);
985             });
986         });
987         self.generics = generics;
988     }
989
990     fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
991         run_lints!(self, check_lifetime, lt);
992         hir_visit::walk_lifetime(self, lt);
993     }
994
995     fn visit_path(&mut self, p: &'tcx hir::Path, id: hir::HirId) {
996         run_lints!(self, check_path, p, id);
997         hir_visit::walk_path(self, p);
998     }
999
1000     fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) {
1001         run_lints!(self, check_attribute, attr);
1002     }
1003 }
1004
1005 impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> {
1006     fn visit_item(&mut self, it: &'a ast::Item) {
1007         self.with_lint_attrs(it.id, &it.attrs, |cx| {
1008             run_lints!(cx, check_item, it);
1009             ast_visit::walk_item(cx, it);
1010             run_lints!(cx, check_item_post, it);
1011         })
1012     }
1013
1014     fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) {
1015         self.with_lint_attrs(it.id, &it.attrs, |cx| {
1016             run_lints!(cx, check_foreign_item, it);
1017             ast_visit::walk_foreign_item(cx, it);
1018             run_lints!(cx, check_foreign_item_post, it);
1019         })
1020     }
1021
1022     fn visit_pat(&mut self, p: &'a ast::Pat) {
1023         let mut visit_subpats = true;
1024         run_lints!(self, check_pat, p, &mut visit_subpats);
1025         self.check_id(p.id);
1026         if visit_subpats {
1027             ast_visit::walk_pat(self, p);
1028         }
1029     }
1030
1031     fn visit_expr(&mut self, e: &'a ast::Expr) {
1032         self.with_lint_attrs(e.id, &e.attrs, |cx| {
1033             run_lints!(cx, check_expr, e);
1034             ast_visit::walk_expr(cx, e);
1035         })
1036     }
1037
1038     fn visit_stmt(&mut self, s: &'a ast::Stmt) {
1039         run_lints!(self, check_stmt, s);
1040         self.check_id(s.id);
1041         ast_visit::walk_stmt(self, s);
1042     }
1043
1044     fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, decl: &'a ast::FnDecl,
1045                 span: Span, id: ast::NodeId) {
1046         run_lints!(self, check_fn, fk, decl, span, id);
1047         self.check_id(id);
1048         ast_visit::walk_fn(self, fk, decl, span);
1049         run_lints!(self, check_fn_post, fk, decl, span, id);
1050     }
1051
1052     fn visit_variant_data(&mut self,
1053                         s: &'a ast::VariantData,
1054                         ident: ast::Ident,
1055                         g: &'a ast::Generics,
1056                         item_id: ast::NodeId,
1057                         _: Span) {
1058         run_lints!(self, check_struct_def, s, ident, g, item_id);
1059         self.check_id(s.id());
1060         ast_visit::walk_struct_def(self, s);
1061         run_lints!(self, check_struct_def_post, s, ident, g, item_id);
1062     }
1063
1064     fn visit_struct_field(&mut self, s: &'a ast::StructField) {
1065         self.with_lint_attrs(s.id, &s.attrs, |cx| {
1066             run_lints!(cx, check_struct_field, s);
1067             ast_visit::walk_struct_field(cx, s);
1068         })
1069     }
1070
1071     fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) {
1072         self.with_lint_attrs(item_id, &v.node.attrs, |cx| {
1073             run_lints!(cx, check_variant, v, g);
1074             ast_visit::walk_variant(cx, v, g, item_id);
1075             run_lints!(cx, check_variant_post, v, g);
1076         })
1077     }
1078
1079     fn visit_ty(&mut self, t: &'a ast::Ty) {
1080         run_lints!(self, check_ty, t);
1081         self.check_id(t.id);
1082         ast_visit::walk_ty(self, t);
1083     }
1084
1085     fn visit_ident(&mut self, ident: ast::Ident) {
1086         run_lints!(self, check_ident, ident);
1087     }
1088
1089     fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) {
1090         run_lints!(self, check_mod, m, s, n);
1091         self.check_id(n);
1092         ast_visit::walk_mod(self, m);
1093         run_lints!(self, check_mod_post, m, s, n);
1094     }
1095
1096     fn visit_local(&mut self, l: &'a ast::Local) {
1097         self.with_lint_attrs(l.id, &l.attrs, |cx| {
1098             run_lints!(cx, check_local, l);
1099             ast_visit::walk_local(cx, l);
1100         })
1101     }
1102
1103     fn visit_block(&mut self, b: &'a ast::Block) {
1104         run_lints!(self, check_block, b);
1105         self.check_id(b.id);
1106         ast_visit::walk_block(self, b);
1107         run_lints!(self, check_block_post, b);
1108     }
1109
1110     fn visit_arm(&mut self, a: &'a ast::Arm) {
1111         run_lints!(self, check_arm, a);
1112         ast_visit::walk_arm(self, a);
1113     }
1114
1115     fn visit_expr_post(&mut self, e: &'a ast::Expr) {
1116         run_lints!(self, check_expr_post, e);
1117     }
1118
1119     fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
1120         run_lints!(self, check_generic_param, param);
1121         ast_visit::walk_generic_param(self, param);
1122     }
1123
1124     fn visit_generics(&mut self, g: &'a ast::Generics) {
1125         run_lints!(self, check_generics, g);
1126         ast_visit::walk_generics(self, g);
1127     }
1128
1129     fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) {
1130         run_lints!(self, check_where_predicate, p);
1131         ast_visit::walk_where_predicate(self, p);
1132     }
1133
1134     fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef, m: &'a ast::TraitBoundModifier) {
1135         run_lints!(self, check_poly_trait_ref, t, m);
1136         ast_visit::walk_poly_trait_ref(self, t, m);
1137     }
1138
1139     fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) {
1140         self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| {
1141             run_lints!(cx, check_trait_item, trait_item);
1142             ast_visit::walk_trait_item(cx, trait_item);
1143             run_lints!(cx, check_trait_item_post, trait_item);
1144         });
1145     }
1146
1147     fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) {
1148         self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| {
1149             run_lints!(cx, check_impl_item, impl_item);
1150             ast_visit::walk_impl_item(cx, impl_item);
1151             run_lints!(cx, check_impl_item_post, impl_item);
1152         });
1153     }
1154
1155     fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) {
1156         run_lints!(self, check_lifetime, lt);
1157         self.check_id(lt.id);
1158     }
1159
1160     fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) {
1161         run_lints!(self, check_path, p, id);
1162         self.check_id(id);
1163         ast_visit::walk_path(self, p);
1164     }
1165
1166     fn visit_attribute(&mut self, attr: &'a ast::Attribute) {
1167         run_lints!(self, check_attribute, attr);
1168     }
1169
1170     fn visit_mac_def(&mut self, mac: &'a ast::MacroDef, id: ast::NodeId) {
1171         run_lints!(self, check_mac_def, mac, id);
1172         self.check_id(id);
1173     }
1174
1175     fn visit_mac(&mut self, mac: &'a ast::Mac) {
1176         // FIXME(#54110): So, this setup isn't really right. I think
1177         // that (a) the libsyntax visitor ought to be doing this as
1178         // part of `walk_mac`, and (b) we should be calling
1179         // `visit_path`, *but* that would require a `NodeId`, and I
1180         // want to get #53686 fixed quickly. -nmatsakis
1181         ast_visit::walk_path(self, &mac.node.path);
1182
1183         run_lints!(self, check_mac, mac);
1184     }
1185 }
1186
1187
1188 /// Perform lint checking on a crate.
1189 ///
1190 /// Consumes the `lint_store` field of the `Session`.
1191 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
1192     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
1193
1194     let krate = tcx.hir().krate();
1195     let passes = tcx.sess.lint_store.borrow_mut().late_passes.take();
1196
1197     let passes = {
1198         let mut cx = LateContext {
1199             tcx,
1200             tables: &ty::TypeckTables::empty(None),
1201             param_env: ty::ParamEnv::empty(),
1202             access_levels,
1203             lint_sess: LintSession {
1204                 passes,
1205                 lints: tcx.sess.lint_store.borrow(),
1206             },
1207             last_ast_node_with_lint_attrs: ast::CRATE_NODE_ID,
1208             generics: None,
1209         };
1210
1211         // Visit the whole crate.
1212         cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| {
1213             // since the root module isn't visited as an item (because it isn't an
1214             // item), warn for it here.
1215             run_lints!(cx, check_crate, krate);
1216
1217             hir_visit::walk_crate(cx, krate);
1218
1219             run_lints!(cx, check_crate_post, krate);
1220         });
1221         cx.lint_sess.passes
1222     };
1223
1224     // Put the lint store levels and passes back in the session.
1225     tcx.sess.lint_store.borrow_mut().late_passes = passes;
1226 }
1227
1228 pub fn check_ast_crate(
1229     sess: &Session,
1230     krate: &ast::Crate,
1231     pre_expansion: bool,
1232 ) {
1233     let (passes, buffered) = if pre_expansion {
1234         (
1235             sess.lint_store.borrow_mut().pre_expansion_passes.take(),
1236             LintBuffer::default(),
1237         )
1238     } else {
1239         (
1240             sess.lint_store.borrow_mut().early_passes.take(),
1241             sess.buffered_lints.borrow_mut().take().unwrap(),
1242         )
1243     };
1244     let (passes, buffered) = {
1245         let mut cx = EarlyContext::new(sess, krate, passes, buffered);
1246
1247         // Visit the whole crate.
1248         cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| {
1249             // since the root module isn't visited as an item (because it isn't an
1250             // item), warn for it here.
1251             run_lints!(cx, check_crate, krate);
1252
1253             ast_visit::walk_crate(cx, krate);
1254
1255             run_lints!(cx, check_crate_post, krate);
1256         });
1257         (cx.lint_sess.passes, cx.buffered)
1258     };
1259
1260     // Put the lint store levels and passes back in the session.
1261     if pre_expansion {
1262         sess.lint_store.borrow_mut().pre_expansion_passes = passes;
1263     } else {
1264         sess.lint_store.borrow_mut().early_passes = passes;
1265     }
1266
1267     // All of the buffered lints should have been emitted at this point.
1268     // If not, that means that we somehow buffered a lint for a node id
1269     // that was not lint-checked (perhaps it doesn't exist?). This is a bug.
1270     //
1271     // Rustdoc runs everybody-loops before the early lints and removes
1272     // function bodies, so it's totally possible for linted
1273     // node ids to not exist (e.g. macros defined within functions for the
1274     // unused_macro lint) anymore. So we only run this check
1275     // when we're not in rustdoc mode. (see issue #47639)
1276     if !sess.opts.actually_rustdoc {
1277         for (_id, lints) in buffered.map {
1278             for early_lint in lints {
1279                 sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
1280             }
1281         }
1282     }
1283 }
1284
1285 impl Encodable for LintId {
1286     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
1287         s.emit_str(&self.lint.name.to_lowercase())
1288     }
1289 }
1290
1291 impl Decodable for LintId {
1292     #[inline]
1293     fn decode<D: Decoder>(d: &mut D) -> Result<LintId, D::Error> {
1294         let s = d.read_str()?;
1295         ty::tls::with(|tcx| {
1296             match tcx.sess.lint_store.borrow().find_lints(&s) {
1297                 Ok(ids) => {
1298                     if ids.len() != 0 {
1299                         panic!("invalid lint-id `{}`", s);
1300                     }
1301                     Ok(ids[0])
1302                 }
1303                 Err(_) => panic!("invalid lint-id `{}`", s),
1304             }
1305         })
1306     }
1307 }