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