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