use mago_atom::Atom;
use mago_atom::atom;
use mago_names::scope::NamespaceScope;
use mago_span::HasSpan;
use mago_syntax::ast::AttributeList;
use mago_syntax::ast::Sequence;
use crate::flags::attribute::AttributeFlags;
use crate::metadata::attribute::AttributeMetadata;
use crate::scanner::Context;
use crate::scanner::inference::infer;
#[inline]
pub fn scan_attribute_lists<'arena>(
attribute_lists: &'arena Sequence<'arena, AttributeList<'arena>>,
context: &mut Context<'_, 'arena>,
) -> Vec<AttributeMetadata> {
let mut metadata = vec![];
for attribute_list in attribute_lists {
for attribute in &attribute_list.attributes {
metadata.push(AttributeMetadata {
name: atom(context.resolved_names.get(&attribute.name)),
span: attribute.span(),
});
}
}
metadata
}
#[inline]
pub fn get_attribute_flags<'arena>(
class_like_name: Atom,
attribute_lists: &'arena Sequence<'arena, AttributeList<'arena>>,
context: &mut Context<'_, 'arena>,
scope: &NamespaceScope,
) -> Option<AttributeFlags> {
if class_like_name.eq_ignore_ascii_case("Attribute") {
return Some(AttributeFlags::TARGET_CLASS);
}
for attribute in attribute_lists.iter().flat_map(|list| list.attributes.iter()) {
let attribute_name = context.resolved_names.get(&attribute.name);
if !attribute_name.eq_ignore_ascii_case("Attribute") {
continue;
}
let Some(first_argument) =
attribute.argument_list.as_ref().and_then(|argument_list| argument_list.arguments.first())
else {
return Some(AttributeFlags::TARGET_ALL);
};
let inferred_type = infer(context, scope, first_argument.value());
let bits = inferred_type.and_then(|i| i.get_single_literal_int_value()).and_then(|value| {
if !(0..=255).contains(&value) {
return None;
}
Some(value as u8)
});
return Some(if let Some(bits) = bits {
AttributeFlags::from_bits(bits)
} else {
AttributeFlags::all()
});
}
None
}