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::get_mixed;
use mago_codex::ttype::get_string;
use mago_span::HasSpan;
use mago_span::Span;
use mago_syntax::cst::Expression;
use mago_syntax::cst::IncludeConstruct;
use mago_syntax::cst::IncludeOnceConstruct;
use mago_syntax::cst::RequireConstruct;
use mago_syntax::cst::RequireOnceConstruct;

use crate::analyzable::Analyzable;
use crate::artifacts::AnalysisArtifacts;
use crate::common::construct::ConstructInput;
use crate::common::construct::analyze_construct_inputs;
use crate::context::Context;
use crate::context::block::BlockContext;
use crate::error::AnalysisError;

impl<'ast, 'arena> Analyzable<'ast, 'arena> for IncludeConstruct<'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,
    {
        analyze_include(
            context,
            block_context,
            artifacts,
            self.span(),
            self.include.span,
            self.value,
            true,  // is_include
            false, // is_once
        )
    }
}

impl<'ast, 'arena> Analyzable<'ast, 'arena> for IncludeOnceConstruct<'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,
    {
        analyze_include(
            context,
            block_context,
            artifacts,
            self.span(),
            self.include_once.span,
            self.value,
            true, // is_include
            true, // is_once
        )
    }
}

impl<'ast, 'arena> Analyzable<'ast, 'arena> for RequireConstruct<'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,
    {
        analyze_include(
            context,
            block_context,
            artifacts,
            self.span(),
            self.require.span,
            self.value,
            false, // is_include
            false, // is_once
        )
    }
}

impl<'ast, 'arena> Analyzable<'ast, 'arena> for RequireOnceConstruct<'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,
    {
        analyze_include(
            context,
            block_context,
            artifacts,
            self.span(),
            self.require_once.span,
            self.value,
            false, // is_include
            true,  // is_once
        )
    }
}

fn analyze_include<'ctx, 'arena, A>(
    context: &mut Context<'ctx, 'arena, A>,
    block_context: &mut BlockContext<'ctx>,
    artifacts: &mut AnalysisArtifacts,
    construct_span: Span,
    keyword_span: Span,
    included_file: &Expression<'arena>,
    is_include: bool,
    is_once: bool,
) -> Result<(), AnalysisError>
where
    A: Arena,
{
    let was_inside_call = block_context.flags.inside_call();
    block_context.flags.set_inside_call(true);
    included_file.analyze(context, block_context, artifacts)?;
    block_context.flags.set_inside_call(was_inside_call);
    let construct_kind = if is_include {
        if is_once { "include_once" } else { "include" }
    } else if is_once {
        "require_once"
    } else {
        "require"
    };

    analyze_construct_inputs(
        context,
        block_context,
        artifacts,
        construct_kind,
        keyword_span,
        ConstructInput::Expression(included_file),
        &get_string(),
        false,
        false,
        true,
    )?;

    artifacts.set_expression_type(&construct_span, get_mixed());

    Ok(())
}