rustc_attr_parsing/attributes/
test_attrs.rs

1use rustc_feature::{AttributeTemplate, template};
2use rustc_hir::Target;
3use rustc_hir::attrs::AttributeKind;
4use rustc_hir::lints::AttributeLintKind;
5use rustc_span::{Symbol, sym};
6
7use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
8use crate::context::MaybeWarn::{Allow, Error};
9use crate::context::{AcceptContext, AllowedTargets, Stage};
10use crate::parser::ArgParser;
11pub(crate) struct IgnoreParser;
12
13impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
14    const PATH: &[Symbol] = &[sym::ignore];
15    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
16    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
17    const ALLOWED_TARGETS: AllowedTargets =
18        AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
19    const TEMPLATE: AttributeTemplate = template!(
20        Word, NameValueStr: "reason",
21        "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
22    );
23
24    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
25        Some(AttributeKind::Ignore {
26            span: cx.attr_span,
27            reason: match args {
28                ArgParser::NoArgs => None,
29                ArgParser::NameValue(name_value) => {
30                    let Some(str_value) = name_value.value_as_str() else {
31                        let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
32                            .suggestions(cx.attr_style, "ignore");
33                        let span = cx.attr_span;
34                        cx.emit_lint(
35                            AttributeLintKind::IllFormedAttributeInput { suggestions },
36                            span,
37                        );
38                        return None;
39                    };
40                    Some(str_value)
41                }
42                ArgParser::List(_) => {
43                    let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE
44                        .suggestions(cx.attr_style, "ignore");
45                    let span = cx.attr_span;
46                    cx.emit_lint(AttributeLintKind::IllFormedAttributeInput { suggestions }, span);
47                    return None;
48                }
49            },
50        })
51    }
52}
53
54pub(crate) struct ShouldPanicParser;
55
56impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
57    const PATH: &[Symbol] = &[sym::should_panic];
58    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
59    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
60    const ALLOWED_TARGETS: AllowedTargets =
61        AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
62    const TEMPLATE: AttributeTemplate = template!(
63        Word, List: &[r#"expected = "reason""#], NameValueStr: "reason",
64        "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
65    );
66
67    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
68        Some(AttributeKind::ShouldPanic {
69            span: cx.attr_span,
70            reason: match args {
71                ArgParser::NoArgs => None,
72                ArgParser::NameValue(name_value) => {
73                    let Some(str_value) = name_value.value_as_str() else {
74                        cx.expected_string_literal(
75                            name_value.value_span,
76                            Some(name_value.value_as_lit()),
77                        );
78                        return None;
79                    };
80                    Some(str_value)
81                }
82                ArgParser::List(list) => {
83                    let Some(single) = list.single() else {
84                        cx.expected_single_argument(list.span);
85                        return None;
86                    };
87                    let Some(single) = single.meta_item() else {
88                        cx.expected_name_value(single.span(), Some(sym::expected));
89                        return None;
90                    };
91                    if !single.path().word_is(sym::expected) {
92                        cx.expected_specific_argument_strings(list.span, vec!["expected"]);
93                        return None;
94                    }
95                    let Some(nv) = single.args().name_value() else {
96                        cx.expected_name_value(single.span(), Some(sym::expected));
97                        return None;
98                    };
99                    let Some(expected) = nv.value_as_str() else {
100                        cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
101                        return None;
102                    };
103                    Some(expected)
104                }
105            },
106        })
107    }
108}