Extract the PHP attribute target bitmask from a class's attribute lists. Scans for `#[\Attribute]` or `#[\Attribute(flags)]` and returns the target bitmask. Returns `0` when the class is not an attribute class. Recognises these patterns: - `#[Attribute]` / `#[\Attribute]` → `TARGET_ALL` (default) - `#[Attribute(Attribute::TARGET_CLASS)]` → `TARGET_CLASS` - `#[Attribute(Attribute::TARGET_CLASS |
(
attribute_lists: &Sequence<'_, AttributeList<'_>>,
content: &str,
)
| 41 | /// - `#[Attribute(TARGET_CLASS | TARGET_METHOD)]` → short-form constants |
| 42 | /// - Numeric literals (e.g. `#[Attribute(1)]`, `#[Attribute(63)]`) |
| 43 | fn extract_attribute_targets( |
| 44 | attribute_lists: &Sequence<'_, AttributeList<'_>>, |
| 45 | content: &str, |
| 46 | ) -> u8 { |
| 47 | use crate::types::attribute_target; |
| 48 | |
| 49 | for attr_list in attribute_lists.iter() { |
| 50 | for attr in attr_list.attributes.iter() { |
| 51 | let short = attr.name.last_segment(); |
| 52 | if short != "Attribute" { |
| 53 | continue; |
| 54 | } |
| 55 | |
| 56 | // `#[\Attribute]` without arguments → TARGET_ALL. |
| 57 | let Some(arg_list) = attr.argument_list.as_ref() else { |
| 58 | return attribute_target::TARGET_ALL; |
| 59 | }; |
| 60 | |
| 61 | // No arguments inside parentheses → TARGET_ALL. |
| 62 | let Some(first_arg) = arg_list.arguments.first() else { |
| 63 | return attribute_target::TARGET_ALL; |
| 64 | }; |
| 65 | |
| 66 | // Extract the raw text of the first argument and parse |
| 67 | // the target flags from it. |
| 68 | let span = first_arg.span(); |
| 69 | let start = span.start.offset as usize; |
| 70 | let end = span.end.offset as usize; |
| 71 | let Some(text) = content.get(start..end) else { |
| 72 | return attribute_target::TARGET_ALL; |
| 73 | }; |
| 74 | |
| 75 | return parse_attribute_target_flags(text); |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | 0 |
| 80 | } |
| 81 | |
| 82 | /// Parse a target-flag expression from the argument to `#[\Attribute(…)]`. |
| 83 | /// |
no test coverage detected