|
1 | 1 | use rustc_ast_pretty::pprust; |
2 | | -use rustc_data_structures::fx::FxIndexMap; |
| 2 | +use rustc_data_structures::fx::{FxIndexMap,FxIndexSet}; |
3 | 3 | use rustc_errors::{Diag,LintDiagnostic,MultiSpan}; |
4 | 4 | use rustc_feature::{Features,GateIssue}; |
5 | | -use rustc_hir::HirId; |
6 | 5 | use rustc_hir::intravisit::{self,Visitor}; |
| 6 | +use rustc_hir::{CRATE_HIR_ID,HirId}; |
7 | 7 | use rustc_index::IndexVec; |
8 | 8 | use rustc_middle::bug; |
9 | 9 | use rustc_middle::hir::nested_filter; |
@@ -115,6 +115,38 @@ impl LintLevelSets { |
115 | 115 | } |
116 | 116 | } |
117 | 117 |
|
| 118 | +fnlints_that_dont_need_to_run(tcx:TyCtxt<'_>,():()) -> FxIndexSet<LintId>{ |
| 119 | +let store = unerased_lint_store(&tcx.sess); |
| 120 | + |
| 121 | +let map = tcx.shallow_lint_levels_on(rustc_hir::CRATE_OWNER_ID); |
| 122 | + |
| 123 | +let dont_need_to_run:FxIndexSet<LintId> = store |
| 124 | +.get_lints() |
| 125 | +.into_iter() |
| 126 | +.filter_map(|lint| { |
| 127 | +if !lint.eval_always{ |
| 128 | +let lint_level = map.lint_level_id_at_node(tcx,LintId::of(lint),CRATE_HIR_ID); |
| 129 | +ifmatches!(lint_level,(Level::Allow, ..)) |
| 130 | + || (matches!(lint_level,(..,LintLevelSource::Default))) |
| 131 | + && lint.default_level(tcx.sess.edition()) == Level::Allow |
| 132 | +{ |
| 133 | +Some(LintId::of(lint)) |
| 134 | +}else{ |
| 135 | +None |
| 136 | +} |
| 137 | +}else{ |
| 138 | +None |
| 139 | +} |
| 140 | +}) |
| 141 | +.collect(); |
| 142 | + |
| 143 | +letmut visitor = LintLevelMaximum{ tcx, dont_need_to_run }; |
| 144 | + visitor.process_opts(); |
| 145 | + tcx.hir().walk_attributes(&mut visitor); |
| 146 | + |
| 147 | + visitor.dont_need_to_run |
| 148 | +} |
| 149 | + |
118 | 150 | #[instrument(level = "trace", skip(tcx), ret)] |
119 | 151 | fnshallow_lint_levels_on(tcx:TyCtxt<'_>,owner: hir::OwnerId) -> ShallowLintLevelMap{ |
120 | 152 | let store = unerased_lint_store(tcx.sess); |
@@ -301,6 +333,83 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { |
301 | 333 | } |
302 | 334 | } |
303 | 335 |
|
| 336 | +/// Visitor with the only function of visiting every item-like in a crate and |
| 337 | +/// computing the highest level that every lint gets put to. |
| 338 | +/// |
| 339 | +/// E.g., if a crate has a global #![allow(lint)] attribute, but a single item |
| 340 | +/// uses #[warn(lint)], this visitor will set that lint level as `Warn` |
| 341 | +structLintLevelMaximum<'tcx>{ |
| 342 | +tcx:TyCtxt<'tcx>, |
| 343 | +/// The actual list of detected lints. |
| 344 | +dont_need_to_run:FxIndexSet<LintId>, |
| 345 | +} |
| 346 | + |
| 347 | +impl<'tcx>LintLevelMaximum<'tcx>{ |
| 348 | +fnprocess_opts(&mutself){ |
| 349 | +let store = unerased_lint_store(self.tcx.sess); |
| 350 | +for(lint_group, level)in&self.tcx.sess.opts.lint_opts{ |
| 351 | +if*level != Level::Allow{ |
| 352 | +letOk(lints) = store.find_lints(lint_group)else{ |
| 353 | +return; |
| 354 | +}; |
| 355 | +for lint in lints { |
| 356 | +self.dont_need_to_run.swap_remove(&lint); |
| 357 | +} |
| 358 | +} |
| 359 | +} |
| 360 | +} |
| 361 | +} |
| 362 | + |
| 363 | +impl<'tcx>Visitor<'tcx>forLintLevelMaximum<'tcx>{ |
| 364 | +typeNestedFilter = nested_filter::All; |
| 365 | + |
| 366 | +fnnested_visit_map(&mutself) -> Self::Map{ |
| 367 | +self.tcx.hir() |
| 368 | +} |
| 369 | + |
| 370 | +/// FIXME(blyxyas): In a future revision, we should also graph #![allow]s, |
| 371 | +/// but that is handled with more care |
| 372 | +fnvisit_attribute(&mutself,attribute:&'tcx ast::Attribute){ |
| 373 | +ifmatches!( |
| 374 | +Level::from_attr(attribute), |
| 375 | +Some( |
| 376 | +Level::Warn |
| 377 | + | Level::Deny |
| 378 | + | Level::Forbid |
| 379 | + | Level::Expect(..) |
| 380 | + | Level::ForceWarn(..), |
| 381 | +) |
| 382 | +){ |
| 383 | +let store = unerased_lint_store(self.tcx.sess); |
| 384 | +letSome(meta) = attribute.meta()else{return}; |
| 385 | +// Lint attributes are always a metalist inside a |
| 386 | +// metalist (even with just one lint). |
| 387 | +letSome(meta_item_list) = meta.meta_item_list()else{return}; |
| 388 | + |
| 389 | +for meta_list in meta_item_list { |
| 390 | +// Convert Path to String |
| 391 | +letSome(meta_item) = meta_list.meta_item()else{return}; |
| 392 | +let ident:&str = &meta_item |
| 393 | +.path |
| 394 | +.segments |
| 395 | +.iter() |
| 396 | +.map(|segment| segment.ident.as_str()) |
| 397 | +.collect::<Vec<&str>>() |
| 398 | +.join("::"); |
| 399 | +letOk(lints) = store.find_lints( |
| 400 | +// 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); |
| 407 | +} |
| 408 | +} |
| 409 | +} |
| 410 | +} |
| 411 | +} |
| 412 | + |
304 | 413 | pubstructLintLevelsBuilder<'s,P>{ |
305 | 414 | sess:&'sSession, |
306 | 415 | features:&'sFeatures, |
@@ -934,7 +1043,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { |
934 | 1043 | } |
935 | 1044 |
|
936 | 1045 | pub(crate)fnprovide(providers:&mutProviders){ |
937 | | -*providers = Providers{ shallow_lint_levels_on, ..*providers }; |
| 1046 | +*providers = Providers{ shallow_lint_levels_on,lints_that_dont_need_to_run,..*providers }; |
938 | 1047 | } |
939 | 1048 |
|
940 | 1049 | pub(crate)fnparse_lint_and_tool_name(lint_name:&str) -> (Option<Symbol>,&str){ |
|
0 commit comments