|
1 | 1 | use rustc_ast_pretty::pprust;
|
2 |
| -use rustc_data_structures::{fx::FxIndexMap, fx::FxIndexSet, sync::Lrc}; |
| 2 | +use rustc_data_structures::{fx::FxIndexMap, fx::FxIndexSet}; |
3 | 3 | use rustc_errors::{Diag, LintDiagnostic, MultiSpan};
|
4 | 4 | use rustc_feature::{Features, GateIssue};
|
5 | 5 | use rustc_hir::intravisit::{self, Visitor};
|
@@ -115,34 +115,44 @@ impl LintLevelSets {
|
115 | 115 | }
|
116 | 116 | }
|
117 | 117 |
|
118 |
| -/// Walk the whole crate collecting nodes where lint levels change |
119 |
| -/// (e.g. `#[allow]` attributes), and joins that list with the warn-by-default |
120 |
| -/// (and not allowed in the crate) and CLI lints. The returned value is a tuple |
121 |
| -/// of 1. The lints that will emit (or at least, should run), and 2. |
122 |
| -/// The lints that are allowed at the crate level and will not emit. |
123 |
| -pub fn lints_that_can_emit(tcx: TyCtxt<'_>, (): ()) -> Lrc<(FxIndexSet<String>, FxIndexSet<String>)> { |
124 |
| - let mut visitor = LintLevelMinimum::new(tcx); |
125 |
| - visitor.process_opts(); |
126 |
| - tcx.hir().walk_attributes(&mut visitor); |
127 |
| - |
| 118 | +pub fn lints_that_dont_need_to_run( |
| 119 | + tcx: TyCtxt<'_>, |
| 120 | + (): (), |
| 121 | +) -> FxIndexSet<LintId> { |
128 | 122 | let store = unerased_lint_store(&tcx.sess);
|
129 | 123 |
|
130 |
| - let lint_groups = store.get_lint_groups(); |
131 |
| - for group in lint_groups { |
132 |
| - let binding = group.0.to_lowercase(); |
133 |
| - let group_name = name_without_tool(&binding).to_string(); |
134 |
| - if visitor.lints_that_actually_run.contains(&group_name) { |
135 |
| - for lint in group.1 { |
136 |
| - visitor.lints_that_actually_run.insert(name_without_tool(&lint.to_string()).to_string()); |
137 |
| - } |
138 |
| - } else if visitor.lints_allowed.contains(&group_name) { |
139 |
| - for lint in &group.1 { |
140 |
| - visitor.lints_allowed.insert(name_without_tool(&lint.to_string()).to_string()); |
| 124 | + let dont_need_to_run: FxIndexSet<LintId> = store |
| 125 | + .get_lints() |
| 126 | + .into_iter() |
| 127 | + .filter_map(|lint| { |
| 128 | + if !lint.loadbearing && lint.default_level(tcx.sess.edition()) == Level::Allow { |
| 129 | + Some(LintId::of(lint)) |
| 130 | + } else { |
| 131 | + None |
141 | 132 | }
|
142 |
| - } |
143 |
| - } |
| 133 | + }) |
| 134 | + .collect(); |
144 | 135 |
|
145 |
| - Lrc::new((visitor.lints_that_actually_run, visitor.lints_allowed)) |
| 136 | + let mut visitor = LintLevelMaximum { tcx, dont_need_to_run }; |
| 137 | + visitor.process_opts(); |
| 138 | + tcx.hir().walk_attributes(&mut visitor); |
| 139 | + |
| 140 | + // let lint_groups = store.get_lint_groups(); |
| 141 | + // for group in lint_groups { |
| 142 | + // let binding = group.0.to_lowercase(); |
| 143 | + // let group_name = name_without_tool(&binding).to_string(); |
| 144 | + // if visitor.lints_that_actually_run.contains(&group_name) { |
| 145 | + // for lint in group.1 { |
| 146 | + // visitor.lints_that_actually_run.insert(name_without_tool(&lint.to_string()).to_string()); |
| 147 | + // } |
| 148 | + // } else if visitor.lints_allowed.contains(&group_name) { |
| 149 | + // for lint in &group.1 { |
| 150 | + // visitor.lints_allowed.insert(name_without_tool(&lint.to_string()).to_string()); |
| 151 | + // } |
| 152 | + // } |
| 153 | + // } |
| 154 | + |
| 155 | + visitor.dont_need_to_run |
146 | 156 | }
|
147 | 157 |
|
148 | 158 | #[instrument(level = "trace", skip(tcx), ret)]
|
@@ -338,83 +348,105 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
|
338 | 348 | ///
|
339 | 349 | /// E.g., if a crate has a global #![allow(lint)] attribute, but a single item
|
340 | 350 | /// uses #[warn(lint)], this visitor will set that lint level as `Warn`
|
341 |
| -struct LintLevelMinimum<'tcx> { |
| 351 | +struct LintLevelMaximum<'tcx> { |
342 | 352 | tcx: TyCtxt<'tcx>,
|
343 | 353 | /// The actual list of detected lints.
|
344 |
| - lints_that_actually_run: FxIndexSet<String>, |
345 |
| - lints_allowed: FxIndexSet<String>, |
| 354 | + dont_need_to_run: FxIndexSet<LintId>, |
346 | 355 | }
|
347 | 356 |
|
348 |
| -impl<'tcx> LintLevelMinimum<'tcx> { |
349 |
| - pub fn new(tcx: TyCtxt<'tcx>) -> Self { |
350 |
| - let mut lints_that_actually_run = FxIndexSet::default(); |
351 |
| - lints_that_actually_run.reserve(230); |
352 |
| - let mut lints_allowed = FxIndexSet::default(); |
353 |
| - lints_allowed.reserve(100); |
354 |
| - Self { |
355 |
| - tcx, |
356 |
| - // That magic number is the current number of lints + some more for possible future lints |
357 |
| - lints_that_actually_run, |
358 |
| - lints_allowed, |
359 |
| - } |
360 |
| - } |
361 |
| - |
| 357 | +impl<'tcx> LintLevelMaximum<'tcx> { |
362 | 358 | fn process_opts(&mut self) {
|
363 |
| - for (lint, level) in &self.tcx.sess.opts.lint_opts { |
364 |
| - if *level == Level::Allow { |
365 |
| - self.lints_allowed.insert(lint.clone()); |
366 |
| - } else { |
367 |
| - self.lints_that_actually_run.insert(lint.to_string()); |
| 359 | + let store = unerased_lint_store(self.tcx.sess); |
| 360 | + for (lint_group, level) in &self.tcx.sess.opts.lint_opts { |
| 361 | + if *level != Level::Allow { |
| 362 | + let Ok(lints) = store.find_lints(lint_group) else { |
| 363 | + return; |
| 364 | + }; |
| 365 | + for lint in lints { |
| 366 | + self.dont_need_to_run.swap_remove(&lint); |
| 367 | + } |
368 | 368 | }
|
369 | 369 | }
|
370 | 370 | }
|
371 | 371 | }
|
372 | 372 |
|
373 |
| -impl<'tcx> Visitor<'tcx> for LintLevelMinimum<'tcx> { |
| 373 | +impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> { |
374 | 374 | type NestedFilter = nested_filter::All;
|
375 | 375 |
|
376 | 376 | fn nested_visit_map(&mut self) -> Self::Map {
|
377 | 377 | self.tcx.hir()
|
378 | 378 | }
|
379 | 379 |
|
380 | 380 | fn visit_attribute(&mut self, attribute: &'tcx ast::Attribute) {
|
381 |
| - if let Some(meta) = attribute.meta() { |
382 |
| - if [sym::warn, sym::deny, sym::forbid, sym::expect] |
383 |
| - .iter() |
384 |
| - .any(|kind| meta.has_name(*kind)) |
385 |
| - { |
| 381 | + match Level::from_attr(attribute) { |
| 382 | + Some( |
| 383 | + Level::Warn |
| 384 | + | Level::Deny |
| 385 | + | Level::Forbid |
| 386 | + | Level::Expect(..) |
| 387 | + | Level::ForceWarn(..), |
| 388 | + ) => { |
| 389 | + let store = unerased_lint_store(self.tcx.sess); |
| 390 | + let Some(meta) = attribute.meta() else { return }; |
386 | 391 | // SAFETY: Lint attributes are always a metalist inside a
|
387 | 392 | // metalist (even with just one lint).
|
388 |
| - for meta_list in meta.meta_item_list().unwrap() { |
389 |
| - // If it's a tool lint (e.g. clippy::my_clippy_lint) |
390 |
| - if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { |
391 |
| - if meta_item.path.segments.len() == 1 { |
392 |
| - self.lints_that_actually_run.insert( |
393 |
| - // SAFETY: Lint attributes can only have literals |
394 |
| - meta_list.ident().unwrap().name.as_str().to_string(), |
395 |
| - ); |
396 |
| - } else { |
397 |
| - self.lints_that_actually_run |
398 |
| - .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); |
399 |
| - } |
| 393 | + let Some(meta_item_list) = meta.meta_item_list() else { return }; |
| 394 | + |
| 395 | + for meta_list in meta_item_list { |
| 396 | + // Convert Path to String |
| 397 | + let Some(meta_item) = meta_list.meta_item() else {return}; |
| 398 | + let ident: &str = &meta_item.path.segments.iter().map(|segment| segment.ident.as_str()).collect::<Vec<&str>>().join("::"); |
| 399 | + let Ok(lints) = store.find_lints( |
| 400 | + // SAFETY: Lint attributes can only have literals |
| 401 | + ident, |
| 402 | + ) else { |
| 403 | + return; |
| 404 | + }; |
| 405 | + for lint in lints { |
| 406 | + self.dont_need_to_run.swap_remove(&lint); |
400 | 407 | }
|
401 |
| - } |
402 |
| - // We handle #![allow]s differently, as these remove checking rather than adding. |
403 |
| - } else if meta.has_name(sym::allow) |
404 |
| - && let ast::AttrStyle::Inner = attribute.style |
405 |
| - { |
406 |
| - for meta_list in meta.meta_item_list().unwrap() { |
407 |
| - // If it's a tool lint (e.g. clippy::my_clippy_lint) |
408 |
| - if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { |
409 |
| - if meta_item.path.segments.len() == 1 { |
410 |
| - self.lints_allowed.insert(meta_list.name_or_empty().as_str().to_string()); |
411 |
| - } else { |
412 |
| - self.lints_allowed |
413 |
| - .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); |
414 |
| - } |
| 408 | + // // If it's a tool lint (e.g. clippy::my_clippy_lint) |
| 409 | + // if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { |
| 410 | + // if meta_item.path.segments.len() == 1 { |
| 411 | + // let Ok(lints) = store.find_lints( |
| 412 | + // // SAFETY: Lint attributes can only have literals |
| 413 | + // meta_list.ident().unwrap().name.as_str(), |
| 414 | + // ) else { |
| 415 | + // return; |
| 416 | + // }; |
| 417 | + // for lint in lints { |
| 418 | + // dbg!("LINT REMOVED", &lint); |
| 419 | + // self.dont_need_to_run.swap_remove(&lint); |
| 420 | + // } |
| 421 | + // } else { |
| 422 | + // let Ok(lints) = store.find_lints( |
| 423 | + // // SAFETY: Lint attributes can only have literals |
| 424 | + // meta_item.path.segments[1].ident.name.as_str(), |
| 425 | + // ) else { |
| 426 | + // return; |
| 427 | + // }; |
| 428 | + // for lint in lints { |
| 429 | + // dbg!("LINT REMOVED", &lint); |
| 430 | + // self.dont_need_to_run.swap_remove(&lint); |
| 431 | + // } |
| 432 | + // } |
415 | 433 | }
|
416 |
| - } |
417 |
| - } |
| 434 | + // We handle #![allow]s differently, as these remove checking rather than adding. |
| 435 | + } // Some(Level::Allow) if ast::AttrStyle::Inner == attribute.style => { |
| 436 | + // for meta_list in meta.meta_item_list().unwrap() { |
| 437 | + // // If it's a tool lint (e.g. clippy::my_clippy_lint) |
| 438 | + // if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { |
| 439 | + // if meta_item.path.segments.len() == 1 { |
| 440 | + // self.lints_allowed |
| 441 | + // .insert(meta_list.name_or_empty().as_str().to_string()); |
| 442 | + // } else { |
| 443 | + // self.lints_allowed |
| 444 | + // .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); |
| 445 | + // } |
| 446 | + // } |
| 447 | + // } |
| 448 | + // } |
| 449 | + _ => { return; } |
418 | 450 | }
|
419 | 451 | }
|
420 | 452 | }
|
@@ -1050,7 +1082,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
1050 | 1082 |
|
1051 | 1083 | pub(crate) fn provide(providers: &mut Providers) {
|
1052 | 1084 | *providers =
|
1053 |
| - Providers { shallow_lint_levels_on, lints_that_can_emit, ..*providers }; |
| 1085 | + Providers { shallow_lint_levels_on, lints_that_dont_need_to_run, ..*providers }; |
1054 | 1086 | }
|
1055 | 1087 |
|
1056 | 1088 | pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
|
|
0 commit comments