mago-analyzer 1.47.1

A PHP static analyzer that can detect type errors in PHP code, and provide suggestions for fixing them.
Documentation
use mago_allocator::Arena;
use mago_codex::ttype::template::TemplateResult;
use mago_span::HasSpan;
use mago_syntax::cst::Pipe;

use crate::analyzable::Analyzable;
use crate::artifacts::AnalysisArtifacts;
use crate::context::Context;
use crate::context::block::BlockContext;
use crate::error::AnalysisError;
use crate::expression::call::analyze_invocation_targets;
use crate::expression::call::function_call::resolve_targets;
use crate::invocation::InvocationArgumentsSource;

impl<'ast, 'arena> Analyzable<'ast, 'arena> for Pipe<'arena> {
    fn analyze<'ctx, A>(
        &'ast self,
        context: &mut Context<'ctx, 'arena, A>,
        block_context: &mut BlockContext<'ctx>,
        artifacts: &mut AnalysisArtifacts,
    ) -> Result<(), AnalysisError>
    where
        A: Arena,
    {
        let mut template_result = TemplateResult::default();

        let was_inside_pipe_callable = block_context.flags.inside_pipe_callable();
        block_context.flags.set_inside_pipe_callable(true);
        let result = resolve_targets(context, block_context, artifacts, self.callable, &mut template_result);
        block_context.flags.set_inside_pipe_callable(was_inside_pipe_callable);
        let (invocation_targets, encountered_invalid_targets) = result?;

        analyze_invocation_targets(
            context,
            block_context,
            artifacts,
            template_result,
            invocation_targets,
            InvocationArgumentsSource::PipeInput(self),
            self.span(),
            None,
            encountered_invalid_targets,
            false,
            false,
            false, // object_has_nullsafe_null - not applicable for pipe expressions
        )
    }
}

#[cfg(test)]
mod tests {
    use indoc::indoc;

    use crate::code::IssueCode;
    use crate::test_analysis;

    test_analysis! {
        name = pipe_expression_too_many_args,
        code = indoc! {r#"
            <?php

            function do_nothing(): void { return; }

            "foo" |> do_nothing(...);
        "#},
        issues = [
            IssueCode::TooManyArguments,
        ],
    }

    test_analysis! {
        name = pipe_expression_too_few_args,
        code = indoc! {r#"
            <?php

            function do_nothing(int $_a, int $_b): void { return; }

            "foo" |> do_nothing(...);
        "#},
        issues = [
            IssueCode::InvalidArgument, // "foo" is not an int
            IssueCode::TooFewArguments,
        ],
    }

    test_analysis! {
        name = pipe_expression_exact_args,
        code = indoc! {"
            <?php

            function do_nothing(int $_a): void { return; }

            123 |> do_nothing(...);
        "},
    }
}