rustc_attr_parsing/attributes/
util.rs

1use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name};
2use rustc_attr_data_structures::RustcVersion;
3use rustc_feature::is_builtin_attr_name;
4use rustc_span::{Symbol, sym};
5
6pub(crate) enum UnsupportedLiteralReason {
7    Generic,
8    CfgString,
9    CfgBoolean,
10    DeprecatedString,
11    DeprecatedKvPair,
12}
13
14pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
15    attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
16}
17
18pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option<Symbol> {
19    first_attr_value_str_by_name(attrs, sym::crate_name)
20}
21
22/// Parse a rustc version number written inside string literal in an attribute,
23/// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
24/// not accepted in this position, unlike when parsing CFG_RELEASE.
25pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
26    let mut components = s.as_str().split('-');
27    let d = components.next()?;
28    if components.next().is_some() {
29        return None;
30    }
31    let mut digits = d.splitn(3, '.');
32    let major = digits.next()?.parse().ok()?;
33    let minor = digits.next()?.parse().ok()?;
34    let patch = digits.next().unwrap_or("0").parse().ok()?;
35    Some(RustcVersion { major, minor, patch })
36}