]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //! Implementation of lint checking. |
2 | //! | |
94b46f34 XL |
3 | //! The lint checking is mostly consolidated into one pass which runs |
4 | //! after all other analyses. Throughout compilation, lint warnings | |
1a4d82fc | 5 | //! can be added via the `add_lint` method on the Session structure. This |
9fa01778 | 6 | //! requires a span and an ID of the node that the lint is being added to. The |
1a4d82fc JJ |
7 | //! lint isn't actually emitted at that time because it is unknown what the |
8 | //! actual lint level at that location is. | |
9 | //! | |
94b46f34 XL |
10 | //! To actually emit lint warnings/errors, a separate pass is used. |
11 | //! A context keeps track of the current state of all lint levels. | |
1a4d82fc JJ |
12 | //! Upon entering a node of the ast which can modify the lint settings, the |
13 | //! previous lint state is pushed onto a stack and the ast is then recursed | |
9fa01778 | 14 | //! upon. As the ast is traversed, this keeps track of the current lint level |
1a4d82fc | 15 | //! for all lint attributes. |
3b2f2976 | 16 | |
1a4d82fc JJ |
17 | use self::TargetLint::*; |
18 | ||
e1599b0c XL |
19 | use crate::hir; |
20 | use crate::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; | |
21 | use crate::hir::intravisit as hir_visit; | |
22 | use crate::hir::intravisit::Visitor; | |
23 | use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData}; | |
532ac7d7 | 24 | use crate::lint::{EarlyLintPass, LateLintPass, EarlyLintPassObject, LateLintPassObject}; |
e74abb32 | 25 | use crate::lint::{Level, Lint, LintId, LintPass, LintBuffer, FutureIncompatibleInfo}; |
9fa01778 XL |
26 | use crate::lint::builtin::BuiltinLintDiagnostics; |
27 | use crate::lint::levels::{LintLevelSets, LintLevelsBuilder}; | |
28 | use crate::middle::privacy::AccessLevels; | |
e74abb32 XL |
29 | use crate::session::Session; |
30 | use crate::ty::{self, print::Printer, subst::GenericArg, TyCtxt, Ty}; | |
9fa01778 XL |
31 | use crate::ty::layout::{LayoutError, LayoutOf, TyLayout}; |
32 | use crate::util::nodemap::FxHashMap; | |
33 | use crate::util::common::time; | |
1a4d82fc | 34 | |
e1599b0c XL |
35 | use errors::DiagnosticBuilder; |
36 | use std::slice; | |
e74abb32 | 37 | use rustc_data_structures::sync::{self, ParallelIterator, join, par_iter}; |
e9174d1e | 38 | use syntax::ast; |
0731742a | 39 | use syntax::util::lev_distance::find_best_match_for_name; |
b039eaaf | 40 | use syntax::visit as ast_visit; |
e1599b0c | 41 | use syntax_pos::{MultiSpan, Span, symbol::Symbol}; |
1a4d82fc | 42 | |
60c5eb7d XL |
43 | use rustc_error_codes::*; |
44 | ||
1a4d82fc JJ |
45 | /// Information about the registered lints. |
46 | /// | |
47 | /// This is basically the subset of `Context` that we can | |
48 | /// build early in the compile pipeline. | |
49 | pub struct LintStore { | |
60c5eb7d | 50 | /// Registered lints. |
e74abb32 | 51 | lints: Vec<&'static Lint>, |
1a4d82fc | 52 | |
e74abb32 XL |
53 | /// Constructor functions for each variety of lint pass. |
54 | /// | |
55 | /// These should only be called once, but since we want to avoid locks or | |
56 | /// interior mutability, we don't enforce this (and lints should, in theory, | |
57 | /// be compatible with being constructed more than once, though not | |
58 | /// necessarily in a sane manner. This is safe though.) | |
59 | pre_expansion_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>, | |
60 | early_passes: Vec<Box<dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync>>, | |
61 | late_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>, | |
62 | /// This is unique in that we construct them per-module, so not once. | |
63 | late_module_passes: Vec<Box<dyn Fn() -> LateLintPassObject + sync::Send + sync::Sync>>, | |
1a4d82fc JJ |
64 | |
65 | /// Lints indexed by name. | |
476ff2be | 66 | by_name: FxHashMap<String, TargetLint>, |
1a4d82fc | 67 | |
0bf4aa26 XL |
68 | /// Map of registered lint groups to what lints they expand to. |
69 | lint_groups: FxHashMap<&'static str, LintGroup>, | |
7cac9316 XL |
70 | } |
71 | ||
3b2f2976 XL |
72 | /// Lints that are buffered up early on in the `Session` before the |
73 | /// `LintLevels` is calculated | |
60c5eb7d | 74 | #[derive(PartialEq, Debug)] |
3b2f2976 XL |
75 | pub struct BufferedEarlyLint { |
76 | pub lint_id: LintId, | |
77 | pub ast_id: ast::NodeId, | |
78 | pub span: MultiSpan, | |
79 | pub msg: String, | |
0531ce1d | 80 | pub diagnostic: BuiltinLintDiagnostics, |
c30ab7b3 SL |
81 | } |
82 | ||
3b2f2976 | 83 | /// The target of the `by_name` map, which accounts for renaming/deprecation. |
1a4d82fc JJ |
84 | enum TargetLint { |
85 | /// A direct lint target | |
86 | Id(LintId), | |
87 | ||
88 | /// Temporary renaming, used for easing migration pain; see #16545 | |
89 | Renamed(String, LintId), | |
c1a9b12d SL |
90 | |
91 | /// Lint with this name existed previously, but has been removed/deprecated. | |
92 | /// The string argument is the reason for removal. | |
93 | Removed(String), | |
94 | } | |
95 | ||
3b2f2976 | 96 | pub enum FindLintError { |
c1a9b12d | 97 | NotFound, |
cc61c64b | 98 | Removed, |
1a4d82fc JJ |
99 | } |
100 | ||
0bf4aa26 XL |
101 | struct LintAlias { |
102 | name: &'static str, | |
103 | /// Whether deprecation warnings should be suppressed for this alias. | |
104 | silent: bool, | |
105 | } | |
106 | ||
107 | struct LintGroup { | |
108 | lint_ids: Vec<LintId>, | |
109 | from_plugin: bool, | |
110 | depr: Option<LintAlias>, | |
111 | } | |
112 | ||
3b2f2976 XL |
113 | pub enum CheckLintNameResult<'a> { |
114 | Ok(&'a [LintId]), | |
0731742a XL |
115 | /// Lint doesn't exist. Potentially contains a suggestion for a correct lint name. |
116 | NoLint(Option<Symbol>), | |
3b2f2976 | 117 | /// The lint is either renamed or removed. This is the warning |
8faf50e0 XL |
118 | /// message, and an optional new name (`None` if removed). |
119 | Warning(String, Option<String>), | |
b7449926 XL |
120 | /// The lint is from a tool. If the Option is None, then either |
121 | /// the lint does not exist in the tool or the code was not | |
122 | /// compiled with the tool and therefore the lint was never | |
123 | /// added to the `LintStore`. Otherwise the `LintId` will be | |
124 | /// returned as if it where a rustc lint. | |
125 | Tool(Result<&'a [LintId], (Option<&'a [LintId]>, String)>), | |
3b2f2976 XL |
126 | } |
127 | ||
1a4d82fc | 128 | impl LintStore { |
1a4d82fc JJ |
129 | pub fn new() -> LintStore { |
130 | LintStore { | |
c30ab7b3 | 131 | lints: vec![], |
e74abb32 XL |
132 | pre_expansion_passes: vec![], |
133 | early_passes: vec![], | |
134 | late_passes: vec![], | |
532ac7d7 | 135 | late_module_passes: vec![], |
0bf4aa26 | 136 | by_name: Default::default(), |
0bf4aa26 | 137 | lint_groups: Default::default(), |
1a4d82fc JJ |
138 | } |
139 | } | |
140 | ||
e74abb32 | 141 | pub fn get_lints<'t>(&'t self) -> &'t [&'static Lint] { |
c34b1796 | 142 | &self.lints |
1a4d82fc JJ |
143 | } |
144 | ||
145 | pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> { | |
0bf4aa26 XL |
146 | self.lint_groups.iter() |
147 | .filter(|(_, LintGroup { depr, .. })| { | |
148 | // Don't display deprecated lint groups. | |
149 | depr.is_none() | |
150 | }) | |
151 | .map(|(k, LintGroup { lint_ids, from_plugin, .. })| { | |
152 | (*k, lint_ids.clone(), *from_plugin) | |
153 | }) | |
154 | .collect() | |
1a4d82fc JJ |
155 | } |
156 | ||
e74abb32 XL |
157 | pub fn register_early_pass( |
158 | &mut self, | |
159 | pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync | |
160 | ) { | |
161 | self.early_passes.push(Box::new(pass)); | |
b039eaaf SL |
162 | } |
163 | ||
8faf50e0 XL |
164 | pub fn register_pre_expansion_pass( |
165 | &mut self, | |
e74abb32 | 166 | pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync, |
8faf50e0 | 167 | ) { |
e74abb32 | 168 | self.pre_expansion_passes.push(Box::new(pass)); |
8faf50e0 XL |
169 | } |
170 | ||
e74abb32 XL |
171 | pub fn register_late_pass( |
172 | &mut self, | |
173 | pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync, | |
174 | ) { | |
175 | self.late_passes.push(Box::new(pass)); | |
176 | } | |
177 | ||
178 | pub fn register_late_mod_pass( | |
179 | &mut self, | |
180 | pass: impl Fn() -> LateLintPassObject + 'static + sync::Send + sync::Sync, | |
181 | ) { | |
182 | self.late_module_passes.push(Box::new(pass)); | |
b039eaaf SL |
183 | } |
184 | ||
185 | // Helper method for register_early/late_pass | |
e74abb32 XL |
186 | pub fn register_lints(&mut self, lints: &[&'static Lint]) { |
187 | for lint in lints { | |
188 | self.lints.push(lint); | |
1a4d82fc | 189 | |
8faf50e0 | 190 | let id = LintId::of(lint); |
1a4d82fc | 191 | if self.by_name.insert(lint.name_lower(), Id(id)).is_some() { |
e74abb32 | 192 | bug!("duplicate specification of lint {}", lint.name_lower()) |
1a4d82fc | 193 | } |
1a4d82fc | 194 | |
e74abb32 XL |
195 | if let Some(FutureIncompatibleInfo { edition, .. }) = lint.future_incompatible { |
196 | if let Some(edition) = edition { | |
197 | self.lint_groups.entry(edition.lint_name()) | |
198 | .or_insert(LintGroup { | |
199 | lint_ids: vec![], | |
200 | from_plugin: lint.is_plugin, | |
201 | depr: None, | |
202 | }) | |
203 | .lint_ids.push(id); | |
204 | } | |
0531ce1d | 205 | |
e74abb32 XL |
206 | self.lint_groups.entry("future_incompatible") |
207 | .or_insert(LintGroup { | |
208 | lint_ids: vec![], | |
209 | from_plugin: lint.is_plugin, | |
210 | depr: None, | |
211 | }) | |
212 | .lint_ids.push(id); | |
0531ce1d | 213 | } |
9cc50fc6 | 214 | } |
9cc50fc6 SL |
215 | } |
216 | ||
0bf4aa26 XL |
217 | pub fn register_group_alias( |
218 | &mut self, | |
219 | lint_name: &'static str, | |
220 | alias: &'static str, | |
221 | ) { | |
222 | self.lint_groups.insert(alias, LintGroup { | |
223 | lint_ids: vec![], | |
224 | from_plugin: false, | |
225 | depr: Some(LintAlias { name: lint_name, silent: true }), | |
226 | }); | |
227 | } | |
228 | ||
b7449926 XL |
229 | pub fn register_group( |
230 | &mut self, | |
b7449926 XL |
231 | from_plugin: bool, |
232 | name: &'static str, | |
233 | deprecated_name: Option<&'static str>, | |
234 | to: Vec<LintId>, | |
235 | ) { | |
236 | let new = self | |
237 | .lint_groups | |
0bf4aa26 XL |
238 | .insert(name, LintGroup { |
239 | lint_ids: to, | |
240 | from_plugin, | |
241 | depr: None, | |
242 | }) | |
b7449926 XL |
243 | .is_none(); |
244 | if let Some(deprecated) = deprecated_name { | |
0bf4aa26 XL |
245 | self.lint_groups.insert(deprecated, LintGroup { |
246 | lint_ids: vec![], | |
247 | from_plugin, | |
248 | depr: Some(LintAlias { name, silent: false }), | |
249 | }); | |
b7449926 | 250 | } |
1a4d82fc JJ |
251 | |
252 | if !new { | |
e74abb32 | 253 | bug!("duplicate specification of lint group {}", name); |
1a4d82fc JJ |
254 | } |
255 | } | |
256 | ||
c34b1796 | 257 | pub fn register_renamed(&mut self, old_name: &str, new_name: &str) { |
1a4d82fc JJ |
258 | let target = match self.by_name.get(new_name) { |
259 | Some(&Id(lint_id)) => lint_id.clone(), | |
54a0048b | 260 | _ => bug!("invalid lint renaming of {} to {}", old_name, new_name) |
1a4d82fc JJ |
261 | }; |
262 | self.by_name.insert(old_name.to_string(), Renamed(new_name.to_string(), target)); | |
263 | } | |
264 | ||
c1a9b12d SL |
265 | pub fn register_removed(&mut self, name: &str, reason: &str) { |
266 | self.by_name.insert(name.into(), Removed(reason.into())); | |
267 | } | |
268 | ||
0bf4aa26 | 269 | pub fn find_lints(&self, mut lint_name: &str) -> Result<Vec<LintId>, FindLintError> { |
1a4d82fc | 270 | match self.by_name.get(lint_name) { |
3b2f2976 | 271 | Some(&Id(lint_id)) => Ok(vec![lint_id]), |
92a42be0 | 272 | Some(&Renamed(_, lint_id)) => { |
3b2f2976 | 273 | Ok(vec![lint_id]) |
c1a9b12d | 274 | }, |
041b39d2 | 275 | Some(&Removed(_)) => { |
c1a9b12d SL |
276 | Err(FindLintError::Removed) |
277 | }, | |
3b2f2976 | 278 | None => { |
0bf4aa26 XL |
279 | loop { |
280 | return match self.lint_groups.get(lint_name) { | |
281 | Some(LintGroup {lint_ids, depr, .. }) => { | |
282 | if let Some(LintAlias { name, .. }) = depr { | |
283 | lint_name = name; | |
284 | continue; | |
285 | } | |
286 | Ok(lint_ids.clone()) | |
287 | } | |
288 | None => Err(FindLintError::Removed) | |
289 | }; | |
1a4d82fc JJ |
290 | } |
291 | } | |
292 | } | |
7cac9316 | 293 | } |
7cac9316 | 294 | |
3b2f2976 XL |
295 | /// Checks the validity of lint names derived from the command line |
296 | pub fn check_lint_name_cmdline(&self, | |
297 | sess: &Session, | |
298 | lint_name: &str, | |
299 | level: Level) { | |
b7449926 | 300 | let db = match self.check_lint_name(lint_name, None) { |
3b2f2976 | 301 | CheckLintNameResult::Ok(_) => None, |
8faf50e0 | 302 | CheckLintNameResult::Warning(ref msg, _) => { |
3b2f2976 XL |
303 | Some(sess.struct_warn(msg)) |
304 | }, | |
0731742a XL |
305 | CheckLintNameResult::NoLint(suggestion) => { |
306 | let mut err = struct_err!(sess, E0602, "unknown lint: `{}`", lint_name); | |
307 | ||
308 | if let Some(suggestion) = suggestion { | |
309 | err.help(&format!("did you mean: `{}`", suggestion)); | |
310 | } | |
311 | ||
312 | Some(err) | |
3b2f2976 | 313 | } |
b7449926 XL |
314 | CheckLintNameResult::Tool(result) => match result { |
315 | Err((Some(_), new_name)) => Some(sess.struct_warn(&format!( | |
316 | "lint name `{}` is deprecated \ | |
317 | and does not have an effect anymore. \ | |
318 | Use: {}", | |
319 | lint_name, new_name | |
320 | ))), | |
321 | _ => None, | |
322 | }, | |
3b2f2976 | 323 | }; |
7cac9316 | 324 | |
3b2f2976 XL |
325 | if let Some(mut db) = db { |
326 | let msg = format!("requested on the command line with `{} {}`", | |
327 | match level { | |
328 | Level::Allow => "-A", | |
329 | Level::Warn => "-W", | |
330 | Level::Deny => "-D", | |
331 | Level::Forbid => "-F", | |
332 | }, | |
333 | lint_name); | |
334 | db.note(&msg); | |
335 | db.emit(); | |
7cac9316 XL |
336 | } |
337 | } | |
338 | ||
3b2f2976 XL |
339 | /// Checks the name of a lint for its existence, and whether it was |
340 | /// renamed or removed. Generates a DiagnosticBuilder containing a | |
341 | /// warning for renamed and removed lints. This is over both lint | |
342 | /// names from attributes and those passed on the command line. Since | |
343 | /// it emits non-fatal warnings and there are *two* lint passes that | |
344 | /// inspect attributes, this is only run from the late pass to avoid | |
345 | /// printing duplicate warnings. | |
b7449926 XL |
346 | pub fn check_lint_name( |
347 | &self, | |
348 | lint_name: &str, | |
e1599b0c | 349 | tool_name: Option<Symbol>, |
0bf4aa26 | 350 | ) -> CheckLintNameResult<'_> { |
b7449926 XL |
351 | let complete_name = if let Some(tool_name) = tool_name { |
352 | format!("{}::{}", tool_name, lint_name) | |
353 | } else { | |
354 | lint_name.to_string() | |
355 | }; | |
356 | // If the lint was scoped with `tool::` check if the tool lint exists | |
357 | if let Some(_) = tool_name { | |
358 | match self.by_name.get(&complete_name) { | |
359 | None => match self.lint_groups.get(&*complete_name) { | |
360 | None => return CheckLintNameResult::Tool(Err((None, String::new()))), | |
0bf4aa26 XL |
361 | Some(LintGroup { lint_ids, .. }) => { |
362 | return CheckLintNameResult::Tool(Ok(&lint_ids)); | |
363 | } | |
b7449926 XL |
364 | }, |
365 | Some(&Id(ref id)) => return CheckLintNameResult::Tool(Ok(slice::from_ref(id))), | |
366 | // If the lint was registered as removed or renamed by the lint tool, we don't need | |
367 | // to treat tool_lints and rustc lints different and can use the code below. | |
368 | _ => {} | |
369 | } | |
370 | } | |
371 | match self.by_name.get(&complete_name) { | |
372 | Some(&Renamed(ref new_name, _)) => CheckLintNameResult::Warning( | |
373 | format!( | |
374 | "lint `{}` has been renamed to `{}`", | |
375 | complete_name, new_name | |
376 | ), | |
377 | Some(new_name.to_owned()), | |
378 | ), | |
379 | Some(&Removed(ref reason)) => CheckLintNameResult::Warning( | |
380 | format!("lint `{}` has been removed: `{}`", complete_name, reason), | |
381 | None, | |
382 | ), | |
383 | None => match self.lint_groups.get(&*complete_name) { | |
384 | // If neither the lint, nor the lint group exists check if there is a `clippy::` | |
385 | // variant of this lint | |
386 | None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"), | |
0bf4aa26 | 387 | Some(LintGroup { lint_ids, depr, .. }) => { |
b7449926 | 388 | // Check if the lint group name is deprecated |
0bf4aa26 XL |
389 | if let Some(LintAlias { name, silent }) = depr { |
390 | let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap(); | |
391 | return if *silent { | |
392 | CheckLintNameResult::Ok(&lint_ids) | |
393 | } else { | |
394 | CheckLintNameResult::Tool(Err(( | |
395 | Some(&lint_ids), | |
396 | name.to_string(), | |
397 | ))) | |
398 | }; | |
b7449926 | 399 | } |
0bf4aa26 | 400 | CheckLintNameResult::Ok(&lint_ids) |
b7449926 | 401 | } |
3b2f2976 | 402 | }, |
b7449926 XL |
403 | Some(&Id(ref id)) => CheckLintNameResult::Ok(slice::from_ref(id)), |
404 | } | |
405 | } | |
406 | ||
407 | fn check_tool_name_for_backwards_compat( | |
408 | &self, | |
409 | lint_name: &str, | |
410 | tool_name: &str, | |
0bf4aa26 | 411 | ) -> CheckLintNameResult<'_> { |
b7449926 XL |
412 | let complete_name = format!("{}::{}", tool_name, lint_name); |
413 | match self.by_name.get(&complete_name) { | |
414 | None => match self.lint_groups.get(&*complete_name) { | |
415 | // Now we are sure, that this lint exists nowhere | |
0731742a XL |
416 | None => { |
417 | let symbols = self.by_name.keys() | |
418 | .map(|name| Symbol::intern(&name)) | |
419 | .collect::<Vec<_>>(); | |
420 | ||
421 | let suggestion = | |
422 | find_best_match_for_name(symbols.iter(), &lint_name.to_lowercase(), None); | |
423 | ||
424 | CheckLintNameResult::NoLint(suggestion) | |
425 | } | |
0bf4aa26 XL |
426 | Some(LintGroup { lint_ids, depr, .. }) => { |
427 | // Reaching this would be weird, but let's cover this case anyway | |
428 | if let Some(LintAlias { name, silent }) = depr { | |
429 | let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap(); | |
430 | return if *silent { | |
431 | CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name))) | |
432 | } else { | |
433 | CheckLintNameResult::Tool(Err(( | |
434 | Some(&lint_ids), | |
435 | name.to_string(), | |
436 | ))) | |
437 | }; | |
b7449926 | 438 | } |
0bf4aa26 | 439 | CheckLintNameResult::Tool(Err((Some(&lint_ids), complete_name))) |
3b2f2976 | 440 | } |
b7449926 XL |
441 | }, |
442 | Some(&Id(ref id)) => { | |
443 | CheckLintNameResult::Tool(Err((Some(slice::from_ref(id)), complete_name))) | |
c1a9b12d | 444 | } |
0731742a | 445 | _ => CheckLintNameResult::NoLint(None), |
c1a9b12d | 446 | } |
1a4d82fc | 447 | } |
1a4d82fc JJ |
448 | } |
449 | ||
b039eaaf | 450 | /// Context for lint checking after type checking. |
dc9dc135 | 451 | pub struct LateContext<'a, 'tcx> { |
1a4d82fc | 452 | /// Type context we're checking in. |
dc9dc135 | 453 | pub tcx: TyCtxt<'tcx>, |
1a4d82fc | 454 | |
32a655c1 | 455 | /// Side-tables for the body we are in. |
532ac7d7 | 456 | // FIXME: Make this lazy to avoid running the TypeckTables query? |
32a655c1 SL |
457 | pub tables: &'a ty::TypeckTables<'tcx>, |
458 | ||
041b39d2 XL |
459 | /// Parameter environment for the item we are in. |
460 | pub param_env: ty::ParamEnv<'tcx>, | |
1a4d82fc | 461 | |
92a42be0 SL |
462 | /// Items accessible from the crate being checked. |
463 | pub access_levels: &'a AccessLevels, | |
1a4d82fc | 464 | |
7cac9316 | 465 | /// The store of registered lints and the lint levels. |
e74abb32 | 466 | lint_store: &'tcx LintStore, |
3b2f2976 | 467 | |
9fa01778 | 468 | last_node_with_lint_attrs: hir::HirId, |
abe05a73 XL |
469 | |
470 | /// Generic type parameters in scope for the item we are in. | |
471 | pub generics: Option<&'tcx hir::Generics>, | |
532ac7d7 XL |
472 | |
473 | /// We are only looking at one module | |
474 | only_module: bool, | |
475 | } | |
476 | ||
dc9dc135 | 477 | pub struct LateContextAndPass<'a, 'tcx, T: LateLintPass<'a, 'tcx>> { |
532ac7d7 XL |
478 | context: LateContext<'a, 'tcx>, |
479 | pass: T, | |
1a4d82fc JJ |
480 | } |
481 | ||
b039eaaf SL |
482 | /// Context for lint checking of the AST, after expansion, before lowering to |
483 | /// HIR. | |
484 | pub struct EarlyContext<'a> { | |
485 | /// Type context we're checking in. | |
486 | pub sess: &'a Session, | |
487 | ||
488 | /// The crate being checked. | |
489 | pub krate: &'a ast::Crate, | |
490 | ||
3b2f2976 XL |
491 | builder: LintLevelsBuilder<'a>, |
492 | ||
7cac9316 | 493 | /// The store of registered lints and the lint levels. |
e74abb32 | 494 | lint_store: &'a LintStore, |
3b2f2976 XL |
495 | |
496 | buffered: LintBuffer, | |
b039eaaf SL |
497 | } |
498 | ||
9fa01778 XL |
499 | pub struct EarlyContextAndPass<'a, T: EarlyLintPass> { |
500 | context: EarlyContext<'a>, | |
501 | pass: T, | |
502 | } | |
503 | ||
8faf50e0 | 504 | pub trait LintPassObject: Sized {} |
7cac9316 | 505 | |
8faf50e0 | 506 | impl LintPassObject for EarlyLintPassObject {} |
7cac9316 | 507 | |
8faf50e0 | 508 | impl LintPassObject for LateLintPassObject {} |
7cac9316 | 509 | |
dc9dc135 | 510 | pub trait LintContext: Sized { |
7cac9316 XL |
511 | type PassObject: LintPassObject; |
512 | ||
b039eaaf SL |
513 | fn sess(&self) -> &Session; |
514 | fn lints(&self) -> &LintStore; | |
1a4d82fc | 515 | |
476ff2be SL |
516 | fn lookup_and_emit<S: Into<MultiSpan>>(&self, |
517 | lint: &'static Lint, | |
518 | span: Option<S>, | |
519 | msg: &str) { | |
3b2f2976 | 520 | self.lookup(lint, span, msg).emit(); |
1a4d82fc JJ |
521 | } |
522 | ||
0531ce1d XL |
523 | fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(&self, |
524 | lint: &'static Lint, | |
525 | span: Option<S>, | |
526 | msg: &str, | |
527 | diagnostic: BuiltinLintDiagnostics) { | |
528 | let mut db = self.lookup(lint, span, msg); | |
529 | diagnostic.run(self.sess(), &mut db); | |
530 | db.emit(); | |
531 | } | |
532 | ||
c30ab7b3 SL |
533 | fn lookup<S: Into<MultiSpan>>(&self, |
534 | lint: &'static Lint, | |
535 | span: Option<S>, | |
536 | msg: &str) | |
0bf4aa26 | 537 | -> DiagnosticBuilder<'_>; |
9cc50fc6 | 538 | |
1a4d82fc | 539 | /// Emit a lint at the appropriate level, for a particular span. |
476ff2be | 540 | fn span_lint<S: Into<MultiSpan>>(&self, lint: &'static Lint, span: S, msg: &str) { |
1a4d82fc JJ |
541 | self.lookup_and_emit(lint, Some(span), msg); |
542 | } | |
543 | ||
c30ab7b3 SL |
544 | fn struct_span_lint<S: Into<MultiSpan>>(&self, |
545 | lint: &'static Lint, | |
546 | span: S, | |
547 | msg: &str) | |
0bf4aa26 | 548 | -> DiagnosticBuilder<'_> { |
9cc50fc6 SL |
549 | self.lookup(lint, Some(span), msg) |
550 | } | |
551 | ||
b039eaaf SL |
552 | /// Emit a lint and note at the appropriate level, for a particular span. |
553 | fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str, | |
554 | note_span: Span, note: &str) { | |
9cc50fc6 | 555 | let mut err = self.lookup(lint, Some(span), msg); |
3b2f2976 XL |
556 | if note_span == span { |
557 | err.note(note); | |
558 | } else { | |
559 | err.span_note(note_span, note); | |
b039eaaf | 560 | } |
9cc50fc6 | 561 | err.emit(); |
b039eaaf SL |
562 | } |
563 | ||
564 | /// Emit a lint and help at the appropriate level, for a particular span. | |
565 | fn span_lint_help(&self, lint: &'static Lint, span: Span, | |
566 | msg: &str, help: &str) { | |
9cc50fc6 | 567 | let mut err = self.lookup(lint, Some(span), msg); |
b039eaaf | 568 | self.span_lint(lint, span, msg); |
3b2f2976 | 569 | err.span_help(span, help); |
9cc50fc6 | 570 | err.emit(); |
b039eaaf SL |
571 | } |
572 | ||
573 | /// Emit a lint at the appropriate level, with no associated span. | |
574 | fn lint(&self, lint: &'static Lint, msg: &str) { | |
476ff2be | 575 | self.lookup_and_emit(lint, None as Option<Span>, msg); |
b039eaaf | 576 | } |
b039eaaf SL |
577 | } |
578 | ||
579 | ||
580 | impl<'a> EarlyContext<'a> { | |
8faf50e0 XL |
581 | fn new( |
582 | sess: &'a Session, | |
e74abb32 | 583 | lint_store: &'a LintStore, |
8faf50e0 | 584 | krate: &'a ast::Crate, |
8faf50e0 | 585 | buffered: LintBuffer, |
e74abb32 | 586 | warn_about_weird_lints: bool, |
8faf50e0 | 587 | ) -> EarlyContext<'a> { |
b039eaaf | 588 | EarlyContext { |
041b39d2 XL |
589 | sess, |
590 | krate, | |
e74abb32 XL |
591 | lint_store, |
592 | builder: LintLevelSets::builder(sess, warn_about_weird_lints, lint_store), | |
8faf50e0 | 593 | buffered, |
3b2f2976 XL |
594 | } |
595 | } | |
9fa01778 | 596 | } |
3b2f2976 | 597 | |
532ac7d7 XL |
598 | macro_rules! lint_callback { ($cx:expr, $f:ident, $($args:expr),*) => ({ |
599 | $cx.pass.$f(&$cx.context, $($args),*); | |
600 | }) } | |
601 | ||
9fa01778 XL |
602 | macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({ |
603 | $cx.pass.$f(&$cx.context, $($args),*); | |
604 | }) } | |
605 | ||
606 | impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { | |
3b2f2976 | 607 | fn check_id(&mut self, id: ast::NodeId) { |
9fa01778 XL |
608 | for early_lint in self.context.buffered.take(id) { |
609 | self.context.lookup_and_emit_with_diagnostics( | |
610 | early_lint.lint_id.lint, | |
611 | Some(early_lint.span.clone()), | |
612 | &early_lint.msg, | |
613 | early_lint.diagnostic | |
614 | ); | |
b039eaaf SL |
615 | } |
616 | } | |
9fa01778 XL |
617 | |
618 | /// Merge the lints specified by any lint attributes into the | |
619 | /// current lint context, call the provided function, then reset the | |
620 | /// lints in effect to their previous state. | |
621 | fn with_lint_attrs<F>(&mut self, | |
622 | id: ast::NodeId, | |
623 | attrs: &'a [ast::Attribute], | |
624 | f: F) | |
625 | where F: FnOnce(&mut Self) | |
626 | { | |
e74abb32 | 627 | let push = self.context.builder.push(attrs, &self.context.lint_store); |
9fa01778 XL |
628 | self.check_id(id); |
629 | self.enter_attrs(attrs); | |
630 | f(self); | |
631 | self.exit_attrs(attrs); | |
632 | self.context.builder.pop(push); | |
633 | } | |
634 | ||
635 | fn enter_attrs(&mut self, attrs: &'a [ast::Attribute]) { | |
636 | debug!("early context: enter_attrs({:?})", attrs); | |
637 | run_early_pass!(self, enter_lint_attrs, attrs); | |
638 | } | |
639 | ||
640 | fn exit_attrs(&mut self, attrs: &'a [ast::Attribute]) { | |
641 | debug!("early context: exit_attrs({:?})", attrs); | |
642 | run_early_pass!(self, exit_lint_attrs, attrs); | |
643 | } | |
b039eaaf SL |
644 | } |
645 | ||
dc9dc135 | 646 | impl LintContext for LateContext<'_, '_> { |
7cac9316 XL |
647 | type PassObject = LateLintPassObject; |
648 | ||
9fa01778 | 649 | /// Gets the overall compiler `Session` object. |
b039eaaf SL |
650 | fn sess(&self) -> &Session { |
651 | &self.tcx.sess | |
652 | } | |
653 | ||
654 | fn lints(&self) -> &LintStore { | |
532ac7d7 | 655 | &*self.lint_store |
b039eaaf SL |
656 | } |
657 | ||
3b2f2976 XL |
658 | fn lookup<S: Into<MultiSpan>>(&self, |
659 | lint: &'static Lint, | |
660 | span: Option<S>, | |
661 | msg: &str) | |
0bf4aa26 | 662 | -> DiagnosticBuilder<'_> { |
9fa01778 XL |
663 | let hir_id = self.last_node_with_lint_attrs; |
664 | ||
3b2f2976 | 665 | match span { |
9fa01778 XL |
666 | Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, msg), |
667 | None => { | |
532ac7d7 | 668 | self.tcx.struct_lint_node(lint, hir_id, msg) |
9fa01778 | 669 | }, |
3b2f2976 XL |
670 | } |
671 | } | |
b039eaaf SL |
672 | } |
673 | ||
dc9dc135 | 674 | impl LintContext for EarlyContext<'_> { |
7cac9316 XL |
675 | type PassObject = EarlyLintPassObject; |
676 | ||
9fa01778 | 677 | /// Gets the overall compiler `Session` object. |
b039eaaf SL |
678 | fn sess(&self) -> &Session { |
679 | &self.sess | |
680 | } | |
681 | ||
682 | fn lints(&self) -> &LintStore { | |
532ac7d7 | 683 | &*self.lint_store |
b039eaaf SL |
684 | } |
685 | ||
3b2f2976 XL |
686 | fn lookup<S: Into<MultiSpan>>(&self, |
687 | lint: &'static Lint, | |
688 | span: Option<S>, | |
689 | msg: &str) | |
0bf4aa26 | 690 | -> DiagnosticBuilder<'_> { |
3b2f2976 XL |
691 | self.builder.struct_lint(lint, span.map(|s| s.into()), msg) |
692 | } | |
9fa01778 | 693 | } |
3b2f2976 | 694 | |
9fa01778 | 695 | impl<'a, 'tcx> LateContext<'a, 'tcx> { |
532ac7d7 XL |
696 | pub fn current_lint_root(&self) -> hir::HirId { |
697 | self.last_node_with_lint_attrs | |
698 | } | |
699 | ||
700 | /// Check if a `DefId`'s path matches the given absolute type path usage. | |
48663c56 | 701 | /// |
60c5eb7d XL |
702 | /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`; |
703 | /// inherent `impl` blocks are matched with the name of the type. | |
704 | /// | |
48663c56 XL |
705 | /// # Examples |
706 | /// | |
707 | /// ```rust,ignore (no context or def id available) | |
dc9dc135 | 708 | /// if cx.match_def_path(def_id, &[sym::core, sym::option, sym::Option]) { |
48663c56 XL |
709 | /// // The given `def_id` is that of an `Option` type |
710 | /// } | |
711 | /// ``` | |
dc9dc135 | 712 | pub fn match_def_path(&self, def_id: DefId, path: &[Symbol]) -> bool { |
48663c56 XL |
713 | let names = self.get_def_path(def_id); |
714 | ||
dc9dc135 | 715 | names.len() == path.len() && names.into_iter().zip(path.iter()).all(|(a, &b)| a == b) |
48663c56 XL |
716 | } |
717 | ||
dc9dc135 | 718 | /// Gets the absolute path of `def_id` as a vector of `Symbol`. |
48663c56 XL |
719 | /// |
720 | /// # Examples | |
721 | /// | |
722 | /// ```rust,ignore (no context or def id available) | |
723 | /// let def_path = cx.get_def_path(def_id); | |
dc9dc135 | 724 | /// if let &[sym::core, sym::option, sym::Option] = &def_path[..] { |
48663c56 XL |
725 | /// // The given `def_id` is that of an `Option` type |
726 | /// } | |
727 | /// ``` | |
dc9dc135 XL |
728 | pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> { |
729 | pub struct AbsolutePathPrinter<'tcx> { | |
730 | pub tcx: TyCtxt<'tcx>, | |
532ac7d7 XL |
731 | } |
732 | ||
dc9dc135 | 733 | impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { |
532ac7d7 XL |
734 | type Error = !; |
735 | ||
dc9dc135 | 736 | type Path = Vec<Symbol>; |
532ac7d7 XL |
737 | type Region = (); |
738 | type Type = (); | |
739 | type DynExistential = (); | |
dc9dc135 | 740 | type Const = (); |
532ac7d7 | 741 | |
dc9dc135 | 742 | fn tcx(&self) -> TyCtxt<'tcx> { |
532ac7d7 XL |
743 | self.tcx |
744 | } | |
745 | ||
746 | fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { | |
747 | Ok(()) | |
748 | } | |
749 | ||
750 | fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { | |
751 | Ok(()) | |
752 | } | |
753 | ||
754 | fn print_dyn_existential( | |
755 | self, | |
756 | _predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, | |
dc9dc135 XL |
757 | ) -> Result<Self::DynExistential, Self::Error> { |
758 | Ok(()) | |
759 | } | |
760 | ||
761 | fn print_const( | |
762 | self, | |
763 | _ct: &'tcx ty::Const<'tcx>, | |
764 | ) -> Result<Self::Const, Self::Error> { | |
532ac7d7 XL |
765 | Ok(()) |
766 | } | |
767 | ||
768 | fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { | |
dc9dc135 | 769 | Ok(vec![self.tcx.original_crate_name(cnum)]) |
532ac7d7 XL |
770 | } |
771 | ||
772 | fn path_qualified( | |
773 | self, | |
774 | self_ty: Ty<'tcx>, | |
775 | trait_ref: Option<ty::TraitRef<'tcx>>, | |
dc9dc135 | 776 | ) -> Result<Self::Path, Self::Error> { |
532ac7d7 | 777 | if trait_ref.is_none() { |
e74abb32 | 778 | if let ty::Adt(def, substs) = self_ty.kind { |
532ac7d7 XL |
779 | return self.print_def_path(def.did, substs); |
780 | } | |
781 | } | |
782 | ||
783 | // This shouldn't ever be needed, but just in case: | |
784 | Ok(vec![match trait_ref { | |
dc9dc135 XL |
785 | Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)), |
786 | None => Symbol::intern(&format!("<{}>", self_ty)), | |
532ac7d7 XL |
787 | }]) |
788 | } | |
789 | ||
790 | fn path_append_impl( | |
791 | self, | |
792 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
793 | _disambiguated_data: &DisambiguatedDefPathData, | |
794 | self_ty: Ty<'tcx>, | |
795 | trait_ref: Option<ty::TraitRef<'tcx>>, | |
dc9dc135 | 796 | ) -> Result<Self::Path, Self::Error> { |
532ac7d7 XL |
797 | let mut path = print_prefix(self)?; |
798 | ||
799 | // This shouldn't ever be needed, but just in case: | |
800 | path.push(match trait_ref { | |
801 | Some(trait_ref) => { | |
60c5eb7d XL |
802 | Symbol::intern( |
803 | &format!( | |
804 | "<impl {} for {}>", | |
805 | trait_ref.print_only_trait_path(), | |
806 | self_ty | |
807 | ) | |
808 | ) | |
532ac7d7 | 809 | }, |
dc9dc135 | 810 | None => Symbol::intern(&format!("<impl {}>", self_ty)), |
532ac7d7 XL |
811 | }); |
812 | ||
813 | Ok(path) | |
814 | } | |
815 | ||
816 | fn path_append( | |
817 | self, | |
818 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
819 | disambiguated_data: &DisambiguatedDefPathData, | |
dc9dc135 | 820 | ) -> Result<Self::Path, Self::Error> { |
532ac7d7 XL |
821 | let mut path = print_prefix(self)?; |
822 | ||
823 | // Skip `::{{constructor}}` on tuple/unit structs. | |
824 | match disambiguated_data.data { | |
825 | DefPathData::Ctor => return Ok(path), | |
826 | _ => {} | |
827 | } | |
828 | ||
e74abb32 | 829 | path.push(disambiguated_data.data.as_symbol()); |
532ac7d7 XL |
830 | Ok(path) |
831 | } | |
832 | ||
833 | fn path_generic_args( | |
834 | self, | |
835 | print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, | |
e74abb32 | 836 | _args: &[GenericArg<'tcx>], |
dc9dc135 | 837 | ) -> Result<Self::Path, Self::Error> { |
532ac7d7 XL |
838 | print_prefix(self) |
839 | } | |
840 | } | |
841 | ||
48663c56 XL |
842 | AbsolutePathPrinter { tcx: self.tcx } |
843 | .print_def_path(def_id, &[]) | |
844 | .unwrap() | |
532ac7d7 XL |
845 | } |
846 | } | |
847 | ||
848 | impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> { | |
849 | type Ty = Ty<'tcx>; | |
850 | type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>; | |
851 | ||
852 | fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout { | |
853 | self.tcx.layout_of(self.param_env.and(ty)) | |
854 | } | |
855 | } | |
856 | ||
857 | impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> LateContextAndPass<'a, 'tcx, T> { | |
9fa01778 XL |
858 | /// Merge the lints specified by any lint attributes into the |
859 | /// current lint context, call the provided function, then reset the | |
860 | /// lints in effect to their previous state. | |
3b2f2976 | 861 | fn with_lint_attrs<F>(&mut self, |
9fa01778 XL |
862 | id: hir::HirId, |
863 | attrs: &'tcx [ast::Attribute], | |
3b2f2976 XL |
864 | f: F) |
865 | where F: FnOnce(&mut Self) | |
866 | { | |
532ac7d7 XL |
867 | let prev = self.context.last_node_with_lint_attrs; |
868 | self.context.last_node_with_lint_attrs = id; | |
3b2f2976 XL |
869 | self.enter_attrs(attrs); |
870 | f(self); | |
871 | self.exit_attrs(attrs); | |
532ac7d7 | 872 | self.context.last_node_with_lint_attrs = prev; |
9fa01778 XL |
873 | } |
874 | ||
532ac7d7 | 875 | fn with_param_env<F>(&mut self, id: hir::HirId, f: F) |
041b39d2 XL |
876 | where F: FnOnce(&mut Self), |
877 | { | |
532ac7d7 XL |
878 | let old_param_env = self.context.param_env; |
879 | self.context.param_env = self.context.tcx.param_env( | |
416331ca | 880 | self.context.tcx.hir().local_def_id(id) |
532ac7d7 | 881 | ); |
041b39d2 | 882 | f(self); |
532ac7d7 | 883 | self.context.param_env = old_param_env; |
041b39d2 | 884 | } |
532ac7d7 XL |
885 | |
886 | fn process_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: hir::HirId) { | |
887 | lint_callback!(self, check_mod, m, s, n); | |
888 | hir_visit::walk_mod(self, m, n); | |
889 | lint_callback!(self, check_mod_post, m, s, n); | |
94b46f34 | 890 | } |
041b39d2 | 891 | |
532ac7d7 XL |
892 | fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) { |
893 | debug!("late context: enter_attrs({:?})", attrs); | |
894 | lint_callback!(self, enter_lint_attrs, attrs); | |
895 | } | |
ff7c6d11 | 896 | |
532ac7d7 XL |
897 | fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) { |
898 | debug!("late context: exit_attrs({:?})", attrs); | |
899 | lint_callback!(self, exit_lint_attrs, attrs); | |
ff7c6d11 XL |
900 | } |
901 | } | |
902 | ||
532ac7d7 XL |
903 | impl<'a, 'tcx, T: LateLintPass<'a, 'tcx>> hir_visit::Visitor<'tcx> |
904 | for LateContextAndPass<'a, 'tcx, T> { | |
92a42be0 SL |
905 | /// Because lints are scoped lexically, we want to walk nested |
906 | /// items in the context of the outer item, so enable | |
907 | /// deep-walking. | |
476ff2be | 908 | fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'tcx> { |
532ac7d7 | 909 | hir_visit::NestedVisitorMap::All(&self.context.tcx.hir()) |
32a655c1 SL |
910 | } |
911 | ||
32a655c1 | 912 | fn visit_nested_body(&mut self, body: hir::BodyId) { |
532ac7d7 XL |
913 | let old_tables = self.context.tables; |
914 | self.context.tables = self.context.tcx.body_tables(body); | |
915 | let body = self.context.tcx.hir().body(body); | |
32a655c1 | 916 | self.visit_body(body); |
532ac7d7 | 917 | self.context.tables = old_tables; |
92a42be0 SL |
918 | } |
919 | ||
e1599b0c XL |
920 | fn visit_param(&mut self, param: &'tcx hir::Param) { |
921 | self.with_lint_attrs(param.hir_id, ¶m.attrs, |cx| { | |
922 | lint_callback!(cx, check_param, param); | |
923 | hir_visit::walk_param(cx, param); | |
416331ca XL |
924 | }); |
925 | } | |
926 | ||
8bb4bdeb | 927 | fn visit_body(&mut self, body: &'tcx hir::Body) { |
532ac7d7 | 928 | lint_callback!(self, check_body, body); |
8bb4bdeb | 929 | hir_visit::walk_body(self, body); |
532ac7d7 | 930 | lint_callback!(self, check_body_post, body); |
8bb4bdeb XL |
931 | } |
932 | ||
476ff2be | 933 | fn visit_item(&mut self, it: &'tcx hir::Item) { |
532ac7d7 | 934 | let generics = self.context.generics.take(); |
e74abb32 | 935 | self.context.generics = it.kind.generics(); |
9fa01778 | 936 | self.with_lint_attrs(it.hir_id, &it.attrs, |cx| { |
532ac7d7 XL |
937 | cx.with_param_env(it.hir_id, |cx| { |
938 | lint_callback!(cx, check_item, it); | |
041b39d2 | 939 | hir_visit::walk_item(cx, it); |
532ac7d7 | 940 | lint_callback!(cx, check_item_post, it); |
041b39d2 | 941 | }); |
abe05a73 | 942 | }); |
532ac7d7 | 943 | self.context.generics = generics; |
1a4d82fc JJ |
944 | } |
945 | ||
476ff2be | 946 | fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) { |
9fa01778 | 947 | self.with_lint_attrs(it.hir_id, &it.attrs, |cx| { |
532ac7d7 XL |
948 | cx.with_param_env(it.hir_id, |cx| { |
949 | lint_callback!(cx, check_foreign_item, it); | |
041b39d2 | 950 | hir_visit::walk_foreign_item(cx, it); |
532ac7d7 | 951 | lint_callback!(cx, check_foreign_item_post, it); |
041b39d2 | 952 | }); |
1a4d82fc JJ |
953 | }) |
954 | } | |
955 | ||
476ff2be | 956 | fn visit_pat(&mut self, p: &'tcx hir::Pat) { |
532ac7d7 | 957 | lint_callback!(self, check_pat, p); |
b039eaaf | 958 | hir_visit::walk_pat(self, p); |
1a4d82fc JJ |
959 | } |
960 | ||
476ff2be | 961 | fn visit_expr(&mut self, e: &'tcx hir::Expr) { |
9fa01778 | 962 | self.with_lint_attrs(e.hir_id, &e.attrs, |cx| { |
532ac7d7 | 963 | lint_callback!(cx, check_expr, e); |
92a42be0 | 964 | hir_visit::walk_expr(cx, e); |
532ac7d7 | 965 | lint_callback!(cx, check_expr_post, e); |
92a42be0 | 966 | }) |
1a4d82fc JJ |
967 | } |
968 | ||
476ff2be | 969 | fn visit_stmt(&mut self, s: &'tcx hir::Stmt) { |
92a42be0 SL |
970 | // statement attributes are actually just attributes on one of |
971 | // - item | |
972 | // - local | |
973 | // - expression | |
974 | // so we keep track of lint levels there | |
532ac7d7 | 975 | lint_callback!(self, check_stmt, s); |
b039eaaf | 976 | hir_visit::walk_stmt(self, s); |
1a4d82fc JJ |
977 | } |
978 | ||
476ff2be | 979 | fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl, |
9fa01778 | 980 | body_id: hir::BodyId, span: Span, id: hir::HirId) { |
32a655c1 SL |
981 | // Wrap in tables here, not just in visit_nested_body, |
982 | // in order for `check_fn` to be able to use them. | |
532ac7d7 XL |
983 | let old_tables = self.context.tables; |
984 | self.context.tables = self.context.tcx.body_tables(body_id); | |
985 | let body = self.context.tcx.hir().body(body_id); | |
986 | lint_callback!(self, check_fn, fk, decl, body, span, id); | |
476ff2be | 987 | hir_visit::walk_fn(self, fk, decl, body_id, span, id); |
532ac7d7 XL |
988 | lint_callback!(self, check_fn_post, fk, decl, body, span, id); |
989 | self.context.tables = old_tables; | |
1a4d82fc JJ |
990 | } |
991 | ||
b039eaaf | 992 | fn visit_variant_data(&mut self, |
476ff2be | 993 | s: &'tcx hir::VariantData, |
e1599b0c XL |
994 | _: ast::Name, |
995 | _: &'tcx hir::Generics, | |
996 | _: hir::HirId, | |
b039eaaf | 997 | _: Span) { |
e1599b0c | 998 | lint_callback!(self, check_struct_def, s); |
b039eaaf | 999 | hir_visit::walk_struct_def(self, s); |
e1599b0c | 1000 | lint_callback!(self, check_struct_def_post, s); |
1a4d82fc JJ |
1001 | } |
1002 | ||
476ff2be | 1003 | fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { |
9fa01778 | 1004 | self.with_lint_attrs(s.hir_id, &s.attrs, |cx| { |
532ac7d7 | 1005 | lint_callback!(cx, check_struct_field, s); |
b039eaaf | 1006 | hir_visit::walk_struct_field(cx, s); |
1a4d82fc JJ |
1007 | }) |
1008 | } | |
1009 | ||
476ff2be SL |
1010 | fn visit_variant(&mut self, |
1011 | v: &'tcx hir::Variant, | |
1012 | g: &'tcx hir::Generics, | |
9fa01778 | 1013 | item_id: hir::HirId) { |
e1599b0c XL |
1014 | self.with_lint_attrs(v.id, &v.attrs, |cx| { |
1015 | lint_callback!(cx, check_variant, v); | |
b039eaaf | 1016 | hir_visit::walk_variant(cx, v, g, item_id); |
e1599b0c | 1017 | lint_callback!(cx, check_variant_post, v); |
1a4d82fc JJ |
1018 | }) |
1019 | } | |
1020 | ||
476ff2be | 1021 | fn visit_ty(&mut self, t: &'tcx hir::Ty) { |
532ac7d7 | 1022 | lint_callback!(self, check_ty, t); |
b039eaaf | 1023 | hir_visit::walk_ty(self, t); |
1a4d82fc JJ |
1024 | } |
1025 | ||
b039eaaf | 1026 | fn visit_name(&mut self, sp: Span, name: ast::Name) { |
532ac7d7 | 1027 | lint_callback!(self, check_name, sp, name); |
1a4d82fc JJ |
1028 | } |
1029 | ||
9fa01778 | 1030 | fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: hir::HirId) { |
532ac7d7 XL |
1031 | if !self.context.only_module { |
1032 | self.process_mod(m, s, n); | |
1033 | } | |
1a4d82fc JJ |
1034 | } |
1035 | ||
476ff2be | 1036 | fn visit_local(&mut self, l: &'tcx hir::Local) { |
9fa01778 | 1037 | self.with_lint_attrs(l.hir_id, &l.attrs, |cx| { |
532ac7d7 | 1038 | lint_callback!(cx, check_local, l); |
92a42be0 SL |
1039 | hir_visit::walk_local(cx, l); |
1040 | }) | |
1a4d82fc JJ |
1041 | } |
1042 | ||
476ff2be | 1043 | fn visit_block(&mut self, b: &'tcx hir::Block) { |
532ac7d7 | 1044 | lint_callback!(self, check_block, b); |
b039eaaf | 1045 | hir_visit::walk_block(self, b); |
532ac7d7 | 1046 | lint_callback!(self, check_block_post, b); |
1a4d82fc JJ |
1047 | } |
1048 | ||
476ff2be | 1049 | fn visit_arm(&mut self, a: &'tcx hir::Arm) { |
532ac7d7 | 1050 | lint_callback!(self, check_arm, a); |
b039eaaf | 1051 | hir_visit::walk_arm(self, a); |
1a4d82fc JJ |
1052 | } |
1053 | ||
ff7c6d11 | 1054 | fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) { |
532ac7d7 | 1055 | lint_callback!(self, check_generic_param, p); |
ff7c6d11 XL |
1056 | hir_visit::walk_generic_param(self, p); |
1057 | } | |
1058 | ||
476ff2be | 1059 | fn visit_generics(&mut self, g: &'tcx hir::Generics) { |
532ac7d7 | 1060 | lint_callback!(self, check_generics, g); |
b039eaaf | 1061 | hir_visit::walk_generics(self, g); |
1a4d82fc JJ |
1062 | } |
1063 | ||
0531ce1d | 1064 | fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate) { |
532ac7d7 | 1065 | lint_callback!(self, check_where_predicate, p); |
0531ce1d XL |
1066 | hir_visit::walk_where_predicate(self, p); |
1067 | } | |
1068 | ||
1069 | fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef, | |
1070 | m: hir::TraitBoundModifier) { | |
532ac7d7 | 1071 | lint_callback!(self, check_poly_trait_ref, t, m); |
0531ce1d XL |
1072 | hir_visit::walk_poly_trait_ref(self, t, m); |
1073 | } | |
1074 | ||
476ff2be | 1075 | fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { |
532ac7d7 XL |
1076 | let generics = self.context.generics.take(); |
1077 | self.context.generics = Some(&trait_item.generics); | |
9fa01778 | 1078 | self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |cx| { |
532ac7d7 XL |
1079 | cx.with_param_env(trait_item.hir_id, |cx| { |
1080 | lint_callback!(cx, check_trait_item, trait_item); | |
041b39d2 | 1081 | hir_visit::walk_trait_item(cx, trait_item); |
532ac7d7 | 1082 | lint_callback!(cx, check_trait_item_post, trait_item); |
041b39d2 | 1083 | }); |
c34b1796 | 1084 | }); |
532ac7d7 | 1085 | self.context.generics = generics; |
c34b1796 AL |
1086 | } |
1087 | ||
476ff2be | 1088 | fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { |
532ac7d7 XL |
1089 | let generics = self.context.generics.take(); |
1090 | self.context.generics = Some(&impl_item.generics); | |
9fa01778 | 1091 | self.with_lint_attrs(impl_item.hir_id, &impl_item.attrs, |cx| { |
532ac7d7 XL |
1092 | cx.with_param_env(impl_item.hir_id, |cx| { |
1093 | lint_callback!(cx, check_impl_item, impl_item); | |
041b39d2 | 1094 | hir_visit::walk_impl_item(cx, impl_item); |
532ac7d7 | 1095 | lint_callback!(cx, check_impl_item_post, impl_item); |
041b39d2 | 1096 | }); |
c34b1796 | 1097 | }); |
532ac7d7 | 1098 | self.context.generics = generics; |
1a4d82fc JJ |
1099 | } |
1100 | ||
476ff2be | 1101 | fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { |
532ac7d7 | 1102 | lint_callback!(self, check_lifetime, lt); |
32a655c1 | 1103 | hir_visit::walk_lifetime(self, lt); |
1a4d82fc JJ |
1104 | } |
1105 | ||
b7449926 | 1106 | fn visit_path(&mut self, p: &'tcx hir::Path, id: hir::HirId) { |
532ac7d7 | 1107 | lint_callback!(self, check_path, p, id); |
b039eaaf SL |
1108 | hir_visit::walk_path(self, p); |
1109 | } | |
1110 | ||
476ff2be | 1111 | fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) { |
532ac7d7 | 1112 | lint_callback!(self, check_attribute, attr); |
b039eaaf SL |
1113 | } |
1114 | } | |
1115 | ||
9fa01778 | 1116 | impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> { |
e1599b0c XL |
1117 | fn visit_param(&mut self, param: &'a ast::Param) { |
1118 | self.with_lint_attrs(param.id, ¶m.attrs, |cx| { | |
1119 | run_early_pass!(cx, check_param, param); | |
1120 | ast_visit::walk_param(cx, param); | |
416331ca XL |
1121 | }); |
1122 | } | |
1123 | ||
476ff2be | 1124 | fn visit_item(&mut self, it: &'a ast::Item) { |
3b2f2976 | 1125 | self.with_lint_attrs(it.id, &it.attrs, |cx| { |
9fa01778 | 1126 | run_early_pass!(cx, check_item, it); |
b039eaaf | 1127 | ast_visit::walk_item(cx, it); |
9fa01778 | 1128 | run_early_pass!(cx, check_item_post, it); |
b039eaaf SL |
1129 | }) |
1130 | } | |
1131 | ||
476ff2be | 1132 | fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) { |
3b2f2976 | 1133 | self.with_lint_attrs(it.id, &it.attrs, |cx| { |
9fa01778 | 1134 | run_early_pass!(cx, check_foreign_item, it); |
b039eaaf | 1135 | ast_visit::walk_foreign_item(cx, it); |
9fa01778 | 1136 | run_early_pass!(cx, check_foreign_item_post, it); |
b039eaaf SL |
1137 | }) |
1138 | } | |
1139 | ||
476ff2be | 1140 | fn visit_pat(&mut self, p: &'a ast::Pat) { |
48663c56 | 1141 | run_early_pass!(self, check_pat, p); |
3b2f2976 | 1142 | self.check_id(p.id); |
48663c56 XL |
1143 | ast_visit::walk_pat(self, p); |
1144 | run_early_pass!(self, check_pat_post, p); | |
b039eaaf SL |
1145 | } |
1146 | ||
476ff2be | 1147 | fn visit_expr(&mut self, e: &'a ast::Expr) { |
3b2f2976 | 1148 | self.with_lint_attrs(e.id, &e.attrs, |cx| { |
9fa01778 | 1149 | run_early_pass!(cx, check_expr, e); |
7453a54e SL |
1150 | ast_visit::walk_expr(cx, e); |
1151 | }) | |
b039eaaf SL |
1152 | } |
1153 | ||
476ff2be | 1154 | fn visit_stmt(&mut self, s: &'a ast::Stmt) { |
9fa01778 | 1155 | run_early_pass!(self, check_stmt, s); |
3b2f2976 | 1156 | self.check_id(s.id); |
b039eaaf SL |
1157 | ast_visit::walk_stmt(self, s); |
1158 | } | |
1159 | ||
476ff2be SL |
1160 | fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, decl: &'a ast::FnDecl, |
1161 | span: Span, id: ast::NodeId) { | |
9fa01778 | 1162 | run_early_pass!(self, check_fn, fk, decl, span, id); |
3b2f2976 | 1163 | self.check_id(id); |
476ff2be | 1164 | ast_visit::walk_fn(self, fk, decl, span); |
9fa01778 | 1165 | run_early_pass!(self, check_fn_post, fk, decl, span, id); |
b039eaaf SL |
1166 | } |
1167 | ||
e1599b0c XL |
1168 | fn visit_variant_data(&mut self, s: &'a ast::VariantData) { |
1169 | run_early_pass!(self, check_struct_def, s); | |
532ac7d7 XL |
1170 | if let Some(ctor_hir_id) = s.ctor_id() { |
1171 | self.check_id(ctor_hir_id); | |
1172 | } | |
b039eaaf | 1173 | ast_visit::walk_struct_def(self, s); |
e1599b0c | 1174 | run_early_pass!(self, check_struct_def_post, s); |
b039eaaf SL |
1175 | } |
1176 | ||
476ff2be | 1177 | fn visit_struct_field(&mut self, s: &'a ast::StructField) { |
3b2f2976 | 1178 | self.with_lint_attrs(s.id, &s.attrs, |cx| { |
9fa01778 | 1179 | run_early_pass!(cx, check_struct_field, s); |
b039eaaf SL |
1180 | ast_visit::walk_struct_field(cx, s); |
1181 | }) | |
1182 | } | |
1183 | ||
e1599b0c XL |
1184 | fn visit_variant(&mut self, v: &'a ast::Variant) { |
1185 | self.with_lint_attrs(v.id, &v.attrs, |cx| { | |
1186 | run_early_pass!(cx, check_variant, v); | |
1187 | ast_visit::walk_variant(cx, v); | |
1188 | run_early_pass!(cx, check_variant_post, v); | |
b039eaaf SL |
1189 | }) |
1190 | } | |
1191 | ||
476ff2be | 1192 | fn visit_ty(&mut self, t: &'a ast::Ty) { |
9fa01778 | 1193 | run_early_pass!(self, check_ty, t); |
3b2f2976 | 1194 | self.check_id(t.id); |
b039eaaf SL |
1195 | ast_visit::walk_ty(self, t); |
1196 | } | |
1197 | ||
83c7162d | 1198 | fn visit_ident(&mut self, ident: ast::Ident) { |
9fa01778 | 1199 | run_early_pass!(self, check_ident, ident); |
b039eaaf SL |
1200 | } |
1201 | ||
7cac9316 | 1202 | fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) { |
9fa01778 | 1203 | run_early_pass!(self, check_mod, m, s, n); |
3b2f2976 | 1204 | self.check_id(n); |
b039eaaf | 1205 | ast_visit::walk_mod(self, m); |
9fa01778 | 1206 | run_early_pass!(self, check_mod_post, m, s, n); |
b039eaaf SL |
1207 | } |
1208 | ||
476ff2be | 1209 | fn visit_local(&mut self, l: &'a ast::Local) { |
3b2f2976 | 1210 | self.with_lint_attrs(l.id, &l.attrs, |cx| { |
9fa01778 | 1211 | run_early_pass!(cx, check_local, l); |
7453a54e SL |
1212 | ast_visit::walk_local(cx, l); |
1213 | }) | |
b039eaaf SL |
1214 | } |
1215 | ||
476ff2be | 1216 | fn visit_block(&mut self, b: &'a ast::Block) { |
9fa01778 | 1217 | run_early_pass!(self, check_block, b); |
3b2f2976 | 1218 | self.check_id(b.id); |
b039eaaf | 1219 | ast_visit::walk_block(self, b); |
9fa01778 | 1220 | run_early_pass!(self, check_block_post, b); |
b039eaaf SL |
1221 | } |
1222 | ||
476ff2be | 1223 | fn visit_arm(&mut self, a: &'a ast::Arm) { |
9fa01778 | 1224 | run_early_pass!(self, check_arm, a); |
b039eaaf SL |
1225 | ast_visit::walk_arm(self, a); |
1226 | } | |
1227 | ||
476ff2be | 1228 | fn visit_expr_post(&mut self, e: &'a ast::Expr) { |
9fa01778 | 1229 | run_early_pass!(self, check_expr_post, e); |
b039eaaf SL |
1230 | } |
1231 | ||
ff7c6d11 | 1232 | fn visit_generic_param(&mut self, param: &'a ast::GenericParam) { |
9fa01778 | 1233 | run_early_pass!(self, check_generic_param, param); |
ff7c6d11 XL |
1234 | ast_visit::walk_generic_param(self, param); |
1235 | } | |
1236 | ||
476ff2be | 1237 | fn visit_generics(&mut self, g: &'a ast::Generics) { |
9fa01778 | 1238 | run_early_pass!(self, check_generics, g); |
b039eaaf SL |
1239 | ast_visit::walk_generics(self, g); |
1240 | } | |
1241 | ||
0531ce1d | 1242 | fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) { |
9fa01778 | 1243 | run_early_pass!(self, check_where_predicate, p); |
0531ce1d XL |
1244 | ast_visit::walk_where_predicate(self, p); |
1245 | } | |
1246 | ||
1247 | fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef, m: &'a ast::TraitBoundModifier) { | |
9fa01778 | 1248 | run_early_pass!(self, check_poly_trait_ref, t, m); |
0531ce1d XL |
1249 | ast_visit::walk_poly_trait_ref(self, t, m); |
1250 | } | |
1251 | ||
476ff2be | 1252 | fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) { |
3b2f2976 | 1253 | self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| { |
9fa01778 | 1254 | run_early_pass!(cx, check_trait_item, trait_item); |
b039eaaf | 1255 | ast_visit::walk_trait_item(cx, trait_item); |
9fa01778 | 1256 | run_early_pass!(cx, check_trait_item_post, trait_item); |
b039eaaf SL |
1257 | }); |
1258 | } | |
1259 | ||
476ff2be | 1260 | fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) { |
3b2f2976 | 1261 | self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| { |
9fa01778 | 1262 | run_early_pass!(cx, check_impl_item, impl_item); |
b039eaaf | 1263 | ast_visit::walk_impl_item(cx, impl_item); |
9fa01778 | 1264 | run_early_pass!(cx, check_impl_item_post, impl_item); |
b039eaaf SL |
1265 | }); |
1266 | } | |
1267 | ||
476ff2be | 1268 | fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) { |
9fa01778 | 1269 | run_early_pass!(self, check_lifetime, lt); |
3b2f2976 | 1270 | self.check_id(lt.id); |
b039eaaf SL |
1271 | } |
1272 | ||
476ff2be | 1273 | fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) { |
9fa01778 | 1274 | run_early_pass!(self, check_path, p, id); |
3b2f2976 | 1275 | self.check_id(id); |
b039eaaf SL |
1276 | ast_visit::walk_path(self, p); |
1277 | } | |
1278 | ||
476ff2be | 1279 | fn visit_attribute(&mut self, attr: &'a ast::Attribute) { |
9fa01778 | 1280 | run_early_pass!(self, check_attribute, attr); |
1a4d82fc | 1281 | } |
7cac9316 | 1282 | |
8faf50e0 | 1283 | fn visit_mac_def(&mut self, mac: &'a ast::MacroDef, id: ast::NodeId) { |
9fa01778 | 1284 | run_early_pass!(self, check_mac_def, mac, id); |
3b2f2976 | 1285 | self.check_id(id); |
92a42be0 | 1286 | } |
8faf50e0 | 1287 | |
b7449926 XL |
1288 | fn visit_mac(&mut self, mac: &'a ast::Mac) { |
1289 | // FIXME(#54110): So, this setup isn't really right. I think | |
1290 | // that (a) the libsyntax visitor ought to be doing this as | |
1291 | // part of `walk_mac`, and (b) we should be calling | |
1292 | // `visit_path`, *but* that would require a `NodeId`, and I | |
1293 | // want to get #53686 fixed quickly. -nmatsakis | |
e1599b0c | 1294 | ast_visit::walk_path(self, &mac.path); |
b7449926 | 1295 | |
9fa01778 | 1296 | run_early_pass!(self, check_mac, mac); |
8faf50e0 | 1297 | } |
92a42be0 SL |
1298 | } |
1299 | ||
532ac7d7 XL |
1300 | struct LateLintPassObjects<'a> { |
1301 | lints: &'a mut [LateLintPassObject], | |
1302 | } | |
92a42be0 | 1303 | |
e1599b0c | 1304 | #[allow(rustc::lint_pass_impl_without_macro)] |
532ac7d7 XL |
1305 | impl LintPass for LateLintPassObjects<'_> { |
1306 | fn name(&self) -> &'static str { | |
1307 | panic!() | |
1308 | } | |
532ac7d7 XL |
1309 | } |
1310 | ||
1311 | macro_rules! expand_late_lint_pass_impl_methods { | |
1312 | ([$a:tt, $hir:tt], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( | |
1313 | $(fn $name(&mut self, context: &LateContext<$a, $hir>, $($param: $arg),*) { | |
1314 | for obj in self.lints.iter_mut() { | |
1315 | obj.$name(context, $($param),*); | |
1316 | } | |
1317 | })* | |
1318 | ) | |
1319 | } | |
1320 | ||
1321 | macro_rules! late_lint_pass_impl { | |
1322 | ([], [$hir:tt], $methods:tt) => ( | |
1323 | impl LateLintPass<'a, $hir> for LateLintPassObjects<'_> { | |
1324 | expand_late_lint_pass_impl_methods!(['a, $hir], $methods); | |
1325 | } | |
1326 | ) | |
1327 | } | |
1328 | ||
1329 | late_lint_methods!(late_lint_pass_impl, [], ['tcx]); | |
1330 | ||
1331 | fn late_lint_mod_pass<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>( | |
dc9dc135 | 1332 | tcx: TyCtxt<'tcx>, |
532ac7d7 XL |
1333 | module_def_id: DefId, |
1334 | pass: T, | |
1335 | ) { | |
7cac9316 | 1336 | let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); |
cc61c64b | 1337 | |
532ac7d7 XL |
1338 | let context = LateContext { |
1339 | tcx, | |
1340 | tables: &ty::TypeckTables::empty(None), | |
1341 | param_env: ty::ParamEnv::empty(), | |
1342 | access_levels, | |
e74abb32 | 1343 | lint_store: &tcx.lint_store, |
532ac7d7 XL |
1344 | last_node_with_lint_attrs: tcx.hir().as_local_hir_id(module_def_id).unwrap(), |
1345 | generics: None, | |
1346 | only_module: true, | |
1347 | }; | |
32a655c1 | 1348 | |
532ac7d7 XL |
1349 | let mut cx = LateContextAndPass { |
1350 | context, | |
1351 | pass | |
1352 | }; | |
1a4d82fc | 1353 | |
532ac7d7 XL |
1354 | let (module, span, hir_id) = tcx.hir().get_module(module_def_id); |
1355 | cx.process_mod(module, span, hir_id); | |
7453a54e | 1356 | |
532ac7d7 XL |
1357 | // Visit the crate attributes |
1358 | if hir_id == hir::CRATE_HIR_ID { | |
dc9dc135 | 1359 | walk_list!(cx, visit_attribute, tcx.hir().attrs(hir::CRATE_HIR_ID)); |
532ac7d7 XL |
1360 | } |
1361 | } | |
1362 | ||
1363 | pub fn late_lint_mod<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>( | |
dc9dc135 | 1364 | tcx: TyCtxt<'tcx>, |
532ac7d7 XL |
1365 | module_def_id: DefId, |
1366 | builtin_lints: T, | |
1367 | ) { | |
1368 | if tcx.sess.opts.debugging_opts.no_interleave_lints { | |
1369 | // These passes runs in late_lint_crate with -Z no_interleave_lints | |
1370 | return; | |
1371 | } | |
1372 | ||
1373 | late_lint_mod_pass(tcx, module_def_id, builtin_lints); | |
1374 | ||
e74abb32 XL |
1375 | let mut passes: Vec<_> = tcx.lint_store.late_module_passes |
1376 | .iter().map(|pass| (pass)()).collect(); | |
532ac7d7 XL |
1377 | |
1378 | if !passes.is_empty() { | |
1379 | late_lint_mod_pass(tcx, module_def_id, LateLintPassObjects { lints: &mut passes[..] }); | |
1380 | } | |
1381 | } | |
1382 | ||
dc9dc135 | 1383 | fn late_lint_pass_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, pass: T) { |
532ac7d7 XL |
1384 | let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); |
1385 | ||
1386 | let krate = tcx.hir().krate(); | |
1387 | ||
1388 | let context = LateContext { | |
1389 | tcx, | |
1390 | tables: &ty::TypeckTables::empty(None), | |
1391 | param_env: ty::ParamEnv::empty(), | |
1392 | access_levels, | |
e74abb32 | 1393 | lint_store: &tcx.lint_store, |
532ac7d7 XL |
1394 | last_node_with_lint_attrs: hir::CRATE_HIR_ID, |
1395 | generics: None, | |
1396 | only_module: false, | |
1397 | }; | |
1398 | ||
1399 | let mut cx = LateContextAndPass { | |
1400 | context, | |
1401 | pass | |
8faf50e0 | 1402 | }; |
1a4d82fc | 1403 | |
532ac7d7 XL |
1404 | // Visit the whole crate. |
1405 | cx.with_lint_attrs(hir::CRATE_HIR_ID, &krate.attrs, |cx| { | |
1406 | // since the root module isn't visited as an item (because it isn't an | |
1407 | // item), warn for it here. | |
1408 | lint_callback!(cx, check_crate, krate); | |
1409 | ||
1410 | hir_visit::walk_crate(cx, krate); | |
1411 | ||
1412 | lint_callback!(cx, check_crate_post, krate); | |
1413 | }) | |
1414 | } | |
1415 | ||
dc9dc135 | 1416 | fn late_lint_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>(tcx: TyCtxt<'tcx>, builtin_lints: T) { |
e74abb32 XL |
1417 | let mut passes = tcx.lint_store |
1418 | .late_passes.iter().map(|p| (p)()).collect::<Vec<_>>(); | |
532ac7d7 XL |
1419 | |
1420 | if !tcx.sess.opts.debugging_opts.no_interleave_lints { | |
1421 | if !passes.is_empty() { | |
1422 | late_lint_pass_crate(tcx, LateLintPassObjects { lints: &mut passes[..] }); | |
1423 | } | |
1424 | ||
1425 | late_lint_pass_crate(tcx, builtin_lints); | |
1426 | } else { | |
1427 | for pass in &mut passes { | |
1428 | time(tcx.sess, &format!("running late lint: {}", pass.name()), || { | |
1429 | late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) }); | |
1430 | }); | |
1431 | } | |
1432 | ||
e74abb32 XL |
1433 | let mut passes: Vec<_> = tcx.lint_store.late_module_passes |
1434 | .iter().map(|pass| (pass)()).collect(); | |
532ac7d7 XL |
1435 | |
1436 | for pass in &mut passes { | |
1437 | time(tcx.sess, &format!("running late module lint: {}", pass.name()), || { | |
1438 | late_lint_pass_crate(tcx, LateLintPassObjects { lints: slice::from_mut(pass) }); | |
1439 | }); | |
1440 | } | |
1441 | } | |
532ac7d7 XL |
1442 | } |
1443 | ||
1444 | /// Performs lint checking on a crate. | |
1445 | pub fn check_crate<'tcx, T: for<'a> LateLintPass<'a, 'tcx>>( | |
dc9dc135 | 1446 | tcx: TyCtxt<'tcx>, |
532ac7d7 XL |
1447 | builtin_lints: impl FnOnce() -> T + Send, |
1448 | ) { | |
1449 | join(|| { | |
1450 | time(tcx.sess, "crate lints", || { | |
1451 | // Run whole crate non-incremental lints | |
1452 | late_lint_crate(tcx, builtin_lints()); | |
1453 | }); | |
1454 | }, || { | |
1455 | time(tcx.sess, "module lints", || { | |
1456 | // Run per-module lints | |
1457 | par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| { | |
e74abb32 | 1458 | tcx.ensure().lint_mod(tcx.hir().local_def_id(module)); |
532ac7d7 XL |
1459 | }); |
1460 | }); | |
1461 | }); | |
1a4d82fc | 1462 | } |
b039eaaf | 1463 | |
9fa01778 XL |
1464 | struct EarlyLintPassObjects<'a> { |
1465 | lints: &'a mut [EarlyLintPassObject], | |
1466 | } | |
1467 | ||
e1599b0c | 1468 | #[allow(rustc::lint_pass_impl_without_macro)] |
9fa01778 XL |
1469 | impl LintPass for EarlyLintPassObjects<'_> { |
1470 | fn name(&self) -> &'static str { | |
1471 | panic!() | |
1472 | } | |
9fa01778 XL |
1473 | } |
1474 | ||
1475 | macro_rules! expand_early_lint_pass_impl_methods { | |
1476 | ([$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( | |
1477 | $(fn $name(&mut self, context: &EarlyContext<'_>, $($param: $arg),*) { | |
1478 | for obj in self.lints.iter_mut() { | |
1479 | obj.$name(context, $($param),*); | |
1480 | } | |
1481 | })* | |
1482 | ) | |
1483 | } | |
1484 | ||
1485 | macro_rules! early_lint_pass_impl { | |
1486 | ([], [$($methods:tt)*]) => ( | |
1487 | impl EarlyLintPass for EarlyLintPassObjects<'_> { | |
1488 | expand_early_lint_pass_impl_methods!([$($methods)*]); | |
1489 | } | |
1490 | ) | |
1491 | } | |
1492 | ||
1493 | early_lint_methods!(early_lint_pass_impl, []); | |
1494 | ||
9fa01778 XL |
1495 | fn early_lint_crate<T: EarlyLintPass>( |
1496 | sess: &Session, | |
e74abb32 | 1497 | lint_store: &LintStore, |
9fa01778 XL |
1498 | krate: &ast::Crate, |
1499 | pass: T, | |
1500 | buffered: LintBuffer, | |
e74abb32 | 1501 | warn_about_weird_lints: bool, |
9fa01778 XL |
1502 | ) -> LintBuffer { |
1503 | let mut cx = EarlyContextAndPass { | |
e74abb32 | 1504 | context: EarlyContext::new(sess, lint_store, krate, buffered, warn_about_weird_lints), |
9fa01778 XL |
1505 | pass, |
1506 | }; | |
1507 | ||
1508 | // Visit the whole crate. | |
1509 | cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| { | |
1510 | // since the root module isn't visited as an item (because it isn't an | |
1511 | // item), warn for it here. | |
1512 | run_early_pass!(cx, check_crate, krate); | |
1513 | ||
1514 | ast_visit::walk_crate(cx, krate); | |
1515 | ||
1516 | run_early_pass!(cx, check_crate_post, krate); | |
1517 | }); | |
1518 | cx.context.buffered | |
1519 | } | |
1520 | ||
1521 | pub fn check_ast_crate<T: EarlyLintPass>( | |
8faf50e0 | 1522 | sess: &Session, |
e74abb32 | 1523 | lint_store: &LintStore, |
8faf50e0 XL |
1524 | krate: &ast::Crate, |
1525 | pre_expansion: bool, | |
e74abb32 | 1526 | lint_buffer: Option<LintBuffer>, |
9fa01778 | 1527 | builtin_lints: T, |
8faf50e0 | 1528 | ) { |
e74abb32 XL |
1529 | let mut passes: Vec<_> = if pre_expansion { |
1530 | lint_store.pre_expansion_passes.iter().map(|p| (p)()).collect() | |
8faf50e0 | 1531 | } else { |
e74abb32 | 1532 | lint_store.early_passes.iter().map(|p| (p)()).collect() |
8faf50e0 | 1533 | }; |
e74abb32 | 1534 | let mut buffered = lint_buffer.unwrap_or_default(); |
b039eaaf | 1535 | |
9fa01778 | 1536 | if !sess.opts.debugging_opts.no_interleave_lints { |
e74abb32 XL |
1537 | buffered = early_lint_crate(sess, lint_store, krate, builtin_lints, buffered, |
1538 | pre_expansion); | |
7453a54e | 1539 | |
9fa01778 XL |
1540 | if !passes.is_empty() { |
1541 | buffered = early_lint_crate( | |
1542 | sess, | |
e74abb32 | 1543 | lint_store, |
9fa01778 XL |
1544 | krate, |
1545 | EarlyLintPassObjects { lints: &mut passes[..] }, | |
1546 | buffered, | |
e74abb32 | 1547 | pre_expansion, |
9fa01778 XL |
1548 | ); |
1549 | } | |
1550 | } else { | |
1551 | for pass in &mut passes { | |
1552 | buffered = time(sess, &format!("running lint: {}", pass.name()), || { | |
1553 | early_lint_crate( | |
1554 | sess, | |
e74abb32 | 1555 | lint_store, |
9fa01778 XL |
1556 | krate, |
1557 | EarlyLintPassObjects { lints: slice::from_mut(pass) }, | |
1558 | buffered, | |
e74abb32 | 1559 | pre_expansion, |
9fa01778 XL |
1560 | ) |
1561 | }); | |
1562 | } | |
1563 | } | |
b039eaaf | 1564 | |
ff7c6d11 XL |
1565 | // All of the buffered lints should have been emitted at this point. |
1566 | // If not, that means that we somehow buffered a lint for a node id | |
1567 | // that was not lint-checked (perhaps it doesn't exist?). This is a bug. | |
1568 | // | |
1569 | // Rustdoc runs everybody-loops before the early lints and removes | |
1570 | // function bodies, so it's totally possible for linted | |
0731742a | 1571 | // node ids to not exist (e.g., macros defined within functions for the |
ff7c6d11 XL |
1572 | // unused_macro lint) anymore. So we only run this check |
1573 | // when we're not in rustdoc mode. (see issue #47639) | |
1574 | if !sess.opts.actually_rustdoc { | |
8faf50e0 | 1575 | for (_id, lints) in buffered.map { |
ff7c6d11 | 1576 | for early_lint in lints { |
0531ce1d | 1577 | sess.delay_span_bug(early_lint.span, "failed to process buffered lint here"); |
ff7c6d11 | 1578 | } |
b039eaaf SL |
1579 | } |
1580 | } | |
1581 | } |