]>
Commit | Line | Data |
---|---|---|
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. | |
3b2f2976 | 26 | |
1a4d82fc JJ |
27 | use self::TargetLint::*; |
28 | ||
3b2f2976 XL |
29 | use rustc_back::slice; |
30 | use lint::{EarlyLintPassObject, LateLintPassObject}; | |
31 | use lint::{Level, Lint, LintId, LintPass, LintBuffer}; | |
32 | use lint::levels::{LintLevelSets, LintLevelsBuilder}; | |
92a42be0 | 33 | use middle::privacy::AccessLevels; |
3b2f2976 XL |
34 | use rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; |
35 | use session::{config, early_error, Session}; | |
041b39d2 | 36 | use traits::Reveal; |
32a655c1 | 37 | use ty::{self, TyCtxt}; |
476ff2be | 38 | use util::nodemap::FxHashMap; |
1a4d82fc | 39 | |
9cc50fc6 | 40 | use std::default::Default as StdDefault; |
7cac9316 | 41 | use std::cell::{Ref, RefCell}; |
e9174d1e | 42 | use syntax::ast; |
7cac9316 | 43 | use syntax_pos::{MultiSpan, Span}; |
3b2f2976 | 44 | use errors::DiagnosticBuilder; |
54a0048b | 45 | use hir; |
cc61c64b | 46 | use hir::def_id::LOCAL_CRATE; |
54a0048b | 47 | use hir::intravisit as hir_visit; |
b039eaaf | 48 | use syntax::visit as ast_visit; |
1a4d82fc JJ |
49 | |
50 | /// Information about the registered lints. | |
51 | /// | |
52 | /// This is basically the subset of `Context` that we can | |
53 | /// build early in the compile pipeline. | |
54 | pub struct LintStore { | |
55 | /// Registered lints. The bool is true if the lint was | |
56 | /// added by a plugin. | |
57 | lints: Vec<(&'static Lint, bool)>, | |
58 | ||
59 | /// Trait objects for each lint pass. | |
7cac9316 XL |
60 | /// This is only `None` while performing a lint pass. See the definition |
61 | /// of `LintSession::new`. | |
b039eaaf SL |
62 | early_passes: Option<Vec<EarlyLintPassObject>>, |
63 | late_passes: Option<Vec<LateLintPassObject>>, | |
1a4d82fc JJ |
64 | |
65 | /// Lints indexed by name. | |
476ff2be | 66 | by_name: FxHashMap<String, TargetLint>, |
1a4d82fc | 67 | |
1a4d82fc JJ |
68 | /// Map of registered lint groups to what lints they expand to. The bool |
69 | /// is true if the lint group was added by a plugin. | |
476ff2be | 70 | lint_groups: FxHashMap<&'static str, (Vec<LintId>, bool)>, |
c1a9b12d | 71 | |
3b2f2976 | 72 | /// Extra info for future incompatibility lints, describing the |
9cc50fc6 | 73 | /// issue or RFC that caused the incompatibility. |
476ff2be | 74 | future_incompatible: FxHashMap<LintId, FutureIncompatibleInfo>, |
7cac9316 XL |
75 | } |
76 | ||
7cac9316 XL |
77 | pub struct LintSession<'a, PassObject> { |
78 | /// Reference to the store of registered lints. | |
79 | lints: Ref<'a, LintStore>, | |
80 | ||
7cac9316 XL |
81 | /// Trait objects for each lint pass. |
82 | passes: Option<Vec<PassObject>>, | |
83 | } | |
84 | ||
85 | ||
3b2f2976 XL |
86 | /// Lints that are buffered up early on in the `Session` before the |
87 | /// `LintLevels` is calculated | |
88 | #[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)] | |
89 | pub struct BufferedEarlyLint { | |
90 | pub lint_id: LintId, | |
91 | pub ast_id: ast::NodeId, | |
92 | pub span: MultiSpan, | |
93 | pub msg: String, | |
c30ab7b3 SL |
94 | } |
95 | ||
9cc50fc6 SL |
96 | /// Extra information for a future incompatibility lint. See the call |
97 | /// to `register_future_incompatible` in `librustc_lint/lib.rs` for | |
98 | /// guidelines. | |
99 | pub struct FutureIncompatibleInfo { | |
100 | pub id: LintId, | |
101 | pub reference: &'static str // e.g., a URL for an issue/PR/RFC or error code | |
102 | } | |
103 | ||
3b2f2976 | 104 | /// The target of the `by_name` map, which accounts for renaming/deprecation. |
1a4d82fc JJ |
105 | enum TargetLint { |
106 | /// A direct lint target | |
107 | Id(LintId), | |
108 | ||
109 | /// Temporary renaming, used for easing migration pain; see #16545 | |
110 | Renamed(String, LintId), | |
c1a9b12d SL |
111 | |
112 | /// Lint with this name existed previously, but has been removed/deprecated. | |
113 | /// The string argument is the reason for removal. | |
114 | Removed(String), | |
115 | } | |
116 | ||
3b2f2976 | 117 | pub enum FindLintError { |
c1a9b12d | 118 | NotFound, |
cc61c64b | 119 | Removed, |
1a4d82fc JJ |
120 | } |
121 | ||
3b2f2976 XL |
122 | pub enum CheckLintNameResult<'a> { |
123 | Ok(&'a [LintId]), | |
124 | /// Lint doesn't exist | |
125 | NoLint, | |
126 | /// The lint is either renamed or removed. This is the warning | |
127 | /// message. | |
128 | Warning(String), | |
129 | } | |
130 | ||
1a4d82fc | 131 | impl LintStore { |
1a4d82fc JJ |
132 | pub fn new() -> LintStore { |
133 | LintStore { | |
c30ab7b3 SL |
134 | lints: vec![], |
135 | early_passes: Some(vec![]), | |
136 | late_passes: Some(vec![]), | |
476ff2be | 137 | by_name: FxHashMap(), |
476ff2be SL |
138 | future_incompatible: FxHashMap(), |
139 | lint_groups: FxHashMap(), | |
1a4d82fc JJ |
140 | } |
141 | } | |
142 | ||
143 | pub fn get_lints<'t>(&'t self) -> &'t [(&'static Lint, bool)] { | |
c34b1796 | 144 | &self.lints |
1a4d82fc JJ |
145 | } |
146 | ||
147 | pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> { | |
148 | self.lint_groups.iter().map(|(k, v)| (*k, | |
149 | v.0.clone(), | |
150 | v.1)).collect() | |
151 | } | |
152 | ||
b039eaaf SL |
153 | pub fn register_early_pass(&mut self, |
154 | sess: Option<&Session>, | |
155 | from_plugin: bool, | |
156 | pass: EarlyLintPassObject) { | |
157 | self.push_pass(sess, from_plugin, &pass); | |
158 | self.early_passes.as_mut().unwrap().push(pass); | |
159 | } | |
160 | ||
161 | pub fn register_late_pass(&mut self, | |
162 | sess: Option<&Session>, | |
163 | from_plugin: bool, | |
164 | pass: LateLintPassObject) { | |
165 | self.push_pass(sess, from_plugin, &pass); | |
166 | self.late_passes.as_mut().unwrap().push(pass); | |
167 | } | |
168 | ||
169 | // Helper method for register_early/late_pass | |
170 | fn push_pass<P: LintPass + ?Sized + 'static>(&mut self, | |
171 | sess: Option<&Session>, | |
172 | from_plugin: bool, | |
173 | pass: &Box<P>) { | |
85aaf69f | 174 | for &lint in pass.get_lints() { |
1a4d82fc JJ |
175 | self.lints.push((*lint, from_plugin)); |
176 | ||
177 | let id = LintId::of(*lint); | |
178 | if self.by_name.insert(lint.name_lower(), Id(id)).is_some() { | |
179 | let msg = format!("duplicate specification of lint {}", lint.name_lower()); | |
180 | match (sess, from_plugin) { | |
181 | // We load builtin lints first, so a duplicate is a compiler bug. | |
182 | // Use early_error when handling -W help with no crate. | |
9cc50fc6 | 183 | (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]), |
54a0048b | 184 | (Some(_), false) => bug!("{}", msg), |
1a4d82fc JJ |
185 | |
186 | // A duplicate name from a plugin is a user error. | |
85aaf69f | 187 | (Some(sess), true) => sess.err(&msg[..]), |
1a4d82fc JJ |
188 | } |
189 | } | |
1a4d82fc | 190 | } |
1a4d82fc JJ |
191 | } |
192 | ||
9cc50fc6 SL |
193 | pub fn register_future_incompatible(&mut self, |
194 | sess: Option<&Session>, | |
195 | lints: Vec<FutureIncompatibleInfo>) { | |
196 | let ids = lints.iter().map(|f| f.id).collect(); | |
197 | self.register_group(sess, false, "future_incompatible", ids); | |
198 | for info in lints { | |
199 | self.future_incompatible.insert(info.id, info); | |
200 | } | |
201 | } | |
202 | ||
203 | pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> { | |
204 | self.future_incompatible.get(&id) | |
205 | } | |
206 | ||
1a4d82fc JJ |
207 | pub fn register_group(&mut self, sess: Option<&Session>, |
208 | from_plugin: bool, name: &'static str, | |
209 | to: Vec<LintId>) { | |
210 | let new = self.lint_groups.insert(name, (to, from_plugin)).is_none(); | |
211 | ||
212 | if !new { | |
213 | let msg = format!("duplicate specification of lint group {}", name); | |
214 | match (sess, from_plugin) { | |
215 | // We load builtin lints first, so a duplicate is a compiler bug. | |
216 | // Use early_error when handling -W help with no crate. | |
9cc50fc6 | 217 | (None, _) => early_error(config::ErrorOutputType::default(), &msg[..]), |
54a0048b | 218 | (Some(_), false) => bug!("{}", msg), |
1a4d82fc JJ |
219 | |
220 | // A duplicate name from a plugin is a user error. | |
85aaf69f | 221 | (Some(sess), true) => sess.err(&msg[..]), |
1a4d82fc JJ |
222 | } |
223 | } | |
224 | } | |
225 | ||
c34b1796 | 226 | pub fn register_renamed(&mut self, old_name: &str, new_name: &str) { |
1a4d82fc JJ |
227 | let target = match self.by_name.get(new_name) { |
228 | Some(&Id(lint_id)) => lint_id.clone(), | |
54a0048b | 229 | _ => bug!("invalid lint renaming of {} to {}", old_name, new_name) |
1a4d82fc JJ |
230 | }; |
231 | self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target)); | |
232 | } | |
233 | ||
c1a9b12d SL |
234 | pub fn register_removed(&mut self, name: &str, reason: &str) { |
235 | self.by_name.insert(name.into(), Removed(reason.into())); | |
236 | } | |
237 | ||
3b2f2976 | 238 | pub fn find_lints(&self, lint_name: &str) -> Result<Vec<LintId>, FindLintError> { |
1a4d82fc | 239 | match self.by_name.get(lint_name) { |
3b2f2976 | 240 | Some(&Id(lint_id)) => Ok(vec![lint_id]), |
92a42be0 | 241 | Some(&Renamed(_, lint_id)) => { |
3b2f2976 | 242 | Ok(vec![lint_id]) |
c1a9b12d | 243 | }, |
041b39d2 | 244 | Some(&Removed(_)) => { |
c1a9b12d SL |
245 | Err(FindLintError::Removed) |
246 | }, | |
3b2f2976 XL |
247 | None => { |
248 | match self.lint_groups.get(lint_name) { | |
249 | Some(v) => Ok(v.0.clone()), | |
250 | None => Err(FindLintError::Removed) | |
1a4d82fc JJ |
251 | } |
252 | } | |
253 | } | |
7cac9316 | 254 | } |
7cac9316 | 255 | |
3b2f2976 XL |
256 | /// Checks the validity of lint names derived from the command line |
257 | pub fn check_lint_name_cmdline(&self, | |
258 | sess: &Session, | |
259 | lint_name: &str, | |
260 | level: Level) { | |
261 | let db = match self.check_lint_name(lint_name) { | |
262 | CheckLintNameResult::Ok(_) => None, | |
263 | CheckLintNameResult::Warning(ref msg) => { | |
264 | Some(sess.struct_warn(msg)) | |
265 | }, | |
266 | CheckLintNameResult::NoLint => { | |
267 | Some(struct_err!(sess, E0602, "unknown lint: `{}`", lint_name)) | |
268 | } | |
269 | }; | |
7cac9316 | 270 | |
3b2f2976 XL |
271 | if let Some(mut db) = db { |
272 | let msg = format!("requested on the command line with `{} {}`", | |
273 | match level { | |
274 | Level::Allow => "-A", | |
275 | Level::Warn => "-W", | |
276 | Level::Deny => "-D", | |
277 | Level::Forbid => "-F", | |
278 | }, | |
279 | lint_name); | |
280 | db.note(&msg); | |
281 | db.emit(); | |
7cac9316 XL |
282 | } |
283 | } | |
284 | ||
3b2f2976 XL |
285 | /// Checks the name of a lint for its existence, and whether it was |
286 | /// renamed or removed. Generates a DiagnosticBuilder containing a | |
287 | /// warning for renamed and removed lints. This is over both lint | |
288 | /// names from attributes and those passed on the command line. Since | |
289 | /// it emits non-fatal warnings and there are *two* lint passes that | |
290 | /// inspect attributes, this is only run from the late pass to avoid | |
291 | /// printing duplicate warnings. | |
292 | pub fn check_lint_name(&self, lint_name: &str) -> CheckLintNameResult { | |
293 | match self.by_name.get(lint_name) { | |
294 | Some(&Renamed(ref new_name, _)) => { | |
295 | CheckLintNameResult::Warning( | |
296 | format!("lint {} has been renamed to {}", lint_name, new_name) | |
297 | ) | |
298 | }, | |
299 | Some(&Removed(ref reason)) => { | |
300 | CheckLintNameResult::Warning( | |
301 | format!("lint {} has been removed: {}", lint_name, reason) | |
302 | ) | |
303 | }, | |
304 | None => { | |
305 | match self.lint_groups.get(lint_name) { | |
306 | None => CheckLintNameResult::NoLint, | |
307 | Some(ids) => CheckLintNameResult::Ok(&ids.0), | |
308 | } | |
c1a9b12d | 309 | } |
3b2f2976 | 310 | Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::ref_slice(id)), |
c1a9b12d | 311 | } |
1a4d82fc | 312 | } |
1a4d82fc JJ |
313 | } |
314 | ||
7cac9316 XL |
315 | impl<'a, PassObject: LintPassObject> LintSession<'a, PassObject> { |
316 | /// Creates a new `LintSession`, by moving out the `LintStore`'s initial | |
317 | /// lint levels and pass objects. These can be restored using the `restore` | |
318 | /// method. | |
319 | fn new(store: &'a RefCell<LintStore>) -> LintSession<'a, PassObject> { | |
320 | let mut s = store.borrow_mut(); | |
7cac9316 XL |
321 | let passes = PassObject::take_passes(&mut *s); |
322 | drop(s); | |
323 | LintSession { | |
324 | lints: store.borrow(), | |
7cac9316 XL |
325 | passes, |
326 | } | |
327 | } | |
328 | ||
329 | /// Restores the levels back to the original lint store. | |
330 | fn restore(self, store: &RefCell<LintStore>) { | |
331 | drop(self.lints); | |
332 | let mut s = store.borrow_mut(); | |
7cac9316 XL |
333 | PassObject::restore_passes(&mut *s, self.passes); |
334 | } | |
7cac9316 XL |
335 | } |
336 | ||
b039eaaf SL |
337 | /// Context for lint checking after type checking. |
338 | pub struct LateContext<'a, 'tcx: 'a> { | |
1a4d82fc | 339 | /// Type context we're checking in. |
a7813a04 | 340 | pub tcx: TyCtxt<'a, 'tcx, 'tcx>, |
1a4d82fc | 341 | |
32a655c1 SL |
342 | /// Side-tables for the body we are in. |
343 | pub tables: &'a ty::TypeckTables<'tcx>, | |
344 | ||
041b39d2 XL |
345 | /// Parameter environment for the item we are in. |
346 | pub param_env: ty::ParamEnv<'tcx>, | |
1a4d82fc | 347 | |
92a42be0 SL |
348 | /// Items accessible from the crate being checked. |
349 | pub access_levels: &'a AccessLevels, | |
1a4d82fc | 350 | |
7cac9316 XL |
351 | /// The store of registered lints and the lint levels. |
352 | lint_sess: LintSession<'tcx, LateLintPassObject>, | |
3b2f2976 XL |
353 | |
354 | last_ast_node_with_lint_attrs: ast::NodeId, | |
abe05a73 XL |
355 | |
356 | /// Generic type parameters in scope for the item we are in. | |
357 | pub generics: Option<&'tcx hir::Generics>, | |
1a4d82fc JJ |
358 | } |
359 | ||
b039eaaf SL |
360 | /// Context for lint checking of the AST, after expansion, before lowering to |
361 | /// HIR. | |
362 | pub struct EarlyContext<'a> { | |
363 | /// Type context we're checking in. | |
364 | pub sess: &'a Session, | |
365 | ||
366 | /// The crate being checked. | |
367 | pub krate: &'a ast::Crate, | |
368 | ||
3b2f2976 XL |
369 | builder: LintLevelsBuilder<'a>, |
370 | ||
7cac9316 XL |
371 | /// The store of registered lints and the lint levels. |
372 | lint_sess: LintSession<'a, EarlyLintPassObject>, | |
3b2f2976 XL |
373 | |
374 | buffered: LintBuffer, | |
b039eaaf SL |
375 | } |
376 | ||
1a4d82fc | 377 | /// Convenience macro for calling a `LintPass` method on every pass in the context. |
b039eaaf | 378 | macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({ |
1a4d82fc JJ |
379 | // Move the vector of passes out of `$cx` so that we can |
380 | // iterate over it mutably while passing `$cx` to the methods. | |
7cac9316 | 381 | let mut passes = $cx.lint_sess_mut().passes.take().unwrap(); |
85aaf69f | 382 | for obj in &mut passes { |
1a4d82fc JJ |
383 | obj.$f($cx, $($args),*); |
384 | } | |
7cac9316 | 385 | $cx.lint_sess_mut().passes = Some(passes); |
1a4d82fc JJ |
386 | }) } |
387 | ||
7cac9316 XL |
388 | pub trait LintPassObject: Sized { |
389 | fn take_passes(store: &mut LintStore) -> Option<Vec<Self>>; | |
390 | fn restore_passes(store: &mut LintStore, passes: Option<Vec<Self>>); | |
391 | } | |
392 | ||
393 | impl LintPassObject for EarlyLintPassObject { | |
394 | fn take_passes(store: &mut LintStore) -> Option<Vec<Self>> { | |
395 | store.early_passes.take() | |
396 | } | |
397 | ||
398 | fn restore_passes(store: &mut LintStore, passes: Option<Vec<Self>>) { | |
399 | store.early_passes = passes; | |
400 | } | |
401 | } | |
402 | ||
403 | impl LintPassObject for LateLintPassObject { | |
404 | fn take_passes(store: &mut LintStore) -> Option<Vec<Self>> { | |
405 | store.late_passes.take() | |
406 | } | |
407 | ||
408 | fn restore_passes(store: &mut LintStore, passes: Option<Vec<Self>>) { | |
409 | store.late_passes = passes; | |
410 | } | |
411 | } | |
412 | ||
413 | ||
476ff2be | 414 | pub trait LintContext<'tcx>: Sized { |
7cac9316 XL |
415 | type PassObject: LintPassObject; |
416 | ||
b039eaaf SL |
417 | fn sess(&self) -> &Session; |
418 | fn lints(&self) -> &LintStore; | |
7cac9316 XL |
419 | fn lint_sess(&self) -> &LintSession<'tcx, Self::PassObject>; |
420 | fn lint_sess_mut(&mut self) -> &mut LintSession<'tcx, Self::PassObject>; | |
476ff2be SL |
421 | fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]); |
422 | fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]); | |
1a4d82fc | 423 | |
476ff2be SL |
424 | fn lookup_and_emit<S: Into<MultiSpan>>(&self, |
425 | lint: &'static Lint, | |
426 | span: Option<S>, | |
427 | msg: &str) { | |
3b2f2976 | 428 | self.lookup(lint, span, msg).emit(); |
1a4d82fc JJ |
429 | } |
430 | ||
c30ab7b3 SL |
431 | fn lookup<S: Into<MultiSpan>>(&self, |
432 | lint: &'static Lint, | |
433 | span: Option<S>, | |
434 | msg: &str) | |
3b2f2976 | 435 | -> DiagnosticBuilder; |
9cc50fc6 | 436 | |
1a4d82fc | 437 | /// Emit a lint at the appropriate level, for a particular span. |
476ff2be | 438 | fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) { |
1a4d82fc JJ |
439 | self.lookup_and_emit(lint, Some(span), msg); |
440 | } | |
441 | ||
c30ab7b3 SL |
442 | fn struct_span_lint<S: Into<MultiSpan>>(&self, |
443 | lint: &'static Lint, | |
444 | span: S, | |
445 | msg: &str) | |
446 | -> DiagnosticBuilder { | |
9cc50fc6 SL |
447 | self.lookup(lint, Some(span), msg) |
448 | } | |
449 | ||
b039eaaf SL |
450 | /// Emit a lint and note at the appropriate level, for a particular span. |
451 | fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str, | |
452 | note_span: Span, note: &str) { | |
9cc50fc6 | 453 | let mut err = self.lookup(lint, Some(span), msg); |
3b2f2976 XL |
454 | if note_span == span { |
455 | err.note(note); | |
456 | } else { | |
457 | err.span_note(note_span, note); | |
b039eaaf | 458 | } |
9cc50fc6 | 459 | err.emit(); |
b039eaaf SL |
460 | } |
461 | ||
462 | /// Emit a lint and help at the appropriate level, for a particular span. | |
463 | fn span_lint_help(&self, lint: &'static Lint, span: Span, | |
464 | msg: &str, help: &str) { | |
9cc50fc6 | 465 | let mut err = self.lookup(lint, Some(span), msg); |
b039eaaf | 466 | self.span_lint(lint, span, msg); |
3b2f2976 | 467 | err.span_help(span, help); |
9cc50fc6 | 468 | err.emit(); |
b039eaaf SL |
469 | } |
470 | ||
471 | /// Emit a lint at the appropriate level, with no associated span. | |
472 | fn lint(&self, lint: &'static Lint, msg: &str) { | |
476ff2be | 473 | self.lookup_and_emit(lint, None as Option<Span>, msg); |
b039eaaf SL |
474 | } |
475 | ||
1a4d82fc JJ |
476 | /// Merge the lints specified by any lint attributes into the |
477 | /// current lint context, call the provided function, then reset the | |
478 | /// lints in effect to their previous state. | |
479 | fn with_lint_attrs<F>(&mut self, | |
3b2f2976 | 480 | id: ast::NodeId, |
476ff2be | 481 | attrs: &'tcx [ast::Attribute], |
b039eaaf | 482 | f: F) |
3b2f2976 | 483 | where F: FnOnce(&mut Self); |
b039eaaf SL |
484 | } |
485 | ||
486 | ||
487 | impl<'a> EarlyContext<'a> { | |
488 | fn new(sess: &'a Session, | |
489 | krate: &'a ast::Crate) -> EarlyContext<'a> { | |
b039eaaf | 490 | EarlyContext { |
041b39d2 XL |
491 | sess, |
492 | krate, | |
7cac9316 | 493 | lint_sess: LintSession::new(&sess.lint_store), |
3b2f2976 XL |
494 | builder: LintLevelSets::builder(sess), |
495 | buffered: sess.buffered_lints.borrow_mut().take().unwrap(), | |
496 | } | |
497 | } | |
498 | ||
499 | fn check_id(&mut self, id: ast::NodeId) { | |
500 | for early_lint in self.buffered.take(id) { | |
501 | self.lookup_and_emit(early_lint.lint_id.lint, | |
502 | Some(early_lint.span.clone()), | |
503 | &early_lint.msg); | |
b039eaaf SL |
504 | } |
505 | } | |
b039eaaf SL |
506 | } |
507 | ||
476ff2be | 508 | impl<'a, 'tcx> LintContext<'tcx> for LateContext<'a, 'tcx> { |
7cac9316 XL |
509 | type PassObject = LateLintPassObject; |
510 | ||
b039eaaf SL |
511 | /// Get the overall compiler `Session` object. |
512 | fn sess(&self) -> &Session { | |
513 | &self.tcx.sess | |
514 | } | |
515 | ||
516 | fn lints(&self) -> &LintStore { | |
7cac9316 | 517 | &*self.lint_sess.lints |
b039eaaf SL |
518 | } |
519 | ||
7cac9316 XL |
520 | fn lint_sess(&self) -> &LintSession<'tcx, Self::PassObject> { |
521 | &self.lint_sess | |
b039eaaf SL |
522 | } |
523 | ||
7cac9316 XL |
524 | fn lint_sess_mut(&mut self) -> &mut LintSession<'tcx, Self::PassObject> { |
525 | &mut self.lint_sess | |
b039eaaf SL |
526 | } |
527 | ||
476ff2be | 528 | fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) { |
92a42be0 | 529 | debug!("late context: enter_attrs({:?})", attrs); |
b039eaaf SL |
530 | run_lints!(self, enter_lint_attrs, late_passes, attrs); |
531 | } | |
532 | ||
476ff2be | 533 | fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) { |
92a42be0 | 534 | debug!("late context: exit_attrs({:?})", attrs); |
b039eaaf SL |
535 | run_lints!(self, exit_lint_attrs, late_passes, attrs); |
536 | } | |
3b2f2976 XL |
537 | |
538 | fn lookup<S: Into<MultiSpan>>(&self, | |
539 | lint: &'static Lint, | |
540 | span: Option<S>, | |
541 | msg: &str) | |
542 | -> DiagnosticBuilder { | |
543 | let id = self.last_ast_node_with_lint_attrs; | |
544 | match span { | |
545 | Some(s) => self.tcx.struct_span_lint_node(lint, id, s, msg), | |
546 | None => self.tcx.struct_lint_node(lint, id, msg), | |
547 | } | |
548 | } | |
549 | ||
550 | fn with_lint_attrs<F>(&mut self, | |
551 | id: ast::NodeId, | |
552 | attrs: &'tcx [ast::Attribute], | |
553 | f: F) | |
554 | where F: FnOnce(&mut Self) | |
555 | { | |
556 | let prev = self.last_ast_node_with_lint_attrs; | |
557 | self.last_ast_node_with_lint_attrs = id; | |
558 | self.enter_attrs(attrs); | |
559 | f(self); | |
560 | self.exit_attrs(attrs); | |
561 | self.last_ast_node_with_lint_attrs = prev; | |
562 | } | |
b039eaaf SL |
563 | } |
564 | ||
476ff2be | 565 | impl<'a> LintContext<'a> for EarlyContext<'a> { |
7cac9316 XL |
566 | type PassObject = EarlyLintPassObject; |
567 | ||
b039eaaf SL |
568 | /// Get the overall compiler `Session` object. |
569 | fn sess(&self) -> &Session { | |
570 | &self.sess | |
571 | } | |
572 | ||
573 | fn lints(&self) -> &LintStore { | |
7cac9316 | 574 | &*self.lint_sess.lints |
b039eaaf SL |
575 | } |
576 | ||
7cac9316 XL |
577 | fn lint_sess(&self) -> &LintSession<'a, Self::PassObject> { |
578 | &self.lint_sess | |
b039eaaf SL |
579 | } |
580 | ||
7cac9316 XL |
581 | fn lint_sess_mut(&mut self) -> &mut LintSession<'a, Self::PassObject> { |
582 | &mut self.lint_sess | |
b039eaaf SL |
583 | } |
584 | ||
476ff2be | 585 | fn enter_attrs(&mut self, attrs: &'a [ast::Attribute]) { |
7453a54e | 586 | debug!("early context: enter_attrs({:?})", attrs); |
b039eaaf SL |
587 | run_lints!(self, enter_lint_attrs, early_passes, attrs); |
588 | } | |
589 | ||
476ff2be | 590 | fn exit_attrs(&mut self, attrs: &'a [ast::Attribute]) { |
92a42be0 | 591 | debug!("early context: exit_attrs({:?})", attrs); |
b039eaaf SL |
592 | run_lints!(self, exit_lint_attrs, early_passes, attrs); |
593 | } | |
3b2f2976 XL |
594 | |
595 | fn lookup<S: Into<MultiSpan>>(&self, | |
596 | lint: &'static Lint, | |
597 | span: Option<S>, | |
598 | msg: &str) | |
599 | -> DiagnosticBuilder { | |
600 | self.builder.struct_lint(lint, span.map(|s| s.into()), msg) | |
601 | } | |
602 | ||
603 | fn with_lint_attrs<F>(&mut self, | |
604 | id: ast::NodeId, | |
605 | attrs: &'a [ast::Attribute], | |
606 | f: F) | |
607 | where F: FnOnce(&mut Self) | |
608 | { | |
609 | let push = self.builder.push(attrs); | |
610 | self.check_id(id); | |
611 | self.enter_attrs(attrs); | |
612 | f(self); | |
613 | self.exit_attrs(attrs); | |
614 | self.builder.pop(push); | |
615 | } | |
b039eaaf SL |
616 | } |
617 | ||
041b39d2 XL |
618 | impl<'a, 'tcx> LateContext<'a, 'tcx> { |
619 | fn with_param_env<F>(&mut self, id: ast::NodeId, f: F) | |
620 | where F: FnOnce(&mut Self), | |
621 | { | |
622 | let old_param_env = self.param_env; | |
623 | self.param_env = self.tcx.param_env(self.tcx.hir.local_def_id(id)); | |
624 | f(self); | |
625 | self.param_env = old_param_env; | |
626 | } | |
627 | } | |
628 | ||
476ff2be | 629 | impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { |
92a42be0 SL |
630 | /// Because lints are scoped lexically, we want to walk nested |
631 | /// items in the context of the outer item, so enable | |
632 | /// deep-walking. | |
476ff2be | 633 | fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> { |
32a655c1 SL |
634 | hir_visit::NestedVisitorMap::All(&self.tcx.hir) |
635 | } | |
636 | ||
32a655c1 SL |
637 | fn visit_nested_body(&mut self, body: hir::BodyId) { |
638 | let old_tables = self.tables; | |
639 | self.tables = self.tcx.body_tables(body); | |
640 | let body = self.tcx.hir.body(body); | |
641 | self.visit_body(body); | |
642 | self.tables = old_tables; | |
92a42be0 SL |
643 | } |
644 | ||
8bb4bdeb XL |
645 | fn visit_body(&mut self, body: &'tcx hir::Body) { |
646 | run_lints!(self, check_body, late_passes, body); | |
647 | hir_visit::walk_body(self, body); | |
648 | run_lints!(self, check_body_post, late_passes, body); | |
649 | } | |
650 | ||
476ff2be | 651 | fn visit_item(&mut self, it: &'tcx hir::Item) { |
abe05a73 XL |
652 | let generics = self.generics.take(); |
653 | self.generics = it.node.generics(); | |
3b2f2976 | 654 | self.with_lint_attrs(it.id, &it.attrs, |cx| { |
041b39d2 XL |
655 | cx.with_param_env(it.id, |cx| { |
656 | run_lints!(cx, check_item, late_passes, it); | |
657 | hir_visit::walk_item(cx, it); | |
658 | run_lints!(cx, check_item_post, late_passes, it); | |
659 | }); | |
abe05a73 XL |
660 | }); |
661 | self.generics = generics; | |
1a4d82fc JJ |
662 | } |
663 | ||
476ff2be | 664 | fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) { |
3b2f2976 | 665 | self.with_lint_attrs(it.id, &it.attrs, |cx| { |
041b39d2 XL |
666 | cx.with_param_env(it.id, |cx| { |
667 | run_lints!(cx, check_foreign_item, late_passes, it); | |
668 | hir_visit::walk_foreign_item(cx, it); | |
669 | run_lints!(cx, check_foreign_item_post, late_passes, it); | |
670 | }); | |
1a4d82fc JJ |
671 | }) |
672 | } | |
673 | ||
476ff2be | 674 | fn visit_pat(&mut self, p: &'tcx hir::Pat) { |
b039eaaf SL |
675 | run_lints!(self, check_pat, late_passes, p); |
676 | hir_visit::walk_pat(self, p); | |
1a4d82fc JJ |
677 | } |
678 | ||
476ff2be | 679 | fn visit_expr(&mut self, e: &'tcx hir::Expr) { |
3b2f2976 | 680 | self.with_lint_attrs(e.id, &e.attrs, |cx| { |
92a42be0 SL |
681 | run_lints!(cx, check_expr, late_passes, e); |
682 | hir_visit::walk_expr(cx, e); | |
32a655c1 | 683 | run_lints!(cx, check_expr_post, late_passes, e); |
92a42be0 | 684 | }) |
1a4d82fc JJ |
685 | } |
686 | ||
476ff2be | 687 | fn visit_stmt(&mut self, s: &'tcx hir::Stmt) { |
92a42be0 SL |
688 | // statement attributes are actually just attributes on one of |
689 | // - item | |
690 | // - local | |
691 | // - expression | |
692 | // so we keep track of lint levels there | |
b039eaaf SL |
693 | run_lints!(self, check_stmt, late_passes, s); |
694 | hir_visit::walk_stmt(self, s); | |
1a4d82fc JJ |
695 | } |
696 | ||
476ff2be | 697 | fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl, |
32a655c1 SL |
698 | body_id: hir::BodyId, span: Span, id: ast::NodeId) { |
699 | // Wrap in tables here, not just in visit_nested_body, | |
700 | // in order for `check_fn` to be able to use them. | |
701 | let old_tables = self.tables; | |
702 | self.tables = self.tcx.body_tables(body_id); | |
703 | let body = self.tcx.hir.body(body_id); | |
b039eaaf | 704 | run_lints!(self, check_fn, late_passes, fk, decl, body, span, id); |
476ff2be | 705 | hir_visit::walk_fn(self, fk, decl, body_id, span, id); |
7453a54e | 706 | run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id); |
32a655c1 | 707 | self.tables = old_tables; |
1a4d82fc JJ |
708 | } |
709 | ||
b039eaaf | 710 | fn visit_variant_data(&mut self, |
476ff2be | 711 | s: &'tcx hir::VariantData, |
b039eaaf | 712 | name: ast::Name, |
476ff2be | 713 | g: &'tcx hir::Generics, |
b039eaaf SL |
714 | item_id: ast::NodeId, |
715 | _: Span) { | |
716 | run_lints!(self, check_struct_def, late_passes, s, name, g, item_id); | |
717 | hir_visit::walk_struct_def(self, s); | |
718 | run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id); | |
1a4d82fc JJ |
719 | } |
720 | ||
476ff2be | 721 | fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { |
3b2f2976 | 722 | self.with_lint_attrs(s.id, &s.attrs, |cx| { |
b039eaaf SL |
723 | run_lints!(cx, check_struct_field, late_passes, s); |
724 | hir_visit::walk_struct_field(cx, s); | |
1a4d82fc JJ |
725 | }) |
726 | } | |
727 | ||
476ff2be SL |
728 | fn visit_variant(&mut self, |
729 | v: &'tcx hir::Variant, | |
730 | g: &'tcx hir::Generics, | |
731 | item_id: ast::NodeId) { | |
3b2f2976 | 732 | self.with_lint_attrs(v.node.data.id(), &v.node.attrs, |cx| { |
b039eaaf SL |
733 | run_lints!(cx, check_variant, late_passes, v, g); |
734 | hir_visit::walk_variant(cx, v, g, item_id); | |
735 | run_lints!(cx, check_variant_post, late_passes, v, g); | |
1a4d82fc JJ |
736 | }) |
737 | } | |
738 | ||
476ff2be | 739 | fn visit_ty(&mut self, t: &'tcx hir::Ty) { |
b039eaaf SL |
740 | run_lints!(self, check_ty, late_passes, t); |
741 | hir_visit::walk_ty(self, t); | |
1a4d82fc JJ |
742 | } |
743 | ||
b039eaaf SL |
744 | fn visit_name(&mut self, sp: Span, name: ast::Name) { |
745 | run_lints!(self, check_name, late_passes, sp, name); | |
1a4d82fc JJ |
746 | } |
747 | ||
476ff2be | 748 | fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) { |
b039eaaf | 749 | run_lints!(self, check_mod, late_passes, m, s, n); |
5bcae85e | 750 | hir_visit::walk_mod(self, m, n); |
7453a54e | 751 | run_lints!(self, check_mod_post, late_passes, m, s, n); |
1a4d82fc JJ |
752 | } |
753 | ||
476ff2be | 754 | fn visit_local(&mut self, l: &'tcx hir::Local) { |
3b2f2976 | 755 | self.with_lint_attrs(l.id, &l.attrs, |cx| { |
92a42be0 SL |
756 | run_lints!(cx, check_local, late_passes, l); |
757 | hir_visit::walk_local(cx, l); | |
758 | }) | |
1a4d82fc JJ |
759 | } |
760 | ||
476ff2be | 761 | fn visit_block(&mut self, b: &'tcx hir::Block) { |
b039eaaf SL |
762 | run_lints!(self, check_block, late_passes, b); |
763 | hir_visit::walk_block(self, b); | |
7453a54e | 764 | run_lints!(self, check_block_post, late_passes, b); |
1a4d82fc JJ |
765 | } |
766 | ||
476ff2be | 767 | fn visit_arm(&mut self, a: &'tcx hir::Arm) { |
b039eaaf SL |
768 | run_lints!(self, check_arm, late_passes, a); |
769 | hir_visit::walk_arm(self, a); | |
1a4d82fc JJ |
770 | } |
771 | ||
476ff2be | 772 | fn visit_decl(&mut self, d: &'tcx hir::Decl) { |
b039eaaf SL |
773 | run_lints!(self, check_decl, late_passes, d); |
774 | hir_visit::walk_decl(self, d); | |
1a4d82fc JJ |
775 | } |
776 | ||
476ff2be | 777 | fn visit_generics(&mut self, g: &'tcx hir::Generics) { |
b039eaaf SL |
778 | run_lints!(self, check_generics, late_passes, g); |
779 | hir_visit::walk_generics(self, g); | |
1a4d82fc JJ |
780 | } |
781 | ||
476ff2be | 782 | fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { |
abe05a73 XL |
783 | let generics = self.generics.take(); |
784 | self.generics = Some(&trait_item.generics); | |
3b2f2976 | 785 | self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| { |
041b39d2 XL |
786 | cx.with_param_env(trait_item.id, |cx| { |
787 | run_lints!(cx, check_trait_item, late_passes, trait_item); | |
788 | hir_visit::walk_trait_item(cx, trait_item); | |
789 | run_lints!(cx, check_trait_item_post, late_passes, trait_item); | |
790 | }); | |
c34b1796 | 791 | }); |
abe05a73 | 792 | self.generics = generics; |
c34b1796 AL |
793 | } |
794 | ||
476ff2be | 795 | fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { |
abe05a73 XL |
796 | let generics = self.generics.take(); |
797 | self.generics = Some(&impl_item.generics); | |
3b2f2976 | 798 | self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| { |
041b39d2 XL |
799 | cx.with_param_env(impl_item.id, |cx| { |
800 | run_lints!(cx, check_impl_item, late_passes, impl_item); | |
801 | hir_visit::walk_impl_item(cx, impl_item); | |
802 | run_lints!(cx, check_impl_item_post, late_passes, impl_item); | |
803 | }); | |
c34b1796 | 804 | }); |
abe05a73 | 805 | self.generics = generics; |
1a4d82fc JJ |
806 | } |
807 | ||
476ff2be | 808 | fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { |
b039eaaf | 809 | run_lints!(self, check_lifetime, late_passes, lt); |
32a655c1 | 810 | hir_visit::walk_lifetime(self, lt); |
1a4d82fc JJ |
811 | } |
812 | ||
476ff2be | 813 | fn visit_lifetime_def(&mut self, lt: &'tcx hir::LifetimeDef) { |
b039eaaf | 814 | run_lints!(self, check_lifetime_def, late_passes, lt); |
32a655c1 | 815 | hir_visit::walk_lifetime_def(self, lt); |
1a4d82fc JJ |
816 | } |
817 | ||
476ff2be | 818 | fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) { |
b039eaaf SL |
819 | run_lints!(self, check_path, late_passes, p, id); |
820 | hir_visit::walk_path(self, p); | |
821 | } | |
822 | ||
476ff2be | 823 | fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) { |
b039eaaf SL |
824 | run_lints!(self, check_attribute, late_passes, attr); |
825 | } | |
826 | } | |
827 | ||
476ff2be SL |
828 | impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { |
829 | fn visit_item(&mut self, it: &'a ast::Item) { | |
3b2f2976 | 830 | self.with_lint_attrs(it.id, &it.attrs, |cx| { |
b039eaaf | 831 | run_lints!(cx, check_item, early_passes, it); |
b039eaaf | 832 | ast_visit::walk_item(cx, it); |
7453a54e | 833 | run_lints!(cx, check_item_post, early_passes, it); |
b039eaaf SL |
834 | }) |
835 | } | |
836 | ||
476ff2be | 837 | fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) { |
3b2f2976 | 838 | self.with_lint_attrs(it.id, &it.attrs, |cx| { |
b039eaaf SL |
839 | run_lints!(cx, check_foreign_item, early_passes, it); |
840 | ast_visit::walk_foreign_item(cx, it); | |
7453a54e | 841 | run_lints!(cx, check_foreign_item_post, early_passes, it); |
b039eaaf SL |
842 | }) |
843 | } | |
844 | ||
476ff2be | 845 | fn visit_pat(&mut self, p: &'a ast::Pat) { |
b039eaaf | 846 | run_lints!(self, check_pat, early_passes, p); |
3b2f2976 | 847 | self.check_id(p.id); |
b039eaaf SL |
848 | ast_visit::walk_pat(self, p); |
849 | } | |
850 | ||
476ff2be | 851 | fn visit_expr(&mut self, e: &'a ast::Expr) { |
3b2f2976 | 852 | self.with_lint_attrs(e.id, &e.attrs, |cx| { |
7453a54e SL |
853 | run_lints!(cx, check_expr, early_passes, e); |
854 | ast_visit::walk_expr(cx, e); | |
855 | }) | |
b039eaaf SL |
856 | } |
857 | ||
476ff2be | 858 | fn visit_stmt(&mut self, s: &'a ast::Stmt) { |
b039eaaf | 859 | run_lints!(self, check_stmt, early_passes, s); |
3b2f2976 | 860 | self.check_id(s.id); |
b039eaaf SL |
861 | ast_visit::walk_stmt(self, s); |
862 | } | |
863 | ||
476ff2be SL |
864 | fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, decl: &'a ast::FnDecl, |
865 | span: Span, id: ast::NodeId) { | |
866 | run_lints!(self, check_fn, early_passes, fk, decl, span, id); | |
3b2f2976 | 867 | self.check_id(id); |
476ff2be SL |
868 | ast_visit::walk_fn(self, fk, decl, span); |
869 | run_lints!(self, check_fn_post, early_passes, fk, decl, span, id); | |
b039eaaf SL |
870 | } |
871 | ||
872 | fn visit_variant_data(&mut self, | |
476ff2be | 873 | s: &'a ast::VariantData, |
b039eaaf | 874 | ident: ast::Ident, |
476ff2be | 875 | g: &'a ast::Generics, |
b039eaaf SL |
876 | item_id: ast::NodeId, |
877 | _: Span) { | |
878 | run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id); | |
3b2f2976 | 879 | self.check_id(s.id()); |
b039eaaf SL |
880 | ast_visit::walk_struct_def(self, s); |
881 | run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id); | |
882 | } | |
883 | ||
476ff2be | 884 | fn visit_struct_field(&mut self, s: &'a ast::StructField) { |
3b2f2976 | 885 | self.with_lint_attrs(s.id, &s.attrs, |cx| { |
b039eaaf SL |
886 | run_lints!(cx, check_struct_field, early_passes, s); |
887 | ast_visit::walk_struct_field(cx, s); | |
888 | }) | |
889 | } | |
890 | ||
476ff2be | 891 | fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) { |
3b2f2976 | 892 | self.with_lint_attrs(item_id, &v.node.attrs, |cx| { |
b039eaaf SL |
893 | run_lints!(cx, check_variant, early_passes, v, g); |
894 | ast_visit::walk_variant(cx, v, g, item_id); | |
895 | run_lints!(cx, check_variant_post, early_passes, v, g); | |
896 | }) | |
897 | } | |
898 | ||
476ff2be | 899 | fn visit_ty(&mut self, t: &'a ast::Ty) { |
b039eaaf | 900 | run_lints!(self, check_ty, early_passes, t); |
3b2f2976 | 901 | self.check_id(t.id); |
b039eaaf SL |
902 | ast_visit::walk_ty(self, t); |
903 | } | |
904 | ||
905 | fn visit_ident(&mut self, sp: Span, id: ast::Ident) { | |
906 | run_lints!(self, check_ident, early_passes, sp, id); | |
907 | } | |
908 | ||
7cac9316 | 909 | fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) { |
b039eaaf | 910 | run_lints!(self, check_mod, early_passes, m, s, n); |
3b2f2976 | 911 | self.check_id(n); |
b039eaaf | 912 | ast_visit::walk_mod(self, m); |
7453a54e | 913 | run_lints!(self, check_mod_post, early_passes, m, s, n); |
b039eaaf SL |
914 | } |
915 | ||
476ff2be | 916 | fn visit_local(&mut self, l: &'a ast::Local) { |
3b2f2976 | 917 | self.with_lint_attrs(l.id, &l.attrs, |cx| { |
7453a54e SL |
918 | run_lints!(cx, check_local, early_passes, l); |
919 | ast_visit::walk_local(cx, l); | |
920 | }) | |
b039eaaf SL |
921 | } |
922 | ||
476ff2be | 923 | fn visit_block(&mut self, b: &'a ast::Block) { |
b039eaaf | 924 | run_lints!(self, check_block, early_passes, b); |
3b2f2976 | 925 | self.check_id(b.id); |
b039eaaf | 926 | ast_visit::walk_block(self, b); |
7453a54e | 927 | run_lints!(self, check_block_post, early_passes, b); |
b039eaaf SL |
928 | } |
929 | ||
476ff2be | 930 | fn visit_arm(&mut self, a: &'a ast::Arm) { |
b039eaaf SL |
931 | run_lints!(self, check_arm, early_passes, a); |
932 | ast_visit::walk_arm(self, a); | |
933 | } | |
934 | ||
476ff2be | 935 | fn visit_expr_post(&mut self, e: &'a ast::Expr) { |
b039eaaf SL |
936 | run_lints!(self, check_expr_post, early_passes, e); |
937 | } | |
938 | ||
476ff2be | 939 | fn visit_generics(&mut self, g: &'a ast::Generics) { |
b039eaaf SL |
940 | run_lints!(self, check_generics, early_passes, g); |
941 | ast_visit::walk_generics(self, g); | |
942 | } | |
943 | ||
476ff2be | 944 | fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) { |
3b2f2976 | 945 | self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| { |
b039eaaf | 946 | run_lints!(cx, check_trait_item, early_passes, trait_item); |
b039eaaf | 947 | ast_visit::walk_trait_item(cx, trait_item); |
7453a54e | 948 | run_lints!(cx, check_trait_item_post, early_passes, trait_item); |
b039eaaf SL |
949 | }); |
950 | } | |
951 | ||
476ff2be | 952 | fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) { |
3b2f2976 | 953 | self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| { |
b039eaaf | 954 | run_lints!(cx, check_impl_item, early_passes, impl_item); |
b039eaaf | 955 | ast_visit::walk_impl_item(cx, impl_item); |
7453a54e | 956 | run_lints!(cx, check_impl_item_post, early_passes, impl_item); |
b039eaaf SL |
957 | }); |
958 | } | |
959 | ||
476ff2be | 960 | fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) { |
b039eaaf | 961 | run_lints!(self, check_lifetime, early_passes, lt); |
3b2f2976 | 962 | self.check_id(lt.id); |
b039eaaf SL |
963 | } |
964 | ||
476ff2be | 965 | fn visit_lifetime_def(&mut self, lt: &'a ast::LifetimeDef) { |
b039eaaf SL |
966 | run_lints!(self, check_lifetime_def, early_passes, lt); |
967 | } | |
968 | ||
476ff2be | 969 | fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) { |
b039eaaf | 970 | run_lints!(self, check_path, early_passes, p, id); |
3b2f2976 | 971 | self.check_id(id); |
b039eaaf SL |
972 | ast_visit::walk_path(self, p); |
973 | } | |
974 | ||
476ff2be | 975 | fn visit_path_list_item(&mut self, prefix: &'a ast::Path, item: &'a ast::PathListItem) { |
b039eaaf | 976 | run_lints!(self, check_path_list_item, early_passes, item); |
3b2f2976 | 977 | self.check_id(item.node.id); |
b039eaaf SL |
978 | ast_visit::walk_path_list_item(self, prefix, item); |
979 | } | |
980 | ||
476ff2be | 981 | fn visit_attribute(&mut self, attr: &'a ast::Attribute) { |
b039eaaf | 982 | run_lints!(self, check_attribute, early_passes, attr); |
1a4d82fc | 983 | } |
7cac9316 XL |
984 | |
985 | fn visit_mac_def(&mut self, _mac: &'a ast::MacroDef, id: ast::NodeId) { | |
3b2f2976 | 986 | self.check_id(id); |
92a42be0 SL |
987 | } |
988 | } | |
989 | ||
990 | ||
1a4d82fc JJ |
991 | /// Perform lint checking on a crate. |
992 | /// | |
993 | /// Consumes the `lint_store` field of the `Session`. | |
cc61c64b | 994 | pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { |
7cac9316 | 995 | let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); |
cc61c64b | 996 | |
32a655c1 SL |
997 | let krate = tcx.hir.krate(); |
998 | ||
32a655c1 | 999 | let mut cx = LateContext { |
041b39d2 | 1000 | tcx, |
3b2f2976 | 1001 | tables: &ty::TypeckTables::empty(None), |
041b39d2 XL |
1002 | param_env: ty::ParamEnv::empty(Reveal::UserFacing), |
1003 | access_levels, | |
7cac9316 | 1004 | lint_sess: LintSession::new(&tcx.sess.lint_store), |
3b2f2976 | 1005 | last_ast_node_with_lint_attrs: ast::CRATE_NODE_ID, |
abe05a73 | 1006 | generics: None, |
32a655c1 | 1007 | }; |
1a4d82fc JJ |
1008 | |
1009 | // Visit the whole crate. | |
3b2f2976 | 1010 | cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| { |
1a4d82fc JJ |
1011 | // since the root module isn't visited as an item (because it isn't an |
1012 | // item), warn for it here. | |
b039eaaf | 1013 | run_lints!(cx, check_crate, late_passes, krate); |
1a4d82fc | 1014 | |
b039eaaf | 1015 | hir_visit::walk_crate(cx, krate); |
7453a54e SL |
1016 | |
1017 | run_lints!(cx, check_crate_post, late_passes, krate); | |
1a4d82fc JJ |
1018 | }); |
1019 | ||
7cac9316 XL |
1020 | // Put the lint store levels and passes back in the session. |
1021 | cx.lint_sess.restore(&tcx.sess.lint_store); | |
1a4d82fc | 1022 | } |
b039eaaf SL |
1023 | |
1024 | pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { | |
1025 | let mut cx = EarlyContext::new(sess, krate); | |
1026 | ||
1027 | // Visit the whole crate. | |
3b2f2976 | 1028 | cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| { |
b039eaaf SL |
1029 | // since the root module isn't visited as an item (because it isn't an |
1030 | // item), warn for it here. | |
1031 | run_lints!(cx, check_crate, early_passes, krate); | |
1032 | ||
1033 | ast_visit::walk_crate(cx, krate); | |
7453a54e SL |
1034 | |
1035 | run_lints!(cx, check_crate_post, early_passes, krate); | |
b039eaaf SL |
1036 | }); |
1037 | ||
7cac9316 XL |
1038 | // Put the lint store levels and passes back in the session. |
1039 | cx.lint_sess.restore(&sess.lint_store); | |
b039eaaf | 1040 | |
3b2f2976 XL |
1041 | // Emit all buffered lints from early on in the session now that we've |
1042 | // calculated the lint levels for all AST nodes. | |
1043 | for (_id, lints) in cx.buffered.map { | |
1044 | for early_lint in lints { | |
1045 | span_bug!(early_lint.span, "failed to process bufferd lint here"); | |
b039eaaf SL |
1046 | } |
1047 | } | |
1048 | } | |
8bb4bdeb XL |
1049 | |
1050 | impl Encodable for LintId { | |
1051 | fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { | |
1052 | s.emit_str(&self.lint.name.to_lowercase()) | |
1053 | } | |
1054 | } | |
1055 | ||
1056 | impl Decodable for LintId { | |
1057 | #[inline] | |
1058 | fn decode<D: Decoder>(d: &mut D) -> Result<LintId, D::Error> { | |
1059 | let s = d.read_str()?; | |
1060 | ty::tls::with(|tcx| { | |
3b2f2976 XL |
1061 | match tcx.sess.lint_store.borrow().find_lints(&s) { |
1062 | Ok(ids) => { | |
1063 | if ids.len() != 0 { | |
1064 | panic!("invalid lint-id `{}`", s); | |
1065 | } | |
1066 | Ok(ids[0]) | |
1067 | } | |
8bb4bdeb XL |
1068 | Err(_) => panic!("invalid lint-id `{}`", s), |
1069 | } | |
1070 | }) | |
1071 | } | |
1072 | } |