|
1 | 1 | use rustc_ast_pretty::pprust; |
2 | | -use rustc_data_structures::fx::FxIndexMap; |
3 | | -use rustc_errors::{Diag,LintDiagnostic,MultiSpan}; |
| 2 | +use rustc_data_structures::{fx::FxIndexMap, sync::Lrc}; |
| 3 | +use rustc_errors::{Diag,DiagMessage,LintDiagnostic,MultiSpan}; |
4 | 4 | use rustc_feature::{Features,GateIssue}; |
5 | 5 | use rustc_hir::HirId; |
6 | 6 | use rustc_hir::intravisit::{self,Visitor}; |
@@ -31,7 +31,7 @@ use crate::errors::{ |
31 | 31 | OverruledAttributeSub,RequestedLevel,UnknownToolInScopedLint,UnsupportedGroup, |
32 | 32 | }; |
33 | 33 | usecrate::fluent_generated as fluent; |
34 | | -usecrate::late::unerased_lint_store; |
| 34 | +usecrate::late::{unerased_lint_store, name_without_tool}; |
35 | 35 | usecrate::lints::{ |
36 | 36 | DeprecatedLintName,DeprecatedLintNameFromCommandLine,IgnoredUnlessCrateSpecified, |
37 | 37 | OverruledAttributeLint,RemovedLint,RemovedLintFromCommandLine,RenamedLint, |
@@ -115,6 +115,36 @@ 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 | +pubfnlints_that_can_emit(tcx:TyCtxt<'_>,():()) -> Lrc<(Vec<String>,Vec<String>)>{ |
| 124 | +letmut visitor = LintLevelMinimum::new(tcx); |
| 125 | + visitor.process_opts(); |
| 126 | + tcx.hir().walk_attributes(&mut visitor); |
| 127 | + |
| 128 | +let store = unerased_lint_store(&tcx.sess); |
| 129 | + |
| 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_to_emit.contains(&group_name){ |
| 135 | +for lint in group.1{ |
| 136 | + visitor.lints_to_emit.push(name_without_tool(&lint.to_string()).to_string()); |
| 137 | +} |
| 138 | +}elseif visitor.lints_allowed.contains(&group_name){ |
| 139 | +for lint in&group.1{ |
| 140 | + visitor.lints_allowed.push(name_without_tool(&lint.to_string()).to_string()); |
| 141 | +} |
| 142 | +} |
| 143 | +} |
| 144 | + |
| 145 | +Lrc::new((visitor.lints_to_emit, visitor.lints_allowed)) |
| 146 | +} |
| 147 | + |
118 | 148 | #[instrument(level = "trace", skip(tcx), ret)] |
119 | 149 | fnshallow_lint_levels_on(tcx:TyCtxt<'_>,owner: hir::OwnerId) -> ShallowLintLevelMap{ |
120 | 150 | let store = unerased_lint_store(tcx.sess); |
@@ -301,6 +331,88 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { |
301 | 331 | } |
302 | 332 | } |
303 | 333 |
|
| 334 | +/// Visitor with the only function of visiting every item-like in a crate and |
| 335 | +/// computing the highest level that every lint gets put to. |
| 336 | +/// |
| 337 | +/// E.g., if a crate has a global #![allow(lint)] attribute, but a single item |
| 338 | +/// uses #[warn(lint)], this visitor will set that lint level as `Warn` |
| 339 | +structLintLevelMinimum<'tcx>{ |
| 340 | +tcx:TyCtxt<'tcx>, |
| 341 | +/// The actual list of detected lints. |
| 342 | +lints_to_emit:Vec<String>, |
| 343 | +lints_allowed:Vec<String>, |
| 344 | +} |
| 345 | + |
| 346 | +impl<'tcx>LintLevelMinimum<'tcx>{ |
| 347 | +pubfnnew(tcx:TyCtxt<'tcx>) -> Self{ |
| 348 | +Self{ |
| 349 | + tcx, |
| 350 | +// That magic number is the current number of lints + some more for possible future lints |
| 351 | +lints_to_emit:Vec::with_capacity(230), |
| 352 | +lints_allowed:Vec::with_capacity(100), |
| 353 | +} |
| 354 | +} |
| 355 | + |
| 356 | +fnprocess_opts(&mutself){ |
| 357 | +for(lint, level)in&self.tcx.sess.opts.lint_opts{ |
| 358 | +if*level == Level::Allow{ |
| 359 | +self.lints_allowed.push(lint.clone()); |
| 360 | +}else{ |
| 361 | +self.lints_to_emit.push(lint.to_string()); |
| 362 | +} |
| 363 | +} |
| 364 | +} |
| 365 | +} |
| 366 | + |
| 367 | +impl<'tcx>Visitor<'tcx>forLintLevelMinimum<'tcx>{ |
| 368 | +typeNestedFilter = nested_filter::All; |
| 369 | + |
| 370 | +fnnested_visit_map(&mutself) -> Self::Map{ |
| 371 | +self.tcx.hir() |
| 372 | +} |
| 373 | + |
| 374 | +fnvisit_attribute(&mutself,attribute:&'tcx ast::Attribute){ |
| 375 | +ifletSome(meta) = attribute.meta(){ |
| 376 | +if[sym::warn, sym::deny, sym::forbid, sym::expect] |
| 377 | +.iter() |
| 378 | +.any(|kind| meta.has_name(*kind)) |
| 379 | +{ |
| 380 | +// SAFETY: Lint attributes are always a metalist inside a |
| 381 | +// metalist (even with just one lint). |
| 382 | +for meta_list in meta.meta_item_list().unwrap(){ |
| 383 | +// If it's a tool lint (e.g. clippy::my_clippy_lint) |
| 384 | +iflet ast::NestedMetaItem::MetaItem(meta_item) = meta_list { |
| 385 | +if meta_item.path.segments.len() == 1{ |
| 386 | +self.lints_to_emit.push( |
| 387 | +// SAFETY: Lint attributes can only have literals |
| 388 | + meta_list.ident().unwrap().name.as_str().to_string(), |
| 389 | +); |
| 390 | +}else{ |
| 391 | +self.lints_to_emit |
| 392 | +.push(meta_item.path.segments[1].ident.name.as_str().to_string()); |
| 393 | +} |
| 394 | +} |
| 395 | +} |
| 396 | +// We handle #![allow]s differently, as these remove checking rather than adding. |
| 397 | +}elseif meta.has_name(sym::allow) |
| 398 | + && let ast::AttrStyle::Inner = attribute.style |
| 399 | +{ |
| 400 | +for meta_list in meta.meta_item_list().unwrap(){ |
| 401 | +// If it's a tool lint (e.g. clippy::my_clippy_lint) |
| 402 | +iflet ast::NestedMetaItem::MetaItem(meta_item) = meta_list { |
| 403 | +if meta_item.path.segments.len() == 1{ |
| 404 | +self.lints_allowed.push(meta_list.name_or_empty().as_str().to_string()) |
| 405 | +}else{ |
| 406 | +self.lints_allowed |
| 407 | +.push(meta_item.path.segments[1].ident.name.as_str().to_string()); |
| 408 | +} |
| 409 | +} |
| 410 | +} |
| 411 | +} |
| 412 | +} |
| 413 | +} |
| 414 | +} |
| 415 | + |
304 | 416 | pubstructLintLevelsBuilder<'s,P>{ |
305 | 417 | sess:&'sSession, |
306 | 418 | features:&'sFeatures, |
@@ -931,7 +1043,8 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { |
931 | 1043 | } |
932 | 1044 |
|
933 | 1045 | pub(crate)fnprovide(providers:&mutProviders){ |
934 | | -*providers = Providers{ shallow_lint_levels_on, ..*providers }; |
| 1046 | +*providers = |
| 1047 | +Providers{ shallow_lint_levels_on, lints_that_can_emit, ..*providers }; |
935 | 1048 | } |
936 | 1049 |
|
937 | 1050 | pub(crate)fnparse_lint_and_tool_name(lint_name:&str) -> (Option<Symbol>,&str){ |
|
0 commit comments