Skip to main content

rustc_attr_parsing/attributes/
test_attrs.rs

1use rustc_hir::attrs::RustcAbiAttrKind;
2use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
3
4use super::prelude::*;
5
6pub(crate) struct IgnoreParser;
7
8impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
9    const PATH: &[Symbol] = &[sym::ignore];
10    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
11    const ALLOWED_TARGETS: AllowedTargets =
12        AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
13    const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
    word: true,
    list: None,
    one_of: &[],
    name_value_str: Some(&["reason"]),
    docs: Some("https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"),
}template!(
14        Word, NameValueStr: "reason",
15        "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
16    );
17
18    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
19        Some(AttributeKind::Ignore {
20            span: cx.attr_span,
21            reason: match args {
22                ArgParser::NoArgs => None,
23                ArgParser::NameValue(name_value) => {
24                    let Some(str_value) = name_value.value_as_str() else {
25                        cx.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
26                        return None;
27                    };
28                    Some(str_value)
29                }
30                ArgParser::List(list) => {
31                    let help = list.single().and_then(|item| item.meta_item()).and_then(|item| {
32                        item.args().no_args().ok()?;
33                        Some(item.path().to_string())
34                    });
35                    cx.adcx().warn_ill_formed_attribute_input_with_help(
36                        ILL_FORMED_ATTRIBUTE_INPUT,
37                        help,
38                    );
39                    return None;
40                }
41            },
42        })
43    }
44}
45
46pub(crate) struct ShouldPanicParser;
47
48impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
49    const PATH: &[Symbol] = &[sym::should_panic];
50    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
51    const ALLOWED_TARGETS: AllowedTargets =
52        AllowedTargets::AllowListWarnRest(&[Allow(Target::Fn), Error(Target::WherePredicate)]);
53    const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
    word: true,
    list: Some(&[r#"expected = "reason""#]),
    one_of: &[],
    name_value_str: Some(&["reason"]),
    docs: Some("https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"),
}template!(
54        Word, List: &[r#"expected = "reason""#], NameValueStr: "reason",
55        "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
56    );
57
58    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
59        Some(AttributeKind::ShouldPanic {
60            span: cx.attr_span,
61            reason: match args {
62                ArgParser::NoArgs => None,
63                ArgParser::NameValue(name_value) => {
64                    let Some(str_value) = name_value.value_as_str() else {
65                        cx.adcx().expected_string_literal(
66                            name_value.value_span,
67                            Some(name_value.value_as_lit()),
68                        );
69                        return None;
70                    };
71                    Some(str_value)
72                }
73                ArgParser::List(list) => {
74                    let Some(single) = list.single() else {
75                        cx.adcx().expected_single_argument(list.span);
76                        return None;
77                    };
78                    let Some(single) = single.meta_item() else {
79                        cx.adcx().expected_name_value(single.span(), Some(sym::expected));
80                        return None;
81                    };
82                    if !single.path().word_is(sym::expected) {
83                        cx.adcx().expected_specific_argument_strings(list.span, &[sym::expected]);
84                        return None;
85                    }
86                    let Some(nv) = single.args().name_value() else {
87                        cx.adcx().expected_name_value(single.span(), Some(sym::expected));
88                        return None;
89                    };
90                    let Some(expected) = nv.value_as_str() else {
91                        cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
92                        return None;
93                    };
94                    Some(expected)
95                }
96            },
97        })
98    }
99}
100
101pub(crate) struct ReexportTestHarnessMainParser;
102
103impl<S: Stage> SingleAttributeParser<S> for ReexportTestHarnessMainParser {
104    const PATH: &[Symbol] = &[sym::reexport_test_harness_main];
105    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
106    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
107    const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
    word: false,
    list: None,
    one_of: &[],
    name_value_str: Some(&["name"]),
    docs: None,
}template!(NameValueStr: "name");
108
109    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
110        let Some(nv) = args.name_value() else {
111            let inner_span = cx.inner_span;
112            cx.adcx().expected_name_value(
113                args.span().unwrap_or(inner_span),
114                Some(sym::reexport_test_harness_main),
115            );
116            return None;
117        };
118
119        let Some(name) = nv.value_as_str() else {
120            cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
121            return None;
122        };
123
124        Some(AttributeKind::ReexportTestHarnessMain(name))
125    }
126}
127
128pub(crate) struct RustcAbiParser;
129
130impl<S: Stage> SingleAttributeParser<S> for RustcAbiParser {
131    const PATH: &[Symbol] = &[sym::rustc_abi];
132    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
133    const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
    word: false,
    list: None,
    one_of: &[sym::debug, sym::assert_eq],
    name_value_str: None,
    docs: None,
}template!(OneOf: &[sym::debug, sym::assert_eq]);
134    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
135        Allow(Target::TyAlias),
136        Allow(Target::Fn),
137        Allow(Target::ForeignFn),
138        Allow(Target::Method(MethodKind::Inherent)),
139        Allow(Target::Method(MethodKind::Trait { body: true })),
140        Allow(Target::Method(MethodKind::Trait { body: false })),
141        Allow(Target::Method(MethodKind::TraitImpl)),
142    ]);
143
144    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
145        let Some(args) = args.list() else {
146            let attr_span = cx.attr_span;
147            cx.adcx().expected_specific_argument_and_list(attr_span, &[sym::assert_eq, sym::debug]);
148            return None;
149        };
150
151        let Some(arg) = args.single() else {
152            let attr_span = cx.attr_span;
153            cx.adcx().expected_single_argument(attr_span);
154            return None;
155        };
156
157        let mut fail_incorrect_argument =
158            |span| cx.adcx().expected_specific_argument(span, &[sym::assert_eq, sym::debug]);
159
160        let Some(arg) = arg.meta_item() else {
161            fail_incorrect_argument(args.span);
162            return None;
163        };
164
165        let kind: RustcAbiAttrKind = match arg.path().word_sym() {
166            Some(sym::assert_eq) => RustcAbiAttrKind::AssertEq,
167            Some(sym::debug) => RustcAbiAttrKind::Debug,
168            None | Some(_) => {
169                fail_incorrect_argument(arg.span());
170                return None;
171            }
172        };
173
174        Some(AttributeKind::RustcAbi { attr_span: cx.attr_span, kind })
175    }
176}
177
178pub(crate) struct RustcDelayedBugFromInsideQueryParser;
179
180impl<S: Stage> NoArgsAttributeParser<S> for RustcDelayedBugFromInsideQueryParser {
181    const PATH: &[Symbol] = &[sym::rustc_delayed_bug_from_inside_query];
182    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
183    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
184    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDelayedBugFromInsideQuery;
185}
186
187pub(crate) struct RustcEvaluateWhereClausesParser;
188
189impl<S: Stage> NoArgsAttributeParser<S> for RustcEvaluateWhereClausesParser {
190    const PATH: &[Symbol] = &[sym::rustc_evaluate_where_clauses];
191    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
192    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
193        Allow(Target::Fn),
194        Allow(Target::Method(MethodKind::Inherent)),
195        Allow(Target::Method(MethodKind::Trait { body: true })),
196        Allow(Target::Method(MethodKind::TraitImpl)),
197        Allow(Target::Method(MethodKind::Trait { body: false })),
198    ]);
199    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEvaluateWhereClauses;
200}
201
202pub(crate) struct TestRunnerParser;
203
204impl<S: Stage> SingleAttributeParser<S> for TestRunnerParser {
205    const PATH: &[Symbol] = &[sym::test_runner];
206    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
207    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
208    const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
    word: false,
    list: Some(&["path"]),
    one_of: &[],
    name_value_str: None,
    docs: None,
}template!(List: &["path"]);
209
210    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
211        let Some(list) = args.list() else {
212            let attr_span = cx.attr_span;
213            cx.adcx().expected_list(attr_span, args);
214            return None;
215        };
216
217        let Some(single) = list.single() else {
218            cx.adcx().expected_single_argument(list.span);
219            return None;
220        };
221
222        let Some(meta) = single.meta_item() else {
223            cx.adcx().expected_not_literal(single.span());
224            return None;
225        };
226
227        Some(AttributeKind::TestRunner(meta.path().0.clone()))
228    }
229}
230
231pub(crate) struct RustcTestMarkerParser;
232
233impl<S: Stage> SingleAttributeParser<S> for RustcTestMarkerParser {
234    const PATH: &[Symbol] = &[sym::rustc_test_marker];
235    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
236    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
237        Allow(Target::Const),
238        Allow(Target::Fn),
239        Allow(Target::Static),
240    ]);
241    const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
    word: false,
    list: None,
    one_of: &[],
    name_value_str: Some(&["test_path"]),
    docs: None,
}template!(NameValueStr: "test_path");
242
243    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
244        let Some(name_value) = args.name_value() else {
245            let attr_span = cx.attr_span;
246            cx.adcx().expected_name_value(attr_span, Some(sym::rustc_test_marker));
247            return None;
248        };
249
250        let Some(value_str) = name_value.value_as_str() else {
251            cx.adcx().expected_string_literal(name_value.value_span, None);
252            return None;
253        };
254
255        if value_str.as_str().trim().is_empty() {
256            cx.adcx().expected_non_empty_string_literal(name_value.value_span);
257            return None;
258        }
259
260        Some(AttributeKind::RustcTestMarker(value_str))
261    }
262}