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