1use std::borrow::Cow;
2
3use rustc_ast::AttrStyle;
4use rustc_errors::DiagArgValue;
5use rustc_feature::Features;
6use rustc_hir::lints::AttributeLintKind;
7use rustc_hir::{MethodKind, Target};
8use rustc_span::sym;
9
10use crate::AttributeParser;
11use crate::context::{AcceptContext, Stage};
12use crate::session_diagnostics::InvalidTarget;
13use crate::target_checking::Policy::Allow;
14
15#[derive(#[automatically_derived]
impl ::core::fmt::Debug for AllowedTargets {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
AllowedTargets::AllowList(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"AllowList", &__self_0),
AllowedTargets::AllowListWarnRest(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"AllowListWarnRest", &__self_0),
}
}
}Debug)]
16pub(crate) enum AllowedTargets {
17 AllowList(&'static [Policy]),
18 AllowListWarnRest(&'static [Policy]),
19}
20
21pub(crate) enum AllowedResult {
22 Allowed,
23 Warn,
24 Error,
25}
26
27impl AllowedTargets {
28 pub(crate) fn is_allowed(&self, target: Target) -> AllowedResult {
29 match self {
30 AllowedTargets::AllowList(list) => {
31 if list.contains(&Policy::Allow(target))
32 || list.contains(&Policy::AllowSilent(target))
33 {
34 AllowedResult::Allowed
35 } else if list.contains(&Policy::Warn(target)) {
36 AllowedResult::Warn
37 } else {
38 AllowedResult::Error
39 }
40 }
41 AllowedTargets::AllowListWarnRest(list) => {
42 if list.contains(&Policy::Allow(target))
43 || list.contains(&Policy::AllowSilent(target))
44 {
45 AllowedResult::Allowed
46 } else if list.contains(&Policy::Error(target)) {
47 AllowedResult::Error
48 } else {
49 AllowedResult::Warn
50 }
51 }
52 }
53 }
54
55 pub(crate) fn allowed_targets(&self) -> Vec<Target> {
56 match self {
57 AllowedTargets::AllowList(list) => list,
58 AllowedTargets::AllowListWarnRest(list) => list,
59 }
60 .iter()
61 .filter_map(|target| match target {
62 Policy::Allow(target) => Some(*target),
63 Policy::AllowSilent(_) => None, Policy::Warn(_) => None,
65 Policy::Error(_) => None,
66 })
67 .collect()
68 }
69}
70
71#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Policy {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
Policy::Allow(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Allow",
&__self_0),
Policy::AllowSilent(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"AllowSilent", &__self_0),
Policy::Warn(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Warn",
&__self_0),
Policy::Error(__self_0) =>
::core::fmt::Formatter::debug_tuple_field1_finish(f, "Error",
&__self_0),
}
}
}Debug, #[automatically_derived]
impl ::core::cmp::Eq for Policy {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<Target>;
}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialEq for Policy {
#[inline]
fn eq(&self, other: &Policy) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(Policy::Allow(__self_0), Policy::Allow(__arg1_0)) =>
__self_0 == __arg1_0,
(Policy::AllowSilent(__self_0), Policy::AllowSilent(__arg1_0))
=> __self_0 == __arg1_0,
(Policy::Warn(__self_0), Policy::Warn(__arg1_0)) =>
__self_0 == __arg1_0,
(Policy::Error(__self_0), Policy::Error(__arg1_0)) =>
__self_0 == __arg1_0,
_ => unsafe { ::core::intrinsics::unreachable() }
}
}
}PartialEq)]
73pub(crate) enum Policy {
74 Allow(Target),
76 AllowSilent(Target),
79 Warn(Target),
82 Error(Target),
84}
85
86impl<'sess, S: Stage> AttributeParser<'sess, S> {
87 pub(crate) fn check_target(
88 allowed_targets: &AllowedTargets,
89 target: Target,
90 cx: &mut AcceptContext<'_, 'sess, S>,
91 ) {
92 if let &AllowedTargets::AllowList(&[Allow(Target::Crate)]) = allowed_targets {
95 Self::check_crate_level(target, cx);
96 return;
97 }
98
99 match allowed_targets.is_allowed(target) {
100 AllowedResult::Allowed => {}
101 AllowedResult::Warn => {
102 let allowed_targets = allowed_targets.allowed_targets();
103 let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features);
104 let name = cx.attr_path.clone();
105
106 let lint = if name.segments[0] == sym::deprecated
107 && ![
108 Target::Closure,
109 Target::Expression,
110 Target::Statement,
111 Target::Arm,
112 Target::MacroCall,
113 ]
114 .contains(&target)
115 {
116 rustc_session::lint::builtin::USELESS_DEPRECATED
117 } else {
118 rustc_session::lint::builtin::UNUSED_ATTRIBUTES
119 };
120
121 let attr_span = cx.attr_span;
122 cx.emit_lint(
123 lint,
124 AttributeLintKind::InvalidTarget {
125 name: name.to_string(),
126 target: target.plural_name(),
127 only: if only { "only " } else { "" },
128 applied,
129 attr_span,
130 },
131 attr_span,
132 );
133 }
134 AllowedResult::Error => {
135 let allowed_targets = allowed_targets.allowed_targets();
136 let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features);
137 let name = cx.attr_path.clone();
138 cx.dcx().emit_err(InvalidTarget {
139 span: cx.attr_span.clone(),
140 name,
141 target: target.plural_name(),
142 only: if only { "only " } else { "" },
143 applied: DiagArgValue::StrListSepByAnd(
144 applied.into_iter().map(Cow::Owned).collect(),
145 ),
146 });
147 }
148 }
149 }
150
151 pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess, S>) {
152 if target == Target::Crate {
153 return;
154 }
155
156 let kind = AttributeLintKind::InvalidStyle {
157 name: cx.attr_path.to_string(),
158 is_used_as_inner: cx.attr_style == AttrStyle::Inner,
159 target: target.name(),
160 target_span: cx.target_span,
161 };
162 let attr_span = cx.attr_span;
163
164 cx.emit_lint(rustc_session::lint::builtin::UNUSED_ATTRIBUTES, kind, attr_span);
165 }
166}
167
168pub(crate) fn allowed_targets_applied(
171 mut allowed_targets: Vec<Target>,
172 target: Target,
173 features: Option<&Features>,
174) -> (Vec<String>, bool) {
175 if let Some(features) = features {
177 if !features.fn_delegation() {
178 allowed_targets.retain(|t| !#[allow(non_exhaustive_omitted_patterns)] match t {
Target::Delegation { .. } => true,
_ => false,
}matches!(t, Target::Delegation { .. }));
179 }
180 if !features.stmt_expr_attributes() {
181 allowed_targets.retain(|t| !#[allow(non_exhaustive_omitted_patterns)] match t {
Target::Expression | Target::Statement => true,
_ => false,
}matches!(t, Target::Expression | Target::Statement));
182 }
183 if !features.extern_types() {
184 allowed_targets.retain(|t| !#[allow(non_exhaustive_omitted_patterns)] match t {
Target::ForeignTy => true,
_ => false,
}matches!(t, Target::ForeignTy));
185 }
186 }
187
188 const FUNCTION_LIKE: &[Target] = &[
192 Target::Fn,
193 Target::Closure,
194 Target::ForeignFn,
195 Target::Method(MethodKind::Inherent),
196 Target::Method(MethodKind::Trait { body: false }),
197 Target::Method(MethodKind::Trait { body: true }),
198 Target::Method(MethodKind::TraitImpl),
199 ];
200 const METHOD_LIKE: &[Target] = &[
201 Target::Method(MethodKind::Inherent),
202 Target::Method(MethodKind::Trait { body: false }),
203 Target::Method(MethodKind::Trait { body: true }),
204 Target::Method(MethodKind::TraitImpl),
205 ];
206 const IMPL_LIKE: &[Target] =
207 &[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }];
208 const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum];
209
210 let mut added_fake_targets = Vec::new();
211 filter_targets(
212 &mut allowed_targets,
213 FUNCTION_LIKE,
214 "functions",
215 target,
216 &mut added_fake_targets,
217 );
218 filter_targets(&mut allowed_targets, METHOD_LIKE, "methods", target, &mut added_fake_targets);
219 filter_targets(&mut allowed_targets, IMPL_LIKE, "impl blocks", target, &mut added_fake_targets);
220 filter_targets(&mut allowed_targets, ADT_LIKE, "data types", target, &mut added_fake_targets);
221
222 let mut target_strings: Vec<_> = added_fake_targets
223 .iter()
224 .copied()
225 .chain(allowed_targets.iter().map(|t| t.plural_name()))
226 .map(|i| i.to_string())
227 .collect();
228
229 target_strings.sort();
231
232 let only_target = target_strings.len() == 1;
234
235 (target_strings, only_target)
236}
237
238fn filter_targets(
239 allowed_targets: &mut Vec<Target>,
240 target_group: &'static [Target],
241 target_group_name: &'static str,
242 target: Target,
243 added_fake_targets: &mut Vec<&'static str>,
244) {
245 if target_group.contains(&target) {
246 return;
247 }
248 if allowed_targets.iter().filter(|at| target_group.contains(at)).count() < 2 {
249 return;
250 }
251 allowed_targets.retain(|t| !target_group.contains(t));
252 added_fake_targets.push(target_group_name);
253}
254
255pub(crate) const ALL_TARGETS: &'static [Policy] = {
260 use Policy::Allow;
261 &[
262 Allow(Target::ExternCrate),
263 Allow(Target::Use),
264 Allow(Target::Static),
265 Allow(Target::Const),
266 Allow(Target::Fn),
267 Allow(Target::Closure),
268 Allow(Target::Mod),
269 Allow(Target::ForeignMod),
270 Allow(Target::GlobalAsm),
271 Allow(Target::TyAlias),
272 Allow(Target::Enum),
273 Allow(Target::Variant),
274 Allow(Target::Struct),
275 Allow(Target::Field),
276 Allow(Target::Union),
277 Allow(Target::Trait),
278 Allow(Target::TraitAlias),
279 Allow(Target::Impl { of_trait: false }),
280 Allow(Target::Impl { of_trait: true }),
281 Allow(Target::Expression),
282 Allow(Target::Statement),
283 Allow(Target::Arm),
284 Allow(Target::AssocConst),
285 Allow(Target::Method(MethodKind::Inherent)),
286 Allow(Target::Method(MethodKind::Trait { body: false })),
287 Allow(Target::Method(MethodKind::Trait { body: true })),
288 Allow(Target::Method(MethodKind::TraitImpl)),
289 Allow(Target::AssocTy),
290 Allow(Target::ForeignFn),
291 Allow(Target::ForeignStatic),
292 Allow(Target::ForeignTy),
293 Allow(Target::MacroDef),
294 Allow(Target::Param),
295 Allow(Target::PatField),
296 Allow(Target::ExprField),
297 Allow(Target::WherePredicate),
298 Allow(Target::MacroCall),
299 Allow(Target::Crate),
300 Allow(Target::Delegation { mac: false }),
301 Allow(Target::Delegation { mac: true }),
302 Allow(Target::GenericParam {
303 kind: rustc_hir::target::GenericParamKind::Const,
304 has_default: false,
305 }),
306 Allow(Target::GenericParam {
307 kind: rustc_hir::target::GenericParamKind::Const,
308 has_default: true,
309 }),
310 Allow(Target::GenericParam {
311 kind: rustc_hir::target::GenericParamKind::Lifetime,
312 has_default: false,
313 }),
314 Allow(Target::GenericParam {
315 kind: rustc_hir::target::GenericParamKind::Lifetime,
316 has_default: true,
317 }),
318 Allow(Target::GenericParam {
319 kind: rustc_hir::target::GenericParamKind::Type,
320 has_default: false,
321 }),
322 Allow(Target::GenericParam {
323 kind: rustc_hir::target::GenericParamKind::Type,
324 has_default: true,
325 }),
326 ]
327};