mago-semantics 1.20.1

PHP Semantics Checker.
Documentation
use mago_php_version::feature::Feature;
use mago_reporting::Annotation;
use mago_reporting::Issue;
use mago_span::HasSpan;
use mago_syntax::ast::Argument;
use mago_syntax::ast::AttributeList;

use crate::internal::context::Context;

#[inline]
pub fn check_attribute_list(attribute_list: &AttributeList, context: &mut Context<'_, '_, '_>) {
    if !context.version.is_supported(Feature::Attributes) {
        context.report(
            Issue::error("Attributes are only available in PHP 8.0 and above.")
                .with_annotation(Annotation::primary(attribute_list.span()).with_message("Attribute list used here."))
                .with_help("Upgrade to PHP 8.0 or above to use attributes."),
        );
    }

    for attr in &attribute_list.attributes {
        let name = attr.name.value();

        if let Some(list) = &attr.argument_list {
            for argument in &list.arguments {
                let (ellipsis, value) = match &argument {
                    Argument::Positional(positional_argument) => {
                        (positional_argument.ellipsis.as_ref(), &positional_argument.value)
                    }
                    Argument::Named(named_argument) => (None, &named_argument.value),
                };

                if let Some(ellipsis) = ellipsis {
                    context.report(
                        Issue::error("Cannot use argument unpacking in attribute arguments.")
                            .with_annotation(
                                Annotation::primary(ellipsis.span()).with_message("Argument unpacking used here."),
                            )
                            .with_annotation(
                                Annotation::secondary(attr.name.span())
                                    .with_message(format!("Attribute `{name}` defined here.")),
                            )
                            .with_note("Unpacking arguments is not allowed in attribute arguments."),
                    );
                }

                if !value.is_constant(&context.version, true) {
                    context.report(
                        Issue::error(format!("Attribute `{name}` argument contains a non-constant expression."))
                            .with_annotations([
                                Annotation::primary(value.span()).with_message("Non-constant expression used here."),
                                Annotation::secondary(attr.name.span())
                                    .with_message(format!("Attribute `{name}` defined here.")),
                            ])
                            .with_note("Attribute arguments must be constant expressions."),
                    );
                }
            }
        }
    }
}