]> git.proxmox.com Git - rustc.git/blame - src/librustc/lint/context.rs
Imported Upstream version 1.10.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 32use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
a7813a04 33use lint::{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.
a7813a04 300 pub tcx: TyCtxt<'a, 'tcx, '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);
a7813a04
XL
459 err.warn(&explanation);
460 err.note(&citation);
92a42be0
SL
461 }
462
85aaf69f 463 if let Some(span) = def {
a7813a04
XL
464 let explanation = "lint level defined here";
465 err.span_note(span, &explanation);
1a4d82fc 466 }
9cc50fc6
SL
467
468 err
1a4d82fc
JJ
469}
470
b039eaaf
SL
471pub trait LintContext: Sized {
472 fn sess(&self) -> &Session;
473 fn lints(&self) -> &LintStore;
474 fn mut_lints(&mut self) -> &mut LintStore;
475 fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)>;
476 fn enter_attrs(&mut self, attrs: &[ast::Attribute]);
477 fn exit_attrs(&mut self, attrs: &[ast::Attribute]);
1a4d82fc
JJ
478
479 /// Get the level of `lint` at the current position of the lint
480 /// traversal.
b039eaaf
SL
481 fn current_level(&self, lint: &'static Lint) -> Level {
482 self.lints().levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
1a4d82fc
JJ
483 }
484
9cc50fc6
SL
485 fn level_src(&self, lint: &'static Lint) -> Option<LevelSource> {
486 self.lints().levels.get(&LintId::of(lint)).map(|ls| match ls {
54a0048b 487 &(Warn, _) => {
1a4d82fc 488 let lint_id = LintId::of(builtin::WARNINGS);
54a0048b
SL
489 let warn_src = self.lints().get_level_source(lint_id);
490 if warn_src.0 != Warn {
491 warn_src
492 } else {
493 *ls
494 }
1a4d82fc 495 }
9cc50fc6
SL
496 _ => *ls
497 })
498 }
499
500 fn lookup_and_emit(&self, lint: &'static Lint, span: Option<Span>, msg: &str) {
501 let (level, src) = match self.level_src(lint) {
502 None => return,
503 Some(pair) => pair,
1a4d82fc
JJ
504 };
505
92a42be0 506 raw_emit_lint(&self.sess(), self.lints(), lint, (level, src), span, msg);
1a4d82fc
JJ
507 }
508
9cc50fc6
SL
509 fn lookup(&self,
510 lint: &'static Lint,
511 span: Option<Span>,
512 msg: &str)
513 -> DiagnosticBuilder {
514 let (level, src) = match self.level_src(lint) {
515 None => return self.sess().diagnostic().struct_dummy(),
516 Some(pair) => pair,
517 };
518
519 raw_struct_lint(&self.sess(), self.lints(), lint, (level, src), span, msg)
520 }
521
1a4d82fc 522 /// Emit a lint at the appropriate level, for a particular span.
b039eaaf 523 fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) {
1a4d82fc
JJ
524 self.lookup_and_emit(lint, Some(span), msg);
525 }
526
9cc50fc6
SL
527 fn struct_span_lint(&self,
528 lint: &'static Lint,
529 span: Span,
530 msg: &str)
531 -> DiagnosticBuilder {
532 self.lookup(lint, Some(span), msg)
533 }
534
b039eaaf
SL
535 /// Emit a lint and note at the appropriate level, for a particular span.
536 fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str,
537 note_span: Span, note: &str) {
9cc50fc6 538 let mut err = self.lookup(lint, Some(span), msg);
b039eaaf
SL
539 if self.current_level(lint) != Level::Allow {
540 if note_span == span {
a7813a04 541 err.note(note);
b039eaaf 542 } else {
9cc50fc6 543 err.span_note(note_span, note);
b039eaaf
SL
544 }
545 }
9cc50fc6 546 err.emit();
b039eaaf
SL
547 }
548
549 /// Emit a lint and help at the appropriate level, for a particular span.
550 fn span_lint_help(&self, lint: &'static Lint, span: Span,
551 msg: &str, help: &str) {
9cc50fc6 552 let mut err = self.lookup(lint, Some(span), msg);
b039eaaf
SL
553 self.span_lint(lint, span, msg);
554 if self.current_level(lint) != Level::Allow {
9cc50fc6 555 err.span_help(span, help);
b039eaaf 556 }
9cc50fc6 557 err.emit();
b039eaaf
SL
558 }
559
560 /// Emit a lint at the appropriate level, with no associated span.
561 fn lint(&self, lint: &'static Lint, msg: &str) {
562 self.lookup_and_emit(lint, None, msg);
563 }
564
1a4d82fc
JJ
565 /// Merge the lints specified by any lint attributes into the
566 /// current lint context, call the provided function, then reset the
567 /// lints in effect to their previous state.
568 fn with_lint_attrs<F>(&mut self,
b039eaaf
SL
569 attrs: &[ast::Attribute],
570 f: F)
571 where F: FnOnce(&mut Self),
1a4d82fc
JJ
572 {
573 // Parse all of the lint attributes, and then add them all to the
574 // current dictionary of lint information. Along the way, keep a history
575 // of what we changed so we can roll everything back after invoking the
576 // specified closure
85aaf69f 577 let mut pushed = 0;
1a4d82fc 578
85aaf69f 579 for result in gather_attrs(attrs) {
1a4d82fc
JJ
580 let v = match result {
581 Err(span) => {
b039eaaf
SL
582 span_err!(self.sess(), span, E0452,
583 "malformed lint attribute");
1a4d82fc
JJ
584 continue;
585 }
586 Ok((lint_name, level, span)) => {
b039eaaf 587 match self.lints().find_lint(&lint_name, &self.sess(), Some(span)) {
c1a9b12d
SL
588 Ok(lint_id) => vec![(lint_id, level, span)],
589 Err(FindLintError::NotFound) => {
b039eaaf 590 match self.lints().lint_groups.get(&lint_name[..]) {
1a4d82fc
JJ
591 Some(&(ref v, _)) => v.iter()
592 .map(|lint_id: &LintId|
593 (*lint_id, level, span))
594 .collect(),
595 None => {
92a42be0
SL
596 // The lint or lint group doesn't exist.
597 // This is an error, but it was handled
598 // by check_lint_name_attribute.
1a4d82fc
JJ
599 continue;
600 }
601 }
c1a9b12d
SL
602 },
603 Err(FindLintError::Removed) => { continue; }
1a4d82fc
JJ
604 }
605 }
606 };
607
85aaf69f 608 for (lint_id, level, span) in v {
b039eaaf 609 let now = self.lints().get_level_source(lint_id).0;
1a4d82fc
JJ
610 if now == Forbid && level != Forbid {
611 let lint_name = lint_id.as_str();
b039eaaf
SL
612 span_err!(self.sess(), span, E0453,
613 "{}({}) overruled by outer forbid({})",
614 level.as_str(), lint_name,
615 lint_name);
1a4d82fc 616 } else if now != level {
b039eaaf
SL
617 let src = self.lints().get_level_source(lint_id).1;
618 self.level_stack().push((lint_id, (now, src)));
1a4d82fc 619 pushed += 1;
b039eaaf 620 self.mut_lints().set_level(lint_id, (level, Node(span)));
1a4d82fc
JJ
621 }
622 }
623 }
624
b039eaaf 625 self.enter_attrs(attrs);
1a4d82fc 626 f(self);
b039eaaf 627 self.exit_attrs(attrs);
1a4d82fc
JJ
628
629 // rollback
85aaf69f 630 for _ in 0..pushed {
b039eaaf
SL
631 let (lint, lvlsrc) = self.level_stack().pop().unwrap();
632 self.mut_lints().set_level(lint, lvlsrc);
633 }
634 }
635}
636
637
638impl<'a> EarlyContext<'a> {
639 fn new(sess: &'a Session,
640 krate: &'a ast::Crate) -> EarlyContext<'a> {
641 // We want to own the lint store, so move it out of the session. Remember
642 // to put it back later...
643 let lint_store = mem::replace(&mut *sess.lint_store.borrow_mut(),
644 LintStore::new());
645 EarlyContext {
646 sess: sess,
647 krate: krate,
648 lints: lint_store,
649 level_stack: vec![],
650 }
651 }
b039eaaf
SL
652}
653
654impl<'a, 'tcx> LateContext<'a, 'tcx> {
a7813a04 655 fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
b039eaaf 656 krate: &'a hir::Crate,
92a42be0 657 access_levels: &'a AccessLevels) -> LateContext<'a, 'tcx> {
b039eaaf
SL
658 // We want to own the lint store, so move it out of the session.
659 let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
660 LintStore::new());
661
662 LateContext {
663 tcx: tcx,
664 krate: krate,
92a42be0 665 access_levels: access_levels,
b039eaaf
SL
666 lints: lint_store,
667 level_stack: vec![],
668 node_levels: RefCell::new(FnvHashMap()),
1a4d82fc
JJ
669 }
670 }
671
b039eaaf 672 fn visit_ids<F>(&mut self, f: F)
54a0048b 673 where F: FnOnce(&mut IdVisitor<LateContext>)
1a4d82fc 674 {
54a0048b 675 let mut v = IdVisitor::new(self);
1a4d82fc
JJ
676 f(&mut v);
677 }
678}
679
b039eaaf
SL
680impl<'a, 'tcx> LintContext for LateContext<'a, 'tcx> {
681 /// Get the overall compiler `Session` object.
682 fn sess(&self) -> &Session {
683 &self.tcx.sess
684 }
685
686 fn lints(&self) -> &LintStore {
687 &self.lints
688 }
689
690 fn mut_lints(&mut self) -> &mut LintStore {
691 &mut self.lints
692 }
693
694 fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> {
695 &mut self.level_stack
696 }
697
698 fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
92a42be0 699 debug!("late context: enter_attrs({:?})", attrs);
b039eaaf
SL
700 run_lints!(self, enter_lint_attrs, late_passes, attrs);
701 }
702
703 fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
92a42be0 704 debug!("late context: exit_attrs({:?})", attrs);
b039eaaf
SL
705 run_lints!(self, exit_lint_attrs, late_passes, attrs);
706 }
707}
708
709impl<'a> LintContext for EarlyContext<'a> {
710 /// Get the overall compiler `Session` object.
711 fn sess(&self) -> &Session {
712 &self.sess
713 }
714
715 fn lints(&self) -> &LintStore {
716 &self.lints
717 }
718
719 fn mut_lints(&mut self) -> &mut LintStore {
720 &mut self.lints
721 }
722
723 fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> {
724 &mut self.level_stack
725 }
726
727 fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
7453a54e 728 debug!("early context: enter_attrs({:?})", attrs);
b039eaaf
SL
729 run_lints!(self, enter_lint_attrs, early_passes, attrs);
730 }
731
732 fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
92a42be0 733 debug!("early context: exit_attrs({:?})", attrs);
b039eaaf
SL
734 run_lints!(self, exit_lint_attrs, early_passes, attrs);
735 }
736}
737
738impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
92a42be0
SL
739 /// Because lints are scoped lexically, we want to walk nested
740 /// items in the context of the outer item, so enable
741 /// deep-walking.
742 fn visit_nested_item(&mut self, item: hir::ItemId) {
a7813a04
XL
743 let tcx = self.tcx;
744 self.visit_item(tcx.map.expect_item(item.id))
92a42be0
SL
745 }
746
e9174d1e 747 fn visit_item(&mut self, it: &hir::Item) {
c34b1796 748 self.with_lint_attrs(&it.attrs, |cx| {
b039eaaf 749 run_lints!(cx, check_item, late_passes, it);
1a4d82fc 750 cx.visit_ids(|v| v.visit_item(it));
b039eaaf 751 hir_visit::walk_item(cx, it);
7453a54e 752 run_lints!(cx, check_item_post, late_passes, it);
1a4d82fc
JJ
753 })
754 }
755
e9174d1e 756 fn visit_foreign_item(&mut self, it: &hir::ForeignItem) {
c34b1796 757 self.with_lint_attrs(&it.attrs, |cx| {
b039eaaf
SL
758 run_lints!(cx, check_foreign_item, late_passes, it);
759 hir_visit::walk_foreign_item(cx, it);
7453a54e 760 run_lints!(cx, check_foreign_item_post, late_passes, it);
1a4d82fc
JJ
761 })
762 }
763
e9174d1e 764 fn visit_pat(&mut self, p: &hir::Pat) {
b039eaaf
SL
765 run_lints!(self, check_pat, late_passes, p);
766 hir_visit::walk_pat(self, p);
1a4d82fc
JJ
767 }
768
e9174d1e 769 fn visit_expr(&mut self, e: &hir::Expr) {
92a42be0
SL
770 self.with_lint_attrs(e.attrs.as_attr_slice(), |cx| {
771 run_lints!(cx, check_expr, late_passes, e);
772 hir_visit::walk_expr(cx, e);
773 })
1a4d82fc
JJ
774 }
775
e9174d1e 776 fn visit_stmt(&mut self, s: &hir::Stmt) {
92a42be0
SL
777 // statement attributes are actually just attributes on one of
778 // - item
779 // - local
780 // - expression
781 // so we keep track of lint levels there
b039eaaf
SL
782 run_lints!(self, check_stmt, late_passes, s);
783 hir_visit::walk_stmt(self, s);
1a4d82fc
JJ
784 }
785
b039eaaf 786 fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
e9174d1e 787 body: &'v hir::Block, span: Span, id: ast::NodeId) {
b039eaaf
SL
788 run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
789 hir_visit::walk_fn(self, fk, decl, body, span);
7453a54e 790 run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
1a4d82fc
JJ
791 }
792
b039eaaf
SL
793 fn visit_variant_data(&mut self,
794 s: &hir::VariantData,
795 name: ast::Name,
e9174d1e 796 g: &hir::Generics,
b039eaaf
SL
797 item_id: ast::NodeId,
798 _: Span) {
799 run_lints!(self, check_struct_def, late_passes, s, name, g, item_id);
800 hir_visit::walk_struct_def(self, s);
801 run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id);
1a4d82fc
JJ
802 }
803
e9174d1e 804 fn visit_struct_field(&mut self, s: &hir::StructField) {
54a0048b 805 self.with_lint_attrs(&s.attrs, |cx| {
b039eaaf
SL
806 run_lints!(cx, check_struct_field, late_passes, s);
807 hir_visit::walk_struct_field(cx, s);
1a4d82fc
JJ
808 })
809 }
810
b039eaaf 811 fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
c34b1796 812 self.with_lint_attrs(&v.node.attrs, |cx| {
b039eaaf
SL
813 run_lints!(cx, check_variant, late_passes, v, g);
814 hir_visit::walk_variant(cx, v, g, item_id);
815 run_lints!(cx, check_variant_post, late_passes, v, g);
1a4d82fc
JJ
816 })
817 }
818
e9174d1e 819 fn visit_ty(&mut self, t: &hir::Ty) {
b039eaaf
SL
820 run_lints!(self, check_ty, late_passes, t);
821 hir_visit::walk_ty(self, t);
1a4d82fc
JJ
822 }
823
b039eaaf
SL
824 fn visit_name(&mut self, sp: Span, name: ast::Name) {
825 run_lints!(self, check_name, late_passes, sp, name);
1a4d82fc
JJ
826 }
827
e9174d1e 828 fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) {
b039eaaf
SL
829 run_lints!(self, check_mod, late_passes, m, s, n);
830 hir_visit::walk_mod(self, m);
7453a54e 831 run_lints!(self, check_mod_post, late_passes, m, s, n);
1a4d82fc
JJ
832 }
833
e9174d1e 834 fn visit_local(&mut self, l: &hir::Local) {
92a42be0
SL
835 self.with_lint_attrs(l.attrs.as_attr_slice(), |cx| {
836 run_lints!(cx, check_local, late_passes, l);
837 hir_visit::walk_local(cx, l);
838 })
1a4d82fc
JJ
839 }
840
e9174d1e 841 fn visit_block(&mut self, b: &hir::Block) {
b039eaaf
SL
842 run_lints!(self, check_block, late_passes, b);
843 hir_visit::walk_block(self, b);
7453a54e 844 run_lints!(self, check_block_post, late_passes, b);
1a4d82fc
JJ
845 }
846
e9174d1e 847 fn visit_arm(&mut self, a: &hir::Arm) {
b039eaaf
SL
848 run_lints!(self, check_arm, late_passes, a);
849 hir_visit::walk_arm(self, a);
1a4d82fc
JJ
850 }
851
e9174d1e 852 fn visit_decl(&mut self, d: &hir::Decl) {
b039eaaf
SL
853 run_lints!(self, check_decl, late_passes, d);
854 hir_visit::walk_decl(self, d);
1a4d82fc
JJ
855 }
856
e9174d1e 857 fn visit_expr_post(&mut self, e: &hir::Expr) {
b039eaaf 858 run_lints!(self, check_expr_post, late_passes, e);
1a4d82fc
JJ
859 }
860
e9174d1e 861 fn visit_generics(&mut self, g: &hir::Generics) {
b039eaaf
SL
862 run_lints!(self, check_generics, late_passes, g);
863 hir_visit::walk_generics(self, g);
1a4d82fc
JJ
864 }
865
e9174d1e 866 fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
c34b1796 867 self.with_lint_attrs(&trait_item.attrs, |cx| {
b039eaaf 868 run_lints!(cx, check_trait_item, late_passes, trait_item);
c34b1796 869 cx.visit_ids(|v| v.visit_trait_item(trait_item));
b039eaaf 870 hir_visit::walk_trait_item(cx, trait_item);
7453a54e 871 run_lints!(cx, check_trait_item_post, late_passes, trait_item);
c34b1796
AL
872 });
873 }
874
e9174d1e 875 fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
c34b1796 876 self.with_lint_attrs(&impl_item.attrs, |cx| {
b039eaaf 877 run_lints!(cx, check_impl_item, late_passes, impl_item);
c34b1796 878 cx.visit_ids(|v| v.visit_impl_item(impl_item));
b039eaaf 879 hir_visit::walk_impl_item(cx, impl_item);
7453a54e 880 run_lints!(cx, check_impl_item_post, late_passes, impl_item);
c34b1796 881 });
1a4d82fc
JJ
882 }
883
b039eaaf
SL
884 fn visit_lifetime(&mut self, lt: &hir::Lifetime) {
885 run_lints!(self, check_lifetime, late_passes, lt);
1a4d82fc
JJ
886 }
887
e9174d1e 888 fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) {
b039eaaf 889 run_lints!(self, check_lifetime_def, late_passes, lt);
1a4d82fc
JJ
890 }
891
e9174d1e 892 fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) {
b039eaaf
SL
893 run_lints!(self, check_path, late_passes, p, id);
894 hir_visit::walk_path(self, p);
895 }
896
897 fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
898 run_lints!(self, check_path_list_item, late_passes, item);
899 hir_visit::walk_path_list_item(self, prefix, item);
1a4d82fc
JJ
900 }
901
b039eaaf 902 fn visit_attribute(&mut self, attr: &ast::Attribute) {
92a42be0 903 check_lint_name_attribute(self, attr);
b039eaaf
SL
904 run_lints!(self, check_attribute, late_passes, attr);
905 }
906}
907
908impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
909 fn visit_item(&mut self, it: &ast::Item) {
910 self.with_lint_attrs(&it.attrs, |cx| {
911 run_lints!(cx, check_item, early_passes, it);
b039eaaf 912 ast_visit::walk_item(cx, it);
7453a54e 913 run_lints!(cx, check_item_post, early_passes, it);
b039eaaf
SL
914 })
915 }
916
917 fn visit_foreign_item(&mut self, it: &ast::ForeignItem) {
918 self.with_lint_attrs(&it.attrs, |cx| {
919 run_lints!(cx, check_foreign_item, early_passes, it);
920 ast_visit::walk_foreign_item(cx, it);
7453a54e 921 run_lints!(cx, check_foreign_item_post, early_passes, it);
b039eaaf
SL
922 })
923 }
924
925 fn visit_pat(&mut self, p: &ast::Pat) {
926 run_lints!(self, check_pat, early_passes, p);
927 ast_visit::walk_pat(self, p);
928 }
929
930 fn visit_expr(&mut self, e: &ast::Expr) {
7453a54e
SL
931 self.with_lint_attrs(e.attrs.as_attr_slice(), |cx| {
932 run_lints!(cx, check_expr, early_passes, e);
933 ast_visit::walk_expr(cx, e);
934 })
b039eaaf
SL
935 }
936
937 fn visit_stmt(&mut self, s: &ast::Stmt) {
938 run_lints!(self, check_stmt, early_passes, s);
939 ast_visit::walk_stmt(self, s);
940 }
941
942 fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, decl: &'v ast::FnDecl,
943 body: &'v ast::Block, span: Span, id: ast::NodeId) {
944 run_lints!(self, check_fn, early_passes, fk, decl, body, span, id);
945 ast_visit::walk_fn(self, fk, decl, body, span);
7453a54e 946 run_lints!(self, check_fn_post, early_passes, fk, decl, body, span, id);
b039eaaf
SL
947 }
948
949 fn visit_variant_data(&mut self,
950 s: &ast::VariantData,
951 ident: ast::Ident,
952 g: &ast::Generics,
953 item_id: ast::NodeId,
954 _: Span) {
955 run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id);
956 ast_visit::walk_struct_def(self, s);
957 run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id);
958 }
959
960 fn visit_struct_field(&mut self, s: &ast::StructField) {
54a0048b 961 self.with_lint_attrs(&s.attrs, |cx| {
b039eaaf
SL
962 run_lints!(cx, check_struct_field, early_passes, s);
963 ast_visit::walk_struct_field(cx, s);
964 })
965 }
966
967 fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics, item_id: ast::NodeId) {
968 self.with_lint_attrs(&v.node.attrs, |cx| {
969 run_lints!(cx, check_variant, early_passes, v, g);
970 ast_visit::walk_variant(cx, v, g, item_id);
971 run_lints!(cx, check_variant_post, early_passes, v, g);
972 })
973 }
974
975 fn visit_ty(&mut self, t: &ast::Ty) {
976 run_lints!(self, check_ty, early_passes, t);
977 ast_visit::walk_ty(self, t);
978 }
979
980 fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
981 run_lints!(self, check_ident, early_passes, sp, id);
982 }
983
984 fn visit_mod(&mut self, m: &ast::Mod, s: Span, n: ast::NodeId) {
985 run_lints!(self, check_mod, early_passes, m, s, n);
986 ast_visit::walk_mod(self, m);
7453a54e 987 run_lints!(self, check_mod_post, early_passes, m, s, n);
b039eaaf
SL
988 }
989
990 fn visit_local(&mut self, l: &ast::Local) {
7453a54e
SL
991 self.with_lint_attrs(l.attrs.as_attr_slice(), |cx| {
992 run_lints!(cx, check_local, early_passes, l);
993 ast_visit::walk_local(cx, l);
994 })
b039eaaf
SL
995 }
996
997 fn visit_block(&mut self, b: &ast::Block) {
998 run_lints!(self, check_block, early_passes, b);
999 ast_visit::walk_block(self, b);
7453a54e 1000 run_lints!(self, check_block_post, early_passes, b);
b039eaaf
SL
1001 }
1002
1003 fn visit_arm(&mut self, a: &ast::Arm) {
1004 run_lints!(self, check_arm, early_passes, a);
1005 ast_visit::walk_arm(self, a);
1006 }
1007
1008 fn visit_decl(&mut self, d: &ast::Decl) {
1009 run_lints!(self, check_decl, early_passes, d);
1010 ast_visit::walk_decl(self, d);
1011 }
1012
1013 fn visit_expr_post(&mut self, e: &ast::Expr) {
1014 run_lints!(self, check_expr_post, early_passes, e);
1015 }
1016
1017 fn visit_generics(&mut self, g: &ast::Generics) {
1018 run_lints!(self, check_generics, early_passes, g);
1019 ast_visit::walk_generics(self, g);
1020 }
1021
1022 fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
1023 self.with_lint_attrs(&trait_item.attrs, |cx| {
1024 run_lints!(cx, check_trait_item, early_passes, trait_item);
b039eaaf 1025 ast_visit::walk_trait_item(cx, trait_item);
7453a54e 1026 run_lints!(cx, check_trait_item_post, early_passes, trait_item);
b039eaaf
SL
1027 });
1028 }
1029
1030 fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
1031 self.with_lint_attrs(&impl_item.attrs, |cx| {
1032 run_lints!(cx, check_impl_item, early_passes, impl_item);
b039eaaf 1033 ast_visit::walk_impl_item(cx, impl_item);
7453a54e 1034 run_lints!(cx, check_impl_item_post, early_passes, impl_item);
b039eaaf
SL
1035 });
1036 }
1037
1038 fn visit_lifetime(&mut self, lt: &ast::Lifetime) {
1039 run_lints!(self, check_lifetime, early_passes, lt);
1040 }
1041
1042 fn visit_lifetime_def(&mut self, lt: &ast::LifetimeDef) {
1043 run_lints!(self, check_lifetime_def, early_passes, lt);
1044 }
1045
1046 fn visit_explicit_self(&mut self, es: &ast::ExplicitSelf) {
1047 run_lints!(self, check_explicit_self, early_passes, es);
1048 ast_visit::walk_explicit_self(self, es);
1049 }
1050
1051 fn visit_path(&mut self, p: &ast::Path, id: ast::NodeId) {
1052 run_lints!(self, check_path, early_passes, p, id);
1053 ast_visit::walk_path(self, p);
1054 }
1055
1056 fn visit_path_list_item(&mut self, prefix: &ast::Path, item: &ast::PathListItem) {
1057 run_lints!(self, check_path_list_item, early_passes, item);
1058 ast_visit::walk_path_list_item(self, prefix, item);
1059 }
1060
1061 fn visit_attribute(&mut self, attr: &ast::Attribute) {
1062 run_lints!(self, check_attribute, early_passes, attr);
1a4d82fc
JJ
1063 }
1064}
1065
1066// Output any lints that were previously added to the session.
b039eaaf
SL
1067impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> {
1068 fn visit_id(&mut self, id: ast::NodeId) {
1069 match self.sess().lints.borrow_mut().remove(&id) {
1070 None => {}
1071 Some(lints) => {
92a42be0 1072 debug!("LateContext::visit_id: id={:?} lints={:?}", id, lints);
b039eaaf
SL
1073 for (lint_id, span, msg) in lints {
1074 self.span_lint(lint_id.lint, span, &msg[..])
1075 }
1076 }
1077 }
1078 }
1079}
1a4d82fc 1080
b039eaaf 1081// This lint pass is defined here because it touches parts of the `LateContext`
1a4d82fc
JJ
1082// that we don't want to expose. It records the lint level at certain AST
1083// nodes, so that the variant size difference check in trans can call
1084// `raw_emit_lint`.
1085
c34b1796 1086pub struct GatherNodeLevels;
1a4d82fc
JJ
1087
1088impl LintPass for GatherNodeLevels {
1089 fn get_lints(&self) -> LintArray {
1090 lint_array!()
1091 }
b039eaaf 1092}
1a4d82fc 1093
b039eaaf
SL
1094impl LateLintPass for GatherNodeLevels {
1095 fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
1a4d82fc 1096 match it.node {
e9174d1e 1097 hir::ItemEnum(..) => {
1a4d82fc
JJ
1098 let lint_id = LintId::of(builtin::VARIANT_SIZE_DIFFERENCES);
1099 let lvlsrc = cx.lints.get_level_source(lint_id);
1100 match lvlsrc {
1101 (lvl, _) if lvl != Allow => {
1102 cx.node_levels.borrow_mut()
1103 .insert((it.id, lint_id), lvlsrc);
1104 },
1105 _ => { }
1106 }
1107 },
1108 _ => { }
1109 }
1110 }
1111}
1112
54a0048b 1113enum CheckLintNameResult {
92a42be0
SL
1114 Ok,
1115 // Lint doesn't exist
1116 NoLint,
54a0048b
SL
1117 // The lint is either renamed or removed. This is the warning
1118 // message.
1119 Warning(String)
92a42be0
SL
1120}
1121
1122/// Checks the name of a lint for its existence, and whether it was
1123/// renamed or removed. Generates a DiagnosticBuilder containing a
1124/// warning for renamed and removed lints. This is over both lint
1125/// names from attributes and those passed on the command line. Since
1126/// it emits non-fatal warnings and there are *two* lint passes that
1127/// inspect attributes, this is only run from the late pass to avoid
1128/// printing duplicate warnings.
54a0048b
SL
1129fn check_lint_name(lint_cx: &LintStore,
1130 lint_name: &str) -> CheckLintNameResult {
92a42be0
SL
1131 match lint_cx.by_name.get(lint_name) {
1132 Some(&Renamed(ref new_name, _)) => {
54a0048b
SL
1133 CheckLintNameResult::Warning(
1134 format!("lint {} has been renamed to {}", lint_name, new_name)
1135 )
92a42be0
SL
1136 },
1137 Some(&Removed(ref reason)) => {
54a0048b
SL
1138 CheckLintNameResult::Warning(
1139 format!("lint {} has been removed: {}", lint_name, reason)
1140 )
92a42be0
SL
1141 },
1142 None => {
1143 match lint_cx.lint_groups.get(lint_name) {
1144 None => {
1145 CheckLintNameResult::NoLint
1146 }
1147 Some(_) => {
1148 /* lint group exists */
1149 CheckLintNameResult::Ok
1150 }
1151 }
1152 }
1153 Some(_) => {
1154 /* lint exists */
1155 CheckLintNameResult::Ok
1156 }
1157 }
1158}
1159
1160// Checks the validity of lint names derived from attributes
1161fn check_lint_name_attribute(cx: &LateContext, attr: &ast::Attribute) {
1162 for result in gather_attr(attr) {
1163 match result {
1164 Err(_) => {
1165 // Malformed lint attr. Reported by with_lint_attrs
1166 continue;
1167 }
1168 Ok((lint_name, _, span)) => {
54a0048b
SL
1169 match check_lint_name(&cx.lints,
1170 &lint_name[..]) {
92a42be0 1171 CheckLintNameResult::Ok => (),
54a0048b
SL
1172 CheckLintNameResult::Warning(ref msg) => {
1173 cx.span_lint(builtin::RENAMED_AND_REMOVED_LINTS,
1174 span, msg);
9cc50fc6 1175 }
92a42be0
SL
1176 CheckLintNameResult::NoLint => {
1177 cx.span_lint(builtin::UNKNOWN_LINTS, span,
1178 &format!("unknown lint: `{}`",
1179 lint_name));
1180 }
1181 }
1182 }
1183 }
1184 }
1185}
1186
1187// Checks the validity of lint names derived from the command line
1188fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore,
1189 lint_name: &str, level: Level) {
54a0048b 1190 let db = match check_lint_name(lint_cx, lint_name) {
9cc50fc6 1191 CheckLintNameResult::Ok => None,
54a0048b
SL
1192 CheckLintNameResult::Warning(ref msg) => {
1193 Some(sess.struct_warn(msg))
1194 },
92a42be0 1195 CheckLintNameResult::NoLint => {
9cc50fc6 1196 Some(sess.struct_err(&format!("unknown lint: `{}`", lint_name)))
92a42be0
SL
1197 }
1198 };
1199
9cc50fc6 1200 if let Some(mut db) = db {
92a42be0
SL
1201 let msg = format!("requested on the command line with `{} {}`",
1202 match level {
1203 Level::Allow => "-A",
1204 Level::Warn => "-W",
1205 Level::Deny => "-D",
1206 Level::Forbid => "-F",
1207 },
1208 lint_name);
9cc50fc6
SL
1209 db.note(&msg);
1210 db.emit();
92a42be0
SL
1211 }
1212}
1213
1214
1a4d82fc
JJ
1215/// Perform lint checking on a crate.
1216///
1217/// Consumes the `lint_store` field of the `Session`.
a7813a04
XL
1218pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1219 access_levels: &AccessLevels) {
9cc50fc6
SL
1220 let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck);
1221
92a42be0
SL
1222 let krate = tcx.map.krate();
1223 let mut cx = LateContext::new(tcx, krate, access_levels);
1a4d82fc
JJ
1224
1225 // Visit the whole crate.
c34b1796 1226 cx.with_lint_attrs(&krate.attrs, |cx| {
1a4d82fc
JJ
1227 cx.visit_id(ast::CRATE_NODE_ID);
1228 cx.visit_ids(|v| {
b039eaaf 1229 hir_visit::walk_crate(v, krate);
1a4d82fc
JJ
1230 });
1231
1232 // since the root module isn't visited as an item (because it isn't an
1233 // item), warn for it here.
b039eaaf 1234 run_lints!(cx, check_crate, late_passes, krate);
1a4d82fc 1235
b039eaaf 1236 hir_visit::walk_crate(cx, krate);
7453a54e
SL
1237
1238 run_lints!(cx, check_crate_post, late_passes, krate);
1a4d82fc
JJ
1239 });
1240
1241 // If we missed any lints added to the session, then there's a bug somewhere
1242 // in the iteration code.
62682a34 1243 for (id, v) in tcx.sess.lints.borrow().iter() {
85aaf69f 1244 for &(lint, span, ref msg) in v {
54a0048b
SL
1245 span_bug!(span,
1246 "unprocessed lint {} at {}: {}",
1247 lint.as_str(), tcx.map.node_to_string(*id), *msg)
1a4d82fc
JJ
1248 }
1249 }
1250
1a4d82fc 1251 *tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
54a0048b
SL
1252
1253 // Put the lint store back in the session.
1254 mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), cx.lints);
1a4d82fc 1255}
b039eaaf
SL
1256
1257pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
1258 let mut cx = EarlyContext::new(sess, krate);
1259
1260 // Visit the whole crate.
1261 cx.with_lint_attrs(&krate.attrs, |cx| {
54a0048b
SL
1262 // Lints may be assigned to the whole crate.
1263 if let Some(lints) = cx.sess.lints.borrow_mut().remove(&ast::CRATE_NODE_ID) {
1264 for (lint_id, span, msg) in lints {
1265 cx.span_lint(lint_id.lint, span, &msg[..])
1266 }
1267 }
b039eaaf
SL
1268
1269 // since the root module isn't visited as an item (because it isn't an
1270 // item), warn for it here.
1271 run_lints!(cx, check_crate, early_passes, krate);
1272
1273 ast_visit::walk_crate(cx, krate);
7453a54e
SL
1274
1275 run_lints!(cx, check_crate_post, early_passes, krate);
b039eaaf
SL
1276 });
1277
1278 // Put the lint store back in the session.
1279 mem::replace(&mut *sess.lint_store.borrow_mut(), cx.lints);
1280
1281 // If we missed any lints added to the session, then there's a bug somewhere
1282 // in the iteration code.
1283 for (_, v) in sess.lints.borrow().iter() {
1284 for &(lint, span, ref msg) in v {
54a0048b 1285 span_bug!(span, "unprocessed lint {}: {}", lint.as_str(), *msg)
b039eaaf
SL
1286 }
1287 }
1288}