alternateGenerator() public method

public alternateGenerator ( CodeBase $code_base ) : Generator
$code_base Phan\CodeBase
return Generator The set of all alternates to this method
Example #1
0
 /**
  * @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);
             }
         }
     }
 }
Example #2
0
 /**
  * @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());
             }
         }
     }
 }