public alternateGenerator ( |
||
$code_base | ||
Résultat | Generator | The set of all alternates to this method |
/** * @param CodeBase $code_base * The global code base * * @param Method $method * The method we're analyzing arguments for * * @param Node $node * The node holding the method call we're looking at * * @param Context $context * The context in which we see the call * * @return null * * @see \Phan\Deprecated\Pass2::arglist_type_check * Formerly `function arglist_type_check` */ private static function analyzeParameterList(CodeBase $code_base, Method $method, Node $node, Context $context) { foreach ($node->children ?? [] as $i => $argument) { // Get the parameter associated with this argument $parameter = $method->getParameterList()[$i] ?? null; // This issue should be caught elsewhere if (!$parameter) { continue; } // If this is a pass-by-reference parameter, make sure // we're passing an allowable argument if ($parameter->isPassByReference()) { if (!$argument instanceof \ast\Node || $argument->kind != \ast\AST_VAR && $argument->kind != \ast\AST_DIM && $argument->kind != \ast\AST_PROP && $argument->kind != \ast\AST_STATIC_PROP) { Log::err(Log::ETYPE, "Only variables can be passed by reference at arg#" . ($i + 1) . " of {$method->getFQSEN()}()", $context->getFile(), $node->lineno); } else { $variable_name = AST::variableName($argument); if ($argument->kind == \ast\AST_STATIC_PROP) { if (in_array($variable_name, ['self', 'static', 'parent'])) { Log::err(Log::ESTATIC, "Using {$variable_name}:: when not in object context", $context->getFile(), $argument->lineno); } } } } // Get the type of the argument. We'll check it against // the parameter in a moment $argument_type = UnionType::fromNode($context, $code_base, $argument); // Expand it to include all parent types up the chain $argument_type_expanded = $argument_type->asExpandedTypes($code_base); /* TODO see issue #42 If argument is an object and it has a String union type, then we need to ignore that in strict_types=1 mode. if ($argument instanceof \ast\Node) { if(!empty($argument->children['class'])) { // arg is an object if ($method->getContext()->getStrictTypes()) { ... } } } or maybe UnionType::fromNode should check strict_types and not return the string union type or we shouldn't add the string type at all when a class has a __toString() and instead set a flag and check that instead */ // Check the method to see if it has the correct // parameter types. If not, keep hunting through // alternates of the method until we find one that // takes the correct types $alternate_parameter = null; $alternate_found = false; foreach ($method->alternateGenerator($code_base) as $alternate_id => $alternate_method) { if (empty($alternate_method->getParameterList()[$i])) { continue; } // Get the parameter associated with this argument $alternate_parameter = $alternate_method->getParameterList()[$i] ?? null; // Expand the types to find all parents and traits $alternate_parameter_type_expanded = $alternate_parameter->getUnionType()->asExpandedTypes($code_base); // See if the argument can be cast to the // parameter if ($argument_type_expanded->canCastToUnionType($alternate_parameter_type_expanded)) { $alternate_found = true; break; } } if (!$alternate_found) { $parameter_name = $alternate_parameter ? $alternate_parameter->getName() : 'unknown'; $parameter_type = $alternate_parameter ? $alternate_parameter->getUnionType() : 'unknown'; if ($method->getContext()->isInternal()) { Log::err(Log::ETYPE, "arg#" . ($i + 1) . "({$parameter_name}) is " . "{$argument_type_expanded} but {$method->getFQSEN()}() " . "takes {$parameter_type}", $context->getFile(), $node->lineno); } else { Log::err(Log::ETYPE, "arg#" . ($i + 1) . "({$parameter_name}) is " . "{$argument_type_expanded} but {$method->getFQSEN()}() " . "takes {$parameter_type} " . "defined at {$method->getContext()->getFile()}:{$method->getContext()->getLineNumberStart()}", $context->getFile(), $node->lineno); } } } }
/** * @param CodeBase $code_base * The global code base * * @param Method $method * The method we're analyzing arguments for * * @param Node $node * The node holding the method call we're looking at * * @param Context $context * The context in which we see the call * * @return null * * @see \Phan\Deprecated\Pass2::arglist_type_check * Formerly `function arglist_type_check` */ private static function analyzeParameterList(CodeBase $code_base, Method $method, Node $node, Context $context) { foreach ($node->children ?? [] as $i => $argument) { // Get the parameter associated with this argument $parameter = $method->getParameterList()[$i] ?? null; // This issue should be caught elsewhere if (!$parameter) { continue; } // If this is a pass-by-reference parameter, make sure // we're passing an allowable argument if ($parameter->isPassByReference()) { if (!$argument instanceof \ast\Node || $argument->kind != \ast\AST_VAR && $argument->kind != \ast\AST_DIM && $argument->kind != \ast\AST_PROP && $argument->kind != \ast\AST_STATIC_PROP) { Issue::emit(Issue::TypeNonVarPassByRef, $context->getFile(), $node->lineno ?? 0, $i + 1, (string) $method->getFQSEN()); } else { $variable_name = (new ContextNode($code_base, $context, $argument))->getVariableName(); if ($argument->kind == \ast\AST_STATIC_PROP) { if (in_array($variable_name, ['self', 'static', 'parent'])) { Issue::emit(Issue::ContextNotObject, $context->getFile(), $node->lineno ?? 0, "\${$variable_name}"); } } } } // Get the type of the argument. We'll check it against // the parameter in a moment $argument_type = UnionType::fromNode($context, $code_base, $argument); // Expand it to include all parent types up the chain $argument_type_expanded = $argument_type->asExpandedTypes($code_base); // Check the method to see if it has the correct // parameter types. If not, keep hunting through // alternates of the method until we find one that // takes the correct types $alternate_parameter = null; $alternate_found = false; foreach ($method->alternateGenerator($code_base) as $alternate_id => $alternate_method) { if (empty($alternate_method->getParameterList()[$i])) { continue; } // Get the parameter associated with this argument $alternate_parameter = $alternate_method->getParameterList()[$i] ?? null; // Expand the types to find all parents and traits $alternate_parameter_type_expanded = $alternate_parameter->getUnionType()->asExpandedTypes($code_base); // See if the argument can be cast to the // parameter if ($argument_type_expanded->canCastToUnionType($alternate_parameter_type_expanded)) { $alternate_found = true; break; } } if (!$alternate_found) { $parameter_name = $alternate_parameter ? $alternate_parameter->getName() : 'unknown'; $parameter_type = $alternate_parameter ? $alternate_parameter->getUnionType() : 'unknown'; if ($method->getContext()->isInternal()) { Issue::emit(Issue::TypeMismatchArgumentInternal, $context->getFile(), $node->lineno ?? 0, $i + 1, $parameter_name, $argument_type_expanded, (string) $method->getFQSEN(), (string) $parameter_type); } else { Issue::emit(Issue::TypeMismatchArgument, $context->getFile(), $node->lineno ?? 0, $i + 1, $parameter_name, $argument_type_expanded, (string) $method->getFQSEN(), (string) $parameter_type, $method->getContext()->getFile(), $method->getContext()->getLineNumberStart()); } } } }