mago-analyzer 1.12.0

A PHP static analyzer that can detect type errors in PHP code, and provide suggestions for fixing them.
Documentation
use foldhash::HashSet;

use mago_span::Span;
use mago_syntax::ast::ArrowFunction;
use mago_syntax::ast::Class;
use mago_syntax::ast::Closure;
use mago_syntax::ast::DirectVariable;
use mago_syntax::ast::Enum;
use mago_syntax::ast::Expression;
use mago_syntax::ast::Function;
use mago_syntax::ast::Interface;
use mago_syntax::ast::Trait;
use mago_syntax::walker::MutWalker;
use mago_syntax::walker::walk_arrow_function_mut;
use mago_syntax::walker::walk_class_mut;
use mago_syntax::walker::walk_closure_mut;
use mago_syntax::walker::walk_closure_use_clause_mut;
use mago_syntax::walker::walk_enum_mut;
use mago_syntax::walker::walk_function_mut;
use mago_syntax::walker::walk_interface_mut;
use mago_syntax::walker::walk_trait_mut;

#[inline]
pub fn get_variables_referenced_in_expression<'arena>(
    expression: &Expression<'arena>,
    ignore_symbols: bool,
) -> HashSet<(&'arena str, Span)> {
    let mut scanner = VariableScanner { ignore_symbols, ..Default::default() };

    scanner.walk_expression(expression, &mut ());
    scanner.variables
}

#[derive(Debug, Default)]
struct VariableScanner<'arena> {
    ignore_symbols: bool,
    variables: HashSet<(&'arena str, Span)>,
}

impl<'ast, 'arena> MutWalker<'ast, 'arena, ()> for VariableScanner<'arena> {
    #[inline]
    fn walk_in_direct_variable(&mut self, direct_variable: &'ast DirectVariable<'arena>, (): &mut ()) {
        self.variables.insert((direct_variable.name, direct_variable.span));
    }

    #[inline]
    fn walk_arrow_function(&mut self, arrow_function: &'ast ArrowFunction<'arena>, context: &mut ()) {
        if self.ignore_symbols {
            self.walk_expression(arrow_function.expression, context);

            return;
        }

        walk_arrow_function_mut(self, arrow_function, context);
    }

    #[inline]
    fn walk_closure(&mut self, closure: &'ast Closure<'arena>, context: &mut ()) {
        if self.ignore_symbols {
            if let Some(closure_use_clause) = closure.use_clause.as_ref() {
                walk_closure_use_clause_mut(self, closure_use_clause, context);
            }

            return;
        }

        walk_closure_mut(self, closure, context);
    }

    #[inline]
    fn walk_function(&mut self, function: &'ast Function<'arena>, context: &mut ()) {
        if self.ignore_symbols {
            return;
        }

        walk_function_mut(self, function, context);
    }

    #[inline]
    fn walk_class(&mut self, class: &'ast Class<'arena>, context: &mut ()) {
        if self.ignore_symbols {
            return;
        }

        walk_class_mut(self, class, context);
    }

    #[inline]
    fn walk_interface(&mut self, interface: &'ast Interface<'arena>, context: &mut ()) {
        if self.ignore_symbols {
            return;
        }

        walk_interface_mut(self, interface, context);
    }

    #[inline]
    fn walk_trait(&mut self, trait_: &'ast Trait<'arena>, context: &mut ()) {
        if self.ignore_symbols {
            return;
        }

        walk_trait_mut(self, trait_, context);
    }

    #[inline]
    fn walk_enum(&mut self, enum_: &'ast Enum<'arena>, context: &mut ()) {
        if self.ignore_symbols {
            return;
        }

        walk_enum_mut(self, enum_, context);
    }
}