1use std::fmt::Debug;
2
3use rustc_ast as ast;
4use rustc_ast::CRATE_NODE_ID;
5use rustc_ast::attr::AttributeExt;
6use rustc_attr_ir::lint::{LintCheck, LintCheckKind};
7use rustc_attr_ir::target::Target;
8use rustc_attr_ir::{Attribute, AttributeKind, find_attr};
9use rustc_attr_parsing::{AttributeParser, Recovery, ShouldEmit};
10use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
11use rustc_data_structures::unord::UnordSet;
12use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, MultiSpan, msg};
13use rustc_feature::{Features, GateIssue};
14use rustc_hir as hir;
15use rustc_hir::HirId;
16use rustc_hir::intravisit::{self, Visitor};
17use rustc_index::IndexVec;
18use rustc_lint_defs::builtin::{
19 self, FORBIDDEN_LINT_GROUPS, RENAMED_AND_REMOVED_LINTS, SINGLE_USE_LIFETIMES,
20 UNFULFILLED_LINT_EXPECTATIONS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES,
21};
22use rustc_lint_defs::{
23 Level, Lint, LintExpectationId, LintId, StableLintExpectationId, UnstableLintExpectationId,
24};
25use rustc_middle::hir::nested_filter;
26use rustc_middle::lint::{
27 LevelSpec, LintExpectation, LintLevelSource, ShallowLintLevelMap, StableLevelSpec,
28 UnstableLevelSpec, emit_lint_base, reveal_actual_level_spec,
29};
30use rustc_middle::query::Providers;
31use rustc_middle::ty::{RegisteredTools, TyCtxt};
32use rustc_session::Session;
33use rustc_span::def_id::CRATE_MOD_ID;
34use rustc_span::{AttrId, DUMMY_SP, Ident, Span, Symbol, sym};
35use thin_vec::ThinVec;
36use tracing::{debug, instrument};
37
38use crate::builtin::MISSING_DOCS;
39use crate::context::{CheckLintNameResult, LintStore};
40use crate::diagnostics::{
41 CheckNameUnknownTool, DeprecatedLintName, DeprecatedLintNameFromCommandLine,
42 IgnoredUnlessCrateSpecified, OverruledAttribute, OverruledAttributeLint, OverruledAttributeSub,
43 RemovedLint, RemovedLintFromCommandLine, RenamedLint, RenamedLintFromCommandLine,
44 RenamedLintSuggestion, RequestedLevel, UnknownLint, UnknownLintFromCommandLine,
45 UnknownLintSuggestion, UnknownToolInScopedLint, UnsupportedGroup,
46};
47use crate::late::unerased_lint_store;
48
49#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LintLevelSets {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field1_finish(f, "LintLevelSets",
"list", &&self.list)
}
}Debug)]
53struct LintLevelSets {
54 list: IndexVec<LintStackIndex, LintSet>,
56}
57
58#[automatically_derived]
impl ::core::marker::Copy for LintStackIndex { }
const COMMAND_LINE: LintStackIndex = LintStackIndex::from_u32(0);
impl LintStackIndex {
#[doc = r" Maximum value the index can take, as a `u32`."]
const MAX_AS_U32: u32 = 0xFFFF_FF00;
#[doc = r" Maximum value the index can take."]
const MAX: Self = Self::from_u32(0xFFFF_FF00);
#[doc = r" Zero value of the index."]
const ZERO: Self = Self::from_u32(0);
#[doc = r" Creates a new index from a given `usize`."]
#[doc = r""]
#[doc = r" # Panics"]
#[doc = r""]
#[doc = r" Will panic if `value` exceeds `MAX`."]
#[inline]
const fn from_usize(value: usize) -> Self {
if !(value <= (0xFFFF_FF00 as usize)) {
::core::panicking::panic("assertion failed: value <= (0xFFFF_FF00 as usize)")
};
unsafe { Self::from_u32_unchecked(value as u32) }
}
#[doc = r" Creates a new index from a given `u32`."]
#[doc = r""]
#[doc = r" # Panics"]
#[doc = r""]
#[doc = r" Will panic if `value` exceeds `MAX`."]
#[inline]
const fn from_u32(value: u32) -> Self {
if !(value <= 0xFFFF_FF00) {
::core::panicking::panic("assertion failed: value <= 0xFFFF_FF00")
};
unsafe { Self::from_u32_unchecked(value) }
}
#[doc = r" Creates a new index from a given `u16`."]
#[doc = r""]
#[doc = r" # Panics"]
#[doc = r""]
#[doc = r" Will panic if `value` exceeds `MAX`."]
#[inline]
const fn from_u16(value: u16) -> Self {
let value = value as u32;
if !(value <= 0xFFFF_FF00) {
::core::panicking::panic("assertion failed: value <= 0xFFFF_FF00")
};
unsafe { Self::from_u32_unchecked(value) }
}
#[doc = r" Creates a new index from a given `u32`."]
#[doc = r""]
#[doc = r" # Safety"]
#[doc = r""]
#[doc =
r" The provided value must be less than or equal to the maximum value for the newtype."]
#[doc =
r" Providing a value outside this range is undefined due to layout restrictions."]
#[doc = r""]
#[doc = r" Prefer using `from_u32`."]
#[inline]
const unsafe fn from_u32_unchecked(value: u32) -> Self {
Self {
private_use_as_methods_instead: unsafe {
std::mem::transmute(value)
},
}
}
#[doc = r" Extracts the value of this index as a `usize`."]
#[inline]
const fn index(self) -> usize { self.as_usize() }
#[doc = r" Extracts the value of this index as a `u32`."]
#[inline]
const fn as_u32(self) -> u32 {
unsafe { std::mem::transmute(self.private_use_as_methods_instead) }
}
#[doc = r" Extracts the value of this index as a `usize`."]
#[inline]
const fn as_usize(self) -> usize { self.as_u32() as usize }
}
impl std::ops::Add<usize> for LintStackIndex {
type Output = Self;
#[inline]
fn add(self, other: usize) -> Self {
Self::from_usize(self.index() + other)
}
}
impl std::ops::AddAssign<usize> for LintStackIndex {
#[inline]
fn add_assign(&mut self, other: usize) { *self = *self + other; }
}
impl rustc_index::Idx for LintStackIndex {
#[inline]
fn new(value: usize) -> Self { Self::from_usize(value) }
#[inline]
fn index(self) -> usize { self.as_usize() }
}
impl From<LintStackIndex> for u32 {
#[inline]
fn from(v: LintStackIndex) -> u32 { v.as_u32() }
}
impl From<LintStackIndex> for usize {
#[inline]
fn from(v: LintStackIndex) -> usize { v.as_usize() }
}
impl From<usize> for LintStackIndex {
#[inline]
fn from(value: usize) -> Self { Self::from_usize(value) }
}
impl From<u32> for LintStackIndex {
#[inline]
fn from(value: u32) -> Self { Self::from_u32(value) }
}
impl ::std::cmp::Eq for LintStackIndex {}
impl ::std::cmp::PartialEq for LintStackIndex {
fn eq(&self, other: &Self) -> bool { self.as_u32().eq(&other.as_u32()) }
}
impl ::std::marker::StructuralPartialEq for LintStackIndex {}
impl ::std::hash::Hash for LintStackIndex {
fn hash<H: ::std::hash::Hasher>(&self, state: &mut H) {
self.as_u32().hash(state)
}
}
impl ::std::fmt::Debug for LintStackIndex {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
fmt.write_fmt(format_args!("{0}", self.as_u32()))
}
}rustc_index::newtype_index! {
59 struct LintStackIndex {
60 const COMMAND_LINE = 0;
61 }
62}
63
64#[derive(#[automatically_derived]
impl ::core::fmt::Debug for LintSet {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "LintSet",
"specs", &self.specs, "parent", &&self.parent)
}
}Debug)]
73struct LintSet {
74 specs: FxIndexMap<LintId, UnstableLevelSpec>,
75 parent: LintStackIndex,
76}
77
78impl LintLevelSets {
79 fn new() -> Self {
80 LintLevelSets { list: IndexVec::new() }
81 }
82
83 fn get_lint_level_spec(
84 &self,
85 lint: &'static Lint,
86 idx: LintStackIndex,
87 aux: Option<&FxIndexMap<LintId, UnstableLevelSpec>>,
88 sess: &Session,
89 ) -> UnstableLevelSpec {
90 reveal_actual_level_spec(sess, LintId::of(lint), |id| {
91 self.raw_lint_level_spec(id, idx, aux)
92 })
93 }
94
95 fn raw_lint_level_spec(
96 &self,
97 id: LintId,
98 mut idx: LintStackIndex,
99 aux: Option<&FxIndexMap<LintId, UnstableLevelSpec>>,
100 ) -> Option<UnstableLevelSpec> {
101 if let Some(specs) = aux
102 && let Some(level_spec) = specs.get(&id)
103 {
104 return Some(*level_spec);
105 }
106
107 loop {
108 let LintSet { ref specs, parent } = self.list[idx];
109 if let Some(level_spec) = specs.get(&id) {
110 return Some(*level_spec);
111 }
112 if idx == COMMAND_LINE {
113 return None;
114 }
115 idx = parent;
116 }
117 }
118}
119
120fn skippable_lints(tcx: TyCtxt<'_>, (): ()) -> UnordSet<LintId> {
121 let store = unerased_lint_store(&tcx.sess);
122 let root_map = tcx.shallow_lint_levels_on(hir::CRATE_OWNER_ID);
123
124 let mut skippable: FxHashSet<LintId> = store
125 .get_lints()
126 .into_iter()
127 .filter(|lint| {
128 let has_future_breakage =
130 lint.future_incompatible.is_some_and(|fut| fut.report_in_deps);
131 !has_future_breakage && !lint.eval_always
132 })
133 .filter(|lint| {
134 let level_spec =
135 root_map.lint_level_spec_at_node(tcx, LintId::of(lint), hir::CRATE_HIR_ID);
136 level_spec.is_allow()
138 || (#[allow(non_exhaustive_omitted_patterns)] match level_spec.src {
LintLevelSource::Default => true,
_ => false,
}matches!(level_spec.src, LintLevelSource::Default)
139 && lint.default_level(tcx.sess.edition()) == Level::Allow)
140 })
141 .map(|lint| LintId::of(*lint))
142 .collect();
143
144 for owner in tcx.hir_crate_items(()).owners() {
145 let map = tcx.shallow_lint_levels_on(owner);
146
147 for (_, specs) in map.specs.iter() {
149 for (lint, level_spec) in specs.iter() {
150 if !level_spec.is_allow() {
151 skippable.remove(lint);
152 }
153 }
154 }
155 }
156
157 skippable.into()
158}
159
160{}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() || { false }
{
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("shallow_lint_levels_on",
"rustc_lint::levels", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/7189d39d9ce936881b8132c6addeaf3e295cd455/compiler/rustc_lint/src/levels.rs"),
::tracing_core::__macro_support::Option::Some(160u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::levels"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("owner")
}> =
::tracing::__macro_support::FieldName::new("owner");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::TRACE <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&owner)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
(move ||
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy
:: needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: ShallowLintLevelMap =
loop {};
return __tracing_attr_fake_return;
}
{
let store = unerased_lint_store(tcx.sess);
let attrs = tcx.hir_attr_map(owner);
let mut levels =
LintLevelsBuilder {
sess: tcx.sess,
features: tcx.features(),
provider: LintLevelQueryMap {
tcx,
cur: owner.into(),
specs: ShallowLintLevelMap::default(),
empty: FxIndexMap::default(),
attrs,
},
lint_added_lints: false,
store,
registered_lint_tools: tcx.registered_lint_tools(()),
};
if owner == hir::CRATE_OWNER_ID {
levels.add_command_line();
}
match attrs.map.range(..) {
[] => {}
&[(local_id, _)] =>
levels.add_id(HirId { owner, local_id }),
_ =>
match tcx.hir_owner_node(owner) {
hir::OwnerNode::Item(item) => levels.visit_item(item),
hir::OwnerNode::ForeignItem(item) =>
levels.visit_foreign_item(item),
hir::OwnerNode::TraitItem(item) =>
levels.visit_trait_item(item),
hir::OwnerNode::ImplItem(item) =>
levels.visit_impl_item(item),
hir::OwnerNode::Crate(mod_) => {
levels.add_id(hir::CRATE_HIR_ID);
levels.visit_mod(mod_, mod_.spans.inner_span, CRATE_MOD_ID)
}
hir::OwnerNode::Synthetic =>
::core::panicking::panic("internal error: entered unreachable code"),
},
}
let specs = levels.provider.specs;
for (_, v) in specs.specs.iter() {
if true {
if !!v.is_empty() {
::core::panicking::panic("assertion failed: !v.is_empty()")
};
};
}
specs
}
})();
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/7189d39d9ce936881b8132c6addeaf3e295cd455/compiler/rustc_lint/src/levels.rs:160",
"rustc_lint::levels", ::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("/rustc-dev/7189d39d9ce936881b8132c6addeaf3e295cd455/compiler/rustc_lint/src/levels.rs"),
::tracing_core::__macro_support::Option::Some(160u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::levels"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("return")
}> =
::tracing::__macro_support::FieldName::new("return");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
x;#[instrument(level = "trace", skip(tcx), ret)]
161fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap {
162 let store = unerased_lint_store(tcx.sess);
163 let attrs = tcx.hir_attr_map(owner);
164
165 let mut levels = LintLevelsBuilder {
166 sess: tcx.sess,
167 features: tcx.features(),
168 provider: LintLevelQueryMap {
169 tcx,
170 cur: owner.into(),
171 specs: ShallowLintLevelMap::default(),
172 empty: FxIndexMap::default(),
173 attrs,
174 },
175 lint_added_lints: false,
176 store,
177 registered_lint_tools: tcx.registered_lint_tools(()),
178 };
179
180 if owner == hir::CRATE_OWNER_ID {
181 levels.add_command_line();
182 }
183
184 match attrs.map.range(..) {
185 [] => {}
187 &[(local_id, _)] => levels.add_id(HirId { owner, local_id }),
189 _ => match tcx.hir_owner_node(owner) {
193 hir::OwnerNode::Item(item) => levels.visit_item(item),
194 hir::OwnerNode::ForeignItem(item) => levels.visit_foreign_item(item),
195 hir::OwnerNode::TraitItem(item) => levels.visit_trait_item(item),
196 hir::OwnerNode::ImplItem(item) => levels.visit_impl_item(item),
197 hir::OwnerNode::Crate(mod_) => {
198 levels.add_id(hir::CRATE_HIR_ID);
199 levels.visit_mod(mod_, mod_.spans.inner_span, CRATE_MOD_ID)
200 }
201 hir::OwnerNode::Synthetic => unreachable!(),
202 },
203 }
204
205 let specs = levels.provider.specs;
206
207 #[cfg(debug_assertions)]
208 for (_, v) in specs.specs.iter() {
209 debug_assert!(!v.is_empty());
210 }
211
212 specs
213}
214
215pub struct TopDown {
216 sets: LintLevelSets,
217 cur: LintStackIndex,
218}
219
220pub trait LintLevelsProvider {
221 type LintExpectationId: Copy + Debug + Into<LintExpectationId>;
222
223 fn current_specs(&self) -> &FxIndexMap<LintId, LevelSpec<Self::LintExpectationId>>;
224
225 fn insert(&mut self, id: LintId, level_spec: LevelSpec<Self::LintExpectationId>);
226
227 fn get_lint_level_spec(
228 &self,
229 lint: &'static Lint,
230 sess: &Session,
231 ) -> LevelSpec<Self::LintExpectationId>;
232
233 fn push_expectation(&mut self, id: Self::LintExpectationId, expectation: LintExpectation);
234
235 fn mk_lint_expectation_id(&self, attr_id: AttrId, lint_index: u16) -> Self::LintExpectationId;
236}
237
238impl LintLevelsProvider for TopDown {
239 type LintExpectationId = UnstableLintExpectationId;
240
241 fn current_specs(&self) -> &FxIndexMap<LintId, UnstableLevelSpec> {
242 &self.sets.list[self.cur].specs
243 }
244
245 fn insert(&mut self, id: LintId, level_spec: UnstableLevelSpec) {
246 self.sets.list[self.cur].specs.insert(id, level_spec);
247 }
248
249 fn get_lint_level_spec(&self, lint: &'static Lint, sess: &Session) -> UnstableLevelSpec {
250 self.sets.get_lint_level_spec(lint, self.cur, Some(self.current_specs()), sess)
251 }
252
253 fn push_expectation(&mut self, _: Self::LintExpectationId, _: LintExpectation) {}
254
255 fn mk_lint_expectation_id(&self, attr_id: AttrId, lint_index: u16) -> Self::LintExpectationId {
256 UnstableLintExpectationId { attr_id, lint_index }
257 }
258}
259
260struct LintLevelQueryMap<'tcx> {
261 tcx: TyCtxt<'tcx>,
262 cur: HirId,
263 specs: ShallowLintLevelMap,
264 empty: FxIndexMap<LintId, StableLevelSpec>,
266 attrs: &'tcx hir::AttributeMap<'tcx>,
267}
268
269impl LintLevelsProvider for LintLevelQueryMap<'_> {
270 type LintExpectationId = StableLintExpectationId;
271
272 fn current_specs(&self) -> &FxIndexMap<LintId, StableLevelSpec> {
273 self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty)
274 }
275
276 fn insert(&mut self, id: LintId, level_spec: StableLevelSpec) {
277 self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, level_spec);
278 }
279
280 fn get_lint_level_spec(&self, lint: &'static Lint, _: &Session) -> StableLevelSpec {
281 self.specs.lint_level_spec_at_node(self.tcx, LintId::of(lint), self.cur)
282 }
283
284 fn push_expectation(&mut self, id: Self::LintExpectationId, expectation: LintExpectation) {
285 self.specs.expectations.push((id, expectation))
286 }
287
288 fn mk_lint_expectation_id(&self, _attr_id: AttrId, lint_index: u16) -> Self::LintExpectationId {
289 StableLintExpectationId { hir_id: self.cur, lint_index }
290 }
291}
292
293impl<'tcx> LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
294 fn add_id(&mut self, hir_id: HirId) {
295 self.provider.cur = hir_id;
296 self.add(self.provider.attrs.get(hir_id.local_id), hir_id == hir::CRATE_HIR_ID);
297 }
298}
299
300impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
301 type NestedFilter = nested_filter::OnlyBodies;
302
303 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
304 self.provider.tcx
305 }
306
307 fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
308 self.add_id(param.hir_id);
309 intravisit::walk_param(self, param);
310 }
311
312 fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
313 self.add_id(it.hir_id());
314 intravisit::walk_item(self, it);
315 }
316
317 fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
318 self.add_id(it.hir_id());
319 intravisit::walk_foreign_item(self, it);
320 }
321
322 fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
323 self.add_id(s.hir_id);
324 intravisit::walk_stmt(self, s);
325 }
326
327 fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
328 self.add_id(e.hir_id);
329 intravisit::walk_expr(self, e);
330 }
331
332 fn visit_pat_field(&mut self, f: &'tcx hir::PatField<'tcx>) -> Self::Result {
333 self.add_id(f.hir_id);
334 intravisit::walk_pat_field(self, f);
335 }
336
337 fn visit_expr_field(&mut self, f: &'tcx hir::ExprField<'tcx>) {
338 self.add_id(f.hir_id);
339 intravisit::walk_expr_field(self, f);
340 }
341
342 fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) {
343 self.add_id(s.hir_id);
344 intravisit::walk_field_def(self, s);
345 }
346
347 fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
348 self.add_id(v.hir_id);
349 intravisit::walk_variant(self, v);
350 }
351
352 fn visit_local(&mut self, l: &'tcx hir::LetStmt<'tcx>) {
353 self.add_id(l.hir_id);
354 intravisit::walk_local(self, l);
355 }
356
357 fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
358 self.add_id(a.hir_id);
359 intravisit::walk_arm(self, a);
360 }
361
362 fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
363 self.add_id(trait_item.hir_id());
364 intravisit::walk_trait_item(self, trait_item);
365 }
366
367 fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
368 self.add_id(impl_item.hir_id());
369 intravisit::walk_impl_item(self, impl_item);
370 }
371}
372
373pub struct LintLevelsBuilder<'s, P> {
374 sess: &'s Session,
375 features: &'s Features,
376 provider: P,
377 lint_added_lints: bool,
378 store: &'s LintStore,
379 registered_lint_tools: &'s RegisteredTools,
380}
381
382pub(crate) struct BuilderPush {
383 prev: LintStackIndex,
384}
385
386impl<'s> LintLevelsBuilder<'s, TopDown> {
387 pub(crate) fn new(
388 sess: &'s Session,
389 features: &'s Features,
390 lint_added_lints: bool,
391 store: &'s LintStore,
392 registered_lint_tools: &'s RegisteredTools,
393 ) -> Self {
394 let mut builder = LintLevelsBuilder {
395 sess,
396 features,
397 provider: TopDown { sets: LintLevelSets::new(), cur: COMMAND_LINE },
398 lint_added_lints,
399 store,
400 registered_lint_tools,
401 };
402 builder.process_command_line();
403 {
match (&builder.provider.sets.list.len(), &1) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(builder.provider.sets.list.len(), 1);
404 builder
405 }
406
407 pub fn crate_root(
408 sess: &'s Session,
409 features: &'s Features,
410 lint_added_lints: bool,
411 store: &'s LintStore,
412 registered_lint_tools: &'s RegisteredTools,
413 crate_attrs: &[ast::Attribute],
414 ) -> Self {
415 let mut builder = Self::new(sess, features, lint_added_lints, store, registered_lint_tools);
416 builder.add(crate_attrs, true);
417 builder
418 }
419
420 fn process_command_line(&mut self) {
421 self.provider.cur = self
422 .provider
423 .sets
424 .list
425 .push(LintSet { specs: FxIndexMap::default(), parent: COMMAND_LINE });
426 self.add_command_line();
427 }
428
429 pub(crate) fn push(&mut self, attrs: &[ast::Attribute], is_crate_node: bool) -> BuilderPush {
444 let prev = self.provider.cur;
445 self.provider.cur =
446 self.provider.sets.list.push(LintSet { specs: FxIndexMap::default(), parent: prev });
447
448 self.add(attrs, is_crate_node);
449
450 if self.provider.current_specs().is_empty() {
451 self.provider.sets.list.pop();
452 self.provider.cur = prev;
453 }
454
455 BuilderPush { prev }
456 }
457
458 pub(crate) fn pop(&mut self, push: BuilderPush) {
460 self.provider.cur = push.prev;
461 std::mem::forget(push);
462 }
463}
464
465#[cfg(debug_assertions)]
466impl Drop for BuilderPush {
467 fn drop(&mut self) {
468 {
::core::panicking::panic_fmt(format_args!("Found a `push` without a `pop`."));
};panic!("Found a `push` without a `pop`.");
469 }
470}
471
472impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P>
473where
474 LevelSpec<P::LintExpectationId>: Into<LevelSpec>,
475{
476 pub(crate) fn sess(&self) -> &Session {
477 self.sess
478 }
479
480 pub(crate) fn features(&self) -> &Features {
481 self.features
482 }
483
484 fn add_command_line(&mut self) {
485 for &(ref lint_name, level) in &self.sess.opts.lint_opts {
486 let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
488 if lint_name_only == crate::WARNINGS.name_lower() && #[allow(non_exhaustive_omitted_patterns)] match level {
Level::ForceWarn => true,
_ => false,
}matches!(level, Level::ForceWarn) {
489 self.sess
490 .dcx()
491 .emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
492 }
493 match self.store.check_lint_name(lint_name_only, tool_name, self.registered_lint_tools)
494 {
495 CheckLintNameResult::Renamed(ref replace) => {
496 let name = lint_name.as_str();
497 let suggestion = RenamedLintSuggestion::WithoutSpan { replace };
498 let requested_level = RequestedLevel { level, lint_name };
499 let lint =
500 RenamedLintFromCommandLine { name, replace, suggestion, requested_level };
501 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
502 }
503 CheckLintNameResult::Removed(ref reason) => {
504 let name = lint_name.as_str();
505 let requested_level = RequestedLevel { level, lint_name };
506 let lint = RemovedLintFromCommandLine { name, reason, requested_level };
507 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
508 }
509 CheckLintNameResult::NoLint(suggestion) => {
510 let name = lint_name.clone();
511 let suggestion = suggestion.map(|(replace, from_rustc)| {
512 UnknownLintSuggestion::WithoutSpan { replace, from_rustc }
513 });
514 let requested_level = RequestedLevel { level, lint_name };
515 let lint = UnknownLintFromCommandLine { name, suggestion, requested_level };
516 self.emit_lint(UNKNOWN_LINTS, lint);
517 }
518 CheckLintNameResult::Tool(_, Some(ref replace)) => {
519 let name = lint_name.clone();
520 let requested_level = RequestedLevel { level, lint_name };
521 let lint = DeprecatedLintNameFromCommandLine { name, replace, requested_level };
522 self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
523 }
524 CheckLintNameResult::NoTool => {
525 self.sess.dcx().emit_err(CheckNameUnknownTool {
526 tool_name: tool_name.unwrap(),
527 sub: RequestedLevel { level, lint_name },
528 });
529 }
530 _ => {}
531 };
532
533 let lint_flag_val = Symbol::intern(lint_name);
534
535 let Some(ids) = self.store.find_lints(lint_name) else {
536 continue;
538 };
539 for &id in ids {
540 if let Some(level_spec) = self.provider.current_specs().get(&id)
542 && #[allow(non_exhaustive_omitted_patterns)] match level_spec.level() {
Level::ForceWarn | Level::Forbid => true,
_ => false,
}matches!(level_spec.level(), Level::ForceWarn | Level::Forbid)
543 {
544 continue;
545 }
546
547 if self.check_gated_lint(id, DUMMY_SP, true) {
548 let src = LintLevelSource::CommandLine(lint_flag_val, level);
549 self.provider.insert(id, LevelSpec::new(level, None, src));
550 }
551 }
552 }
553 }
554
555 fn insert_spec(&mut self, id: LintId, level_spec: LevelSpec<P::LintExpectationId>) {
559 let level = level_spec.level();
560 let lint_id = level_spec.lint_id();
561 let src = level_spec.src;
562
563 let old_level_spec = self.provider.get_lint_level_spec(id.lint, self.sess);
564 let old_level = old_level_spec.level();
565 let old_src = old_level_spec.src;
566
567 if self.lint_added_lints && level == Level::Deny && old_level == Level::Forbid {
574 return;
576 } else if self.lint_added_lints && level != Level::Forbid && old_level == Level::Forbid {
577 let fcw_warning = match old_src {
584 LintLevelSource::Default => false,
585 LintLevelSource::Node { name, .. } => self.store.is_lint_group(name),
586 LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
587 };
588 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/7189d39d9ce936881b8132c6addeaf3e295cd455/compiler/rustc_lint/src/levels.rs:588",
"rustc_lint::levels", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/7189d39d9ce936881b8132c6addeaf3e295cd455/compiler/rustc_lint/src/levels.rs"),
::tracing_core::__macro_support::Option::Some(588u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::levels"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("fcw_warning={0:?}, specs.get(&id) = {1:?}, old_src={2:?}, id_name={3:?}",
fcw_warning, self.provider.current_specs(), old_src,
id.lint.name_lower()) as &dyn ::tracing::field::Value))])
});
} else { ; }
};debug!(
589 "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
590 fcw_warning,
591 self.provider.current_specs(),
592 old_src,
593 id.lint.name_lower(),
594 );
595 let sub = match old_src {
596 LintLevelSource::Default => {
597 OverruledAttributeSub::DefaultSource { id: id.to_string() }
598 }
599 LintLevelSource::Node { span, reason, .. } => {
600 OverruledAttributeSub::NodeSource { span, reason }
601 }
602 LintLevelSource::CommandLine(name, _) => {
603 OverruledAttributeSub::CommandLineSource { id: name }
604 }
605 };
606 if !fcw_warning {
607 self.sess.dcx().emit_err(OverruledAttribute {
608 span: src.span(),
609 overruled: src.span(),
610 lint_level: level.as_str(),
611 lint_source: src.name(),
612 sub,
613 });
614 } else {
615 self.emit_span_lint(
616 FORBIDDEN_LINT_GROUPS,
617 src.span().into(),
618 OverruledAttributeLint {
619 overruled: src.span(),
620 lint_level: level.as_str(),
621 lint_source: src.name(),
622 sub,
623 },
624 );
625 }
626
627 if !fcw_warning {
631 return;
632 }
633 }
634
635 if let Level::Expect = level
639 && id == LintId::of(UNFULFILLED_LINT_EXPECTATIONS)
640 {
641 return;
642 }
643
644 match (old_level, level) {
645 (Level::ForceWarn, Level::Expect) => {
647 self.provider.insert(id, LevelSpec::new(Level::ForceWarn, lint_id, old_src))
648 }
649 (Level::ForceWarn, _) => {
651 self.provider.insert(id, LevelSpec::new(Level::ForceWarn, None, old_src))
652 }
653 _ => self.provider.insert(id, LevelSpec::new(level, lint_id, src)),
655 };
656 }
657
658 fn parse_lint_attributes(
659 &mut self,
660 attrs: &[impl AttributeExt + 'static],
661 ) -> ThinVec<LintCheck> {
662 fn try_cast_slice<T: 'static, U: 'static>(slice: &[T]) -> Option<&[U]> {
663 use std::any::TypeId;
664 if TypeId::of::<T>() == TypeId::of::<U>() {
665 unsafe {
667 Some(core::slice::from_raw_parts(slice.as_ptr().cast::<U>(), slice.len()))
668 }
669 } else {
670 None
671 }
672 }
673
674 if let Some(attrs) = try_cast_slice::<_, rustc_attr_ir::Attribute>(attrs) {
675 return {
'done:
{
for i in attrs {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(LintCheck(lints)) => {
break 'done Some(lints.clone());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}find_attr!(attrs, LintCheck(lints) => lints.clone()).unwrap_or_default();
676 }
677
678 let parsed = AttributeParser::parse_limited_all(
679 self.sess,
680 try_cast_slice(attrs).unwrap_or_else(|| {
681 {
::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
format_args!("unknown `&[implAttributeExt]` {0}",
std::any::type_name_of_val(attrs))));
}unreachable!("unknown `&[implAttributeExt]` {}", std::any::type_name_of_val(attrs))
682 }),
683 Some(&|attr| {
684 (attr.path_matches(&[sym::allow])
703 || attr.path_matches(&[sym::warn])
704 || attr.path_matches(&[sym::deny])
705 || attr.path_matches(&[sym::forbid])
706 || attr.path_matches(&[sym::expect]))
707 && attr.meta_item_list().is_some()
708 }),
709 Target::Crate,
710 DUMMY_SP,
711 CRATE_NODE_ID,
712 Some(self.features),
713 ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
714 Some(self.registered_lint_tools),
715 );
716 parsed
717 .into_iter()
718 .find_map(|p| {
719 if let Attribute::Parsed(AttributeKind::LintCheck(lints)) = p {
720 Some(lints)
721 } else {
722 None
723 }
724 })
725 .unwrap_or_default()
726 }
727
728 fn add(&mut self, attrs: &[impl AttributeExt + 'static], is_crate_node: bool) {
729 if attrs.is_empty() {
730 return;
731 }
732 for attr in attrs {
733 if attr.is_automatically_derived_attr() {
734 self.provider.insert(
735 LintId::of(SINGLE_USE_LIFETIMES),
736 LevelSpec::new(Level::Allow, None, LintLevelSource::Default),
737 );
738 continue;
739 }
740
741 if attr.is_doc_hidden() {
743 self.provider.insert(
744 LintId::of(MISSING_DOCS),
745 LevelSpec::new(Level::Allow, None, LintLevelSource::Default),
746 );
747 continue;
748 }
749 }
750 let lint_checks = self.parse_lint_attributes(attrs);
751
752 let sess = self.sess;
753
754 for (lint_index, lint_check) in lint_checks.into_iter().enumerate() {
756 let LintCheck { tool, lint_name, lint_span, kind, reason, attr_id, attr_span: _ } =
757 lint_check;
758
759 let full_lint_name = lint_name.as_str();
760
761 let level = match kind {
762 LintCheckKind::Allow => Level::Allow,
763 LintCheckKind::Warn => Level::Warn,
764 LintCheckKind::Deny => Level::Deny,
765 LintCheckKind::Forbid => Level::Forbid,
766 LintCheckKind::Expect => Level::Expect,
767 };
768
769 let lint_id = (level == Level::Expect)
772 .then(|| self.provider.mk_lint_expectation_id(attr_id.attr_id, lint_index as u16));
773
774 let lint_result = self.store.check_lint_name(
775 full_lint_name,
776 tool.map(|i| i.name),
777 self.registered_lint_tools,
778 );
779
780 let (ids, name) = match lint_result {
781 CheckLintNameResult::Ok(ids) => (ids, lint_name),
782
783 CheckLintNameResult::Tool(ids, new_lint_name) => {
784 let name = match new_lint_name {
785 None => {
786 let complete_name = &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", tool.unwrap().name,
lint_name))
})format!("{}::{lint_name}", tool.unwrap().name);
787 Symbol::intern(complete_name)
788 }
789 Some(new_lint_name) => {
790 self.emit_span_lint(
791 builtin::RENAMED_AND_REMOVED_LINTS,
792 lint_span.into(),
793 DeprecatedLintName {
794 name: lint_name.to_string(),
795 suggestion: lint_span,
796 replace: &new_lint_name,
797 },
798 );
799 Symbol::intern(&new_lint_name)
800 }
801 };
802 (ids, name)
803 }
804
805 CheckLintNameResult::MissingTool => {
806 continue;
811 }
812
813 CheckLintNameResult::NoTool => {
814 sess.dcx().emit_err(UnknownToolInScopedLint {
815 span: Some(tool.unwrap().span),
816 tool_name: tool.unwrap().name,
817 lint_name: full_lint_name.to_string(),
818 is_nightly_build: sess.is_nightly_build(),
819 });
820 continue;
821 }
822
823 CheckLintNameResult::Renamed(ref replace) => {
824 if self.lint_added_lints {
825 let suggestion =
826 RenamedLintSuggestion::WithSpan { suggestion: lint_span, replace };
827 let name = tool
828 .map(|Ident { name, .. }| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", name, full_lint_name))
})format!("{name}::{full_lint_name}"))
829 .unwrap_or_else(|| full_lint_name.to_string());
830 self.emit_span_lint(
831 RENAMED_AND_REMOVED_LINTS,
832 lint_span.into(),
833 RenamedLint { name: name.as_str(), replace, suggestion },
834 );
835 }
836
837 let CheckLintNameResult::Ok(ids) =
843 self.store.check_lint_name(replace, None, self.registered_lint_tools)
844 else {
845 {
::core::panicking::panic_fmt(format_args!("renamed lint does not exist: {0}",
replace));
};panic!("renamed lint does not exist: {replace}");
846 };
847
848 (ids, Symbol::intern(&replace))
849 }
850
851 CheckLintNameResult::Removed(ref reason) => {
852 if self.lint_added_lints {
853 let name = if let Some(Ident { name, .. }) = tool {
854 &::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", name, full_lint_name))
})format!("{name}::{full_lint_name}")
855 } else {
856 full_lint_name
857 };
858 self.emit_span_lint(
859 RENAMED_AND_REMOVED_LINTS,
860 lint_span.into(),
861 RemovedLint { name, reason },
862 );
863 }
864 continue;
865 }
866
867 CheckLintNameResult::NoLint(suggestion) => {
868 if self.lint_added_lints {
869 let name = tool
870 .map(|Ident { name, .. }| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}::{1}", name, full_lint_name))
})format!("{name}::{full_lint_name}"))
871 .unwrap_or_else(|| full_lint_name.to_string());
872 let suggestion = suggestion.map(|(replace, from_rustc)| {
873 UnknownLintSuggestion::WithSpan {
874 suggestion: lint_span,
875 replace,
876 from_rustc,
877 }
878 });
879 self.emit_span_lint(
880 UNKNOWN_LINTS,
881 lint_span.into(),
882 UnknownLint { name, suggestion },
883 );
884 }
885 continue;
886 }
887 };
888
889 let src = LintLevelSource::Node { name, span: lint_span, reason };
890 for &id in ids {
891 if self.check_gated_lint(id, lint_span, false) {
892 self.insert_spec(id, LevelSpec::new(level, lint_id, src));
893 }
894 }
895
896 if let (Level::Expect, Some(expect_id)) = (level, lint_id) {
902 let is_unfulfilled_lint_expectations = match ids {
906 [lint] => *lint == LintId::of(UNFULFILLED_LINT_EXPECTATIONS),
907 _ => false,
908 };
909 self.provider.push_expectation(
910 expect_id,
911 LintExpectation::new(
912 reason,
913 lint_span,
914 is_unfulfilled_lint_expectations,
915 tool.map(|i| i.name),
916 ),
917 );
918 }
919 }
920
921 if self.lint_added_lints && !is_crate_node {
922 for (id, level_spec) in self.provider.current_specs().iter() {
923 if !id.lint.crate_level_only {
924 continue;
925 }
926
927 let LintLevelSource::Node { name: lint_attr_name, span: lint_attr_span, .. } =
928 level_spec.src
929 else {
930 continue;
931 };
932
933 self.emit_span_lint(
934 UNUSED_ATTRIBUTES,
935 lint_attr_span.into(),
936 IgnoredUnlessCrateSpecified {
937 level: level_spec.level().as_str(),
938 name: lint_attr_name,
939 },
940 );
941 break;
943 }
944 }
945 }
946
947 #[track_caller]
951 fn check_gated_lint(&self, lint_id: LintId, span: Span, lint_from_cli: bool) -> bool {
952 let feature = if let Some(feature) = lint_id.lint.feature_gate
953 && !self.features.enabled(feature)
954 && !span.allows_unstable(feature)
955 {
956 feature
958 } else {
959 return true;
961 };
962
963 struct UnknownLint<'a> {
964 sess: &'a Session,
965 lint_id: LintId,
966 feature: Symbol,
967 lint_from_cli: bool,
968 }
969
970 impl<'a, 'b> Diagnostic<'a> for UnknownLint<'b> {
971 fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: rustc_errors::Level) -> Diag<'a> {
972 let Self { sess, lint_id, feature, lint_from_cli } = self;
973 let mut lint = Diag::new(dcx, level, rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("unknown lint: `{$name}`"))msg!("unknown lint: `{$name}`"))
974 .with_arg("name", lint_id.lint.name_lower())
975 .with_note(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the `{$name}` lint is unstable"))msg!("the `{$name}` lint is unstable"));
976 if feature != sym::staged_api {
979 rustc_session::diagnostics::add_feature_diagnostics_for_issue(
980 &mut lint,
981 sess,
982 feature,
983 GateIssue::Language,
984 lint_from_cli,
985 None,
986 );
987 }
988 lint
989 }
990 }
991
992 if self.lint_added_lints {
993 let lint = builtin::UNKNOWN_LINTS;
994 let level_spec = self.lint_level_spec(builtin::UNKNOWN_LINTS);
995 emit_lint_base(
996 self.sess,
997 lint,
998 level_spec,
999 Some(span.into()),
1000 UnknownLint { sess: &self.sess, lint_id, feature, lint_from_cli },
1001 );
1002 }
1003
1004 false
1005 }
1006
1007 pub fn lint_level_spec(&self, lint: &'static Lint) -> LevelSpec<P::LintExpectationId> {
1009 self.provider.get_lint_level_spec(lint, self.sess)
1010 }
1011
1012 #[track_caller]
1015 pub(crate) fn opt_span_lint(
1016 &self,
1017 lint: &'static Lint,
1018 span: Option<MultiSpan>,
1019 decorator: impl for<'a> Diagnostic<'a>,
1020 ) {
1021 let level_spec = self.lint_level_spec(lint);
1022 emit_lint_base(self.sess, lint, level_spec, span, decorator)
1023 }
1024
1025 #[track_caller]
1026 pub fn emit_span_lint(
1027 &self,
1028 lint: &'static Lint,
1029 span: MultiSpan,
1030 decorator: impl for<'a> Diagnostic<'a>,
1031 ) {
1032 let level_spec = self.lint_level_spec(lint);
1033 emit_lint_base(self.sess, lint, level_spec, Some(span), decorator);
1034 }
1035
1036 #[track_caller]
1037 pub fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> Diagnostic<'a>) {
1038 let level_spec = self.lint_level_spec(lint);
1039 emit_lint_base(self.sess, lint, level_spec, None, decorator);
1040 }
1041}
1042
1043pub(crate) fn provide(providers: &mut Providers) {
1044 *providers = Providers { shallow_lint_levels_on, skippable_lints, ..*providers };
1045}
1046
1047pub(crate) fn parse_lint_and_tool_name(lint_name: &str) -> (Option<Symbol>, &str) {
1048 match lint_name.split_once("::") {
1049 Some((tool_name, lint_name)) => {
1050 let tool_name = Symbol::intern(tool_name);
1051
1052 (Some(tool_name), lint_name)
1053 }
1054 None => (None, lint_name),
1055 }
1056}