|
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};
|
@@ -143,34 +143,44 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
|
143 | 143 | builder.provider.expectations
|
144 | 144 | }
|
145 | 145 |
|
146 |
| -/// Walk the whole crate collecting nodes where lint levels change |
147 |
| -/// (e.g. `#[allow]` attributes), and joins that list with the warn-by-default |
148 |
| -/// (and not allowed in the crate) and CLI lints. The returned value is a tuple |
149 |
| -/// of 1. The lints that will emit (or at least, should run), and 2. |
150 |
| -/// The lints that are allowed at the crate level and will not emit. |
151 |
| -pub fn lints_that_can_emit(tcx: TyCtxt<'_>, (): ()) -> Lrc<(FxIndexSet<String>, FxIndexSet<String>)> { |
152 |
| - let mut visitor = LintLevelMinimum::new(tcx); |
153 |
| - visitor.process_opts(); |
154 |
| - tcx.hir().walk_attributes(&mut visitor); |
155 |
| - |
| 146 | +pub fn lints_that_dont_need_to_run( |
| 147 | + tcx: TyCtxt<'_>, |
| 148 | + (): (), |
| 149 | +) -> FxIndexSet<LintId> { |
156 | 150 | let store = unerased_lint_store(&tcx.sess);
|
157 | 151 |
|
158 |
| - let lint_groups = store.get_lint_groups(); |
159 |
| - for group in lint_groups { |
160 |
| - let binding = group.0.to_lowercase(); |
161 |
| - let group_name = name_without_tool(&binding).to_string(); |
162 |
| - if visitor.lints_that_actually_run.contains(&group_name) { |
163 |
| - for lint in group.1 { |
164 |
| - visitor.lints_that_actually_run.insert(name_without_tool(&lint.to_string()).to_string()); |
165 |
| - } |
166 |
| - } else if visitor.lints_allowed.contains(&group_name) { |
167 |
| - for lint in &group.1 { |
168 |
| - visitor.lints_allowed.insert(name_without_tool(&lint.to_string()).to_string()); |
| 152 | + let dont_need_to_run: FxIndexSet<LintId> = store |
| 153 | + .get_lints() |
| 154 | + .into_iter() |
| 155 | + .filter_map(|lint| { |
| 156 | + if !lint.loadbearing && lint.default_level(tcx.sess.edition()) == Level::Allow { |
| 157 | + Some(LintId::of(lint)) |
| 158 | + } else { |
| 159 | + None |
169 | 160 | }
|
170 |
| - } |
171 |
| - } |
| 161 | + }) |
| 162 | + .collect(); |
172 | 163 |
|
173 |
| - Lrc::new((visitor.lints_that_actually_run, visitor.lints_allowed)) |
| 164 | + let mut visitor = LintLevelMaximum { tcx, dont_need_to_run }; |
| 165 | + visitor.process_opts(); |
| 166 | + tcx.hir().walk_attributes(&mut visitor); |
| 167 | + |
| 168 | + // let lint_groups = store.get_lint_groups(); |
| 169 | + // for group in lint_groups { |
| 170 | + // let binding = group.0.to_lowercase(); |
| 171 | + // let group_name = name_without_tool(&binding).to_string(); |
| 172 | + // if visitor.lints_that_actually_run.contains(&group_name) { |
| 173 | + // for lint in group.1 { |
| 174 | + // visitor.lints_that_actually_run.insert(name_without_tool(&lint.to_string()).to_string()); |
| 175 | + // } |
| 176 | + // } else if visitor.lints_allowed.contains(&group_name) { |
| 177 | + // for lint in &group.1 { |
| 178 | + // visitor.lints_allowed.insert(name_without_tool(&lint.to_string()).to_string()); |
| 179 | + // } |
| 180 | + // } |
| 181 | + // } |
| 182 | + |
| 183 | + visitor.dont_need_to_run |
174 | 184 | }
|
175 | 185 |
|
176 | 186 | #[instrument(level = "trace", skip(tcx), ret)]
|
@@ -477,83 +487,105 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'
|
477 | 487 | ///
|
478 | 488 | /// E.g., if a crate has a global #![allow(lint)] attribute, but a single item
|
479 | 489 | /// uses #[warn(lint)], this visitor will set that lint level as `Warn`
|
480 |
| -struct LintLevelMinimum<'tcx> { |
| 490 | +struct LintLevelMaximum<'tcx> { |
481 | 491 | tcx: TyCtxt<'tcx>,
|
482 | 492 | /// The actual list of detected lints.
|
483 |
| - lints_that_actually_run: FxIndexSet<String>, |
484 |
| - lints_allowed: FxIndexSet<String>, |
| 493 | + dont_need_to_run: FxIndexSet<LintId>, |
485 | 494 | }
|
486 | 495 |
|
487 |
| -impl<'tcx> LintLevelMinimum<'tcx> { |
488 |
| - pub fn new(tcx: TyCtxt<'tcx>) -> Self { |
489 |
| - let mut lints_that_actually_run = FxIndexSet::default(); |
490 |
| - lints_that_actually_run.reserve(230); |
491 |
| - let mut lints_allowed = FxIndexSet::default(); |
492 |
| - lints_allowed.reserve(100); |
493 |
| - Self { |
494 |
| - tcx, |
495 |
| - // That magic number is the current number of lints + some more for possible future lints |
496 |
| - lints_that_actually_run, |
497 |
| - lints_allowed, |
498 |
| - } |
499 |
| - } |
500 |
| - |
| 496 | +impl<'tcx> LintLevelMaximum<'tcx> { |
501 | 497 | fn process_opts(&mut self) {
|
502 |
| - for (lint, level) in &self.tcx.sess.opts.lint_opts { |
503 |
| - if *level == Level::Allow { |
504 |
| - self.lints_allowed.insert(lint.clone()); |
505 |
| - } else { |
506 |
| - self.lints_that_actually_run.insert(lint.to_string()); |
| 498 | + let store = unerased_lint_store(self.tcx.sess); |
| 499 | + for (lint_group, level) in &self.tcx.sess.opts.lint_opts { |
| 500 | + if *level != Level::Allow { |
| 501 | + let Ok(lints) = store.find_lints(lint_group) else { |
| 502 | + return; |
| 503 | + }; |
| 504 | + for lint in lints { |
| 505 | + self.dont_need_to_run.swap_remove(&lint); |
| 506 | + } |
507 | 507 | }
|
508 | 508 | }
|
509 | 509 | }
|
510 | 510 | }
|
511 | 511 |
|
512 |
| -impl<'tcx> Visitor<'tcx> for LintLevelMinimum<'tcx> { |
| 512 | +impl<'tcx> Visitor<'tcx> for LintLevelMaximum<'tcx> { |
513 | 513 | type NestedFilter = nested_filter::All;
|
514 | 514 |
|
515 | 515 | fn nested_visit_map(&mut self) -> Self::Map {
|
516 | 516 | self.tcx.hir()
|
517 | 517 | }
|
518 | 518 |
|
519 | 519 | fn visit_attribute(&mut self, attribute: &'tcx ast::Attribute) {
|
520 |
| - if let Some(meta) = attribute.meta() { |
521 |
| - if [sym::warn, sym::deny, sym::forbid, sym::expect] |
522 |
| - .iter() |
523 |
| - .any(|kind| meta.has_name(*kind)) |
524 |
| - { |
| 520 | + match Level::from_attr(attribute) { |
| 521 | + Some( |
| 522 | + Level::Warn |
| 523 | + | Level::Deny |
| 524 | + | Level::Forbid |
| 525 | + | Level::Expect(..) |
| 526 | + | Level::ForceWarn(..), |
| 527 | + ) => { |
| 528 | + let store = unerased_lint_store(self.tcx.sess); |
| 529 | + let Some(meta) = attribute.meta() else { return }; |
525 | 530 | // SAFETY: Lint attributes are always a metalist inside a
|
526 | 531 | // metalist (even with just one lint).
|
527 |
| - for meta_list in meta.meta_item_list().unwrap() { |
528 |
| - // If it's a tool lint (e.g. clippy::my_clippy_lint) |
529 |
| - if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { |
530 |
| - if meta_item.path.segments.len() == 1 { |
531 |
| - self.lints_that_actually_run.insert( |
532 |
| - // SAFETY: Lint attributes can only have literals |
533 |
| - meta_list.ident().unwrap().name.as_str().to_string(), |
534 |
| - ); |
535 |
| - } else { |
536 |
| - self.lints_that_actually_run |
537 |
| - .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); |
538 |
| - } |
| 532 | + let Some(meta_item_list) = meta.meta_item_list() else { return }; |
| 533 | + |
| 534 | + for meta_list in meta_item_list { |
| 535 | + // Convert Path to String |
| 536 | + let Some(meta_item) = meta_list.meta_item() else {return}; |
| 537 | + let ident: &str = &meta_item.path.segments.iter().map(|segment| segment.ident.as_str()).collect::<Vec<&str>>().join("::"); |
| 538 | + let Ok(lints) = store.find_lints( |
| 539 | + // SAFETY: Lint attributes can only have literals |
| 540 | + ident, |
| 541 | + ) else { |
| 542 | + return; |
| 543 | + }; |
| 544 | + for lint in lints { |
| 545 | + self.dont_need_to_run.swap_remove(&lint); |
539 | 546 | }
|
540 |
| - } |
541 |
| - // We handle #![allow]s differently, as these remove checking rather than adding. |
542 |
| - } else if meta.has_name(sym::allow) |
543 |
| - && let ast::AttrStyle::Inner = attribute.style |
544 |
| - { |
545 |
| - for meta_list in meta.meta_item_list().unwrap() { |
546 |
| - // If it's a tool lint (e.g. clippy::my_clippy_lint) |
547 |
| - if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { |
548 |
| - if meta_item.path.segments.len() == 1 { |
549 |
| - self.lints_allowed.insert(meta_list.name_or_empty().as_str().to_string()); |
550 |
| - } else { |
551 |
| - self.lints_allowed |
552 |
| - .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); |
553 |
| - } |
| 547 | + // // If it's a tool lint (e.g. clippy::my_clippy_lint) |
| 548 | + // if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { |
| 549 | + // if meta_item.path.segments.len() == 1 { |
| 550 | + // let Ok(lints) = store.find_lints( |
| 551 | + // // SAFETY: Lint attributes can only have literals |
| 552 | + // meta_list.ident().unwrap().name.as_str(), |
| 553 | + // ) else { |
| 554 | + // return; |
| 555 | + // }; |
| 556 | + // for lint in lints { |
| 557 | + // dbg!("LINT REMOVED", &lint); |
| 558 | + // self.dont_need_to_run.swap_remove(&lint); |
| 559 | + // } |
| 560 | + // } else { |
| 561 | + // let Ok(lints) = store.find_lints( |
| 562 | + // // SAFETY: Lint attributes can only have literals |
| 563 | + // meta_item.path.segments[1].ident.name.as_str(), |
| 564 | + // ) else { |
| 565 | + // return; |
| 566 | + // }; |
| 567 | + // for lint in lints { |
| 568 | + // dbg!("LINT REMOVED", &lint); |
| 569 | + // self.dont_need_to_run.swap_remove(&lint); |
| 570 | + // } |
| 571 | + // } |
554 | 572 | }
|
555 |
| - } |
556 |
| - } |
| 573 | + // We handle #![allow]s differently, as these remove checking rather than adding. |
| 574 | + } // Some(Level::Allow) if ast::AttrStyle::Inner == attribute.style => { |
| 575 | + // for meta_list in meta.meta_item_list().unwrap() { |
| 576 | + // // If it's a tool lint (e.g. clippy::my_clippy_lint) |
| 577 | + // if let ast::NestedMetaItem::MetaItem(meta_item) = meta_list { |
| 578 | + // if meta_item.path.segments.len() == 1 { |
| 579 | + // self.lints_allowed |
| 580 | + // .insert(meta_list.name_or_empty().as_str().to_string()); |
| 581 | + // } else { |
| 582 | + // self.lints_allowed |
| 583 | + // .insert(meta_item.path.segments[1].ident.name.as_str().to_string()); |
| 584 | + // } |
| 585 | + // } |
| 586 | + // } |
| 587 | + // } |
| 588 | + _ => { return; } |
557 | 589 | }
|
558 | 590 | }
|
559 | 591 | }
|
@@ -1217,7 +1249,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
|
1217 | 1249 |
|
1218 | 1250 | pub(crate) fn provide(providers: &mut Providers) {
|
1219 | 1251 | *providers =
|
1220 |
| - Providers { shallow_lint_levels_on, lint_expectations, lints_that_can_emit, ..*providers }; |
| 1252 | + Providers { shallow_lint_levels_on, lint_expectations, lints_that_dont_need_to_run, ..*providers }; |
1221 | 1253 | }
|
1222 | 1254 |
|
1223 | 1255 | pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
|
|
0 commit comments