/** * Take a pass over all functions verifying various * states. * * @return null */ public static function analyzeFunctions(CodeBase $code_base) { $function_count = count($code_base->getFunctionAndMethodSet()); $i = 0; foreach ($code_base->getFunctionAndMethodSet() as $function_or_method) { CLI::progress('method', ++$i / $function_count); if ($function_or_method->isInternal()) { continue; } DuplicateFunctionAnalyzer::analyzeDuplicateFunction($code_base, $function_or_method); ParameterTypesAnalyzer::analyzeParameterTypes($code_base, $function_or_method); // Let any plugins analyze the methods or functions if ($function_or_method instanceof Func) { ConfigPluginSet::instance()->analyzeFunction($code_base, $function_or_method); } else { if ($function_or_method instanceof Method) { ConfigPluginSet::instance()->analyzeMethod($code_base, $function_or_method); } } } }
/** * This method should be called after hydration * * @return void */ public final function analyze(CodeBase $code_base) { if ($this->isInternal()) { return; } // Make sure the parent classes exist ParentClassExistsAnalyzer::analyzeParentClassExists($code_base, $this); DuplicateClassAnalyzer::analyzeDuplicateClass($code_base, $this); ParentConstructorCalledAnalyzer::analyzeParentConstructorCalled($code_base, $this); PropertyTypesAnalyzer::analyzePropertyTypes($code_base, $this); // Analyze this class to make sure that we don't have conflicting // types between similar inherited methods. CompositionAnalyzer::analyzeComposition($code_base, $this); // Let any configured plugins analyze the class ConfigPluginSet::instance()->analyzeClass($code_base, $this); }
/** * For non-special nodes, we propagate the context and scope * from the parent, through the children and return the * modified scope * * │ * ▼ * ┌──● * │ * ●──●──● * │ * ●──┘ * │ * ▼ * * @param Node $node * An AST node we'd like to determine the UnionType * for * * @return Context * The updated context after visiting the node */ public function visit(Node $node) : Context { $context = $this->context->withLineNumberStart($node->lineno ?? 0); // Visit the given node populating the code base // with anything we learn and get a new context // indicating the state of the world within the // given node $context = (new PreOrderAnalysisVisitor($this->code_base, $context))($node); assert(!empty($context), 'Context cannot be null'); // With a context that is inside of the node passed // to this method, we analyze all children of the // node. foreach ($node->children ?? [] as $child_node) { // Skip any non Node children or boring nodes // that are too deep. if (!$child_node instanceof Node || !Analysis::shouldVisit($child_node)) { $context->withLineNumberStart($child_node->lineno ?? 0); continue; } // Step into each child node and get an // updated context for the node $context = (new BlockAnalysisVisitor($this->code_base, $context, $node, $this->depth + 1))($child_node); } // Now that we know all about our context (like what // 'self' means), we can analyze statements like // assignments and method calls. $context = (new PostOrderAnalysisVisitor($this->code_base, $context->withLineNumberStart($node->lineno ?? 0), $this->parent_node))($node); // Let any configured plugins analyze the node ConfigPluginSet::instance()->analyzeNode($this->code_base, $context, $node, $this->parent_node); return $context; }
/** * This method should be called after hydration * * @return void */ protected function analyzeOnce(CodeBase $code_base) { if ($this->isInternal()) { return; } // Analyze this class to make sure that CompositionAnalyzer::analyzeComposition($code_base, $this); // Make sure the parent classes exist ParentClassExistsAnalyzer::analyzeParentClassExists($code_base, $this); DuplicateClassAnalyzer::analyzeDuplicateClass($code_base, $this); ParentConstructorCalledAnalyzer::analyzeParentConstructorCalled($code_base, $this); PropertyTypesAnalyzer::analyzePropertyTypes($code_base, $this); // Let any configured plugins analyze the class ConfigPluginSet::instance()->analyzeClass($code_base, $this); }