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