getParameterList() public method

public getParameterList ( ) : Parameter[]
return Parameter[] A list of parameters on the method
Example #1
0
 /**
  * Check method parameters to make sure they're valid
  *
  * @return null
  */
 public static function analyzeParameterTypes(CodeBase $code_base, FunctionInterface $method)
 {
     // Look at each parameter to make sure their types
     // are valid
     foreach ($method->getParameterList() as $parameter) {
         $union_type = $parameter->getUnionType();
         // Look at each type in the parameter's Union Type
         foreach ($union_type->getTypeSet() as $type) {
             // If its a native type or a reference to
             // self, its OK
             if ($type->isNativeType() || $type->isSelfType()) {
                 continue;
             }
             if ($type instanceof TemplateType) {
                 if ($method instanceof Method) {
                     if ($method->isStatic()) {
                         Issue::maybeEmit($code_base, $method->getContext(), Issue::TemplateTypeStaticMethod, $method->getFileRef()->getLineNumberStart(), (string) $method->getFQSEN());
                     }
                 }
             } else {
                 // Make sure the class exists
                 $type_fqsen = $type->asFQSEN();
                 if (!$code_base->hasClassWithFQSEN($type_fqsen)) {
                     Issue::maybeEmit($code_base, $method->getContext(), Issue::UndeclaredTypeParameter, $method->getFileRef()->getLineNumberStart(), (string) $type_fqsen);
                 }
             }
         }
     }
     if ($method instanceof Method) {
         self::analyzeOverrideSignature($code_base, $method);
     }
 }
 /**
  * Check to see if the given Clazz is a duplicate
  *
  * @return null
  */
 public static function analyzeParameterTypes(CodeBase $code_base, FunctionInterface $method)
 {
     // Look at each method parameter
     foreach ($method->getParameterList() as $parameter) {
         $union_type = $parameter->getUnionType();
         // Look at each type in the parameter's Union Type
         foreach ($union_type->getTypeSet() as $type) {
             // If its a native type or a reference to
             // self, its OK
             if ($type->isNativeType() || $type->isSelfType()) {
                 continue;
             }
             // Otherwise, make sure the class exists
             $type_fqsen = $type->asFQSEN();
             if (!$code_base->hasClassWithFQSEN($type_fqsen)) {
                 Issue::emit(Issue::UndeclaredTypeParameter, $method->getFileRef()->getFile(), $method->getFileRef()->getLineNumberStart(), (string) $type_fqsen);
             }
         }
     }
 }
Example #3
0
 /**
  * Analyze the parameters and arguments for a call
  * to the given method or function
  *
  * @param CodeBase $code_base
  * @param Method $method
  * @param Node $node
  *
  * @return null
  */
 private function analyzeCallToMethod(CodeBase $code_base, FunctionInterface $method, Node $node)
 {
     $method->addReference($this->context);
     // Create variables for any pass-by-reference
     // parameters
     $argument_list = $node->children['args'];
     foreach ($argument_list->children as $i => $argument) {
         $parameter = $method->getParameterList()[$i] ?? null;
         if (!$parameter || !is_object($argument)) {
             continue;
         }
         // If pass-by-reference, make sure the variable exists
         // or create it if it doesn't.
         if ($parameter->isPassByReference()) {
             if ($argument->kind == \ast\AST_VAR) {
                 // We don't do anything with it; just create it
                 // if it doesn't exist
                 $variable = (new ContextNode($this->code_base, $this->context, $argument))->getOrCreateVariable();
             } elseif ($argument->kind == \ast\AST_STATIC_PROP || $argument->kind == \ast\AST_PROP) {
                 $property_name = $argument->children['prop'];
                 if (is_string($property_name)) {
                     // We don't do anything with it; just create it
                     // if it doesn't exist
                     try {
                         $property = (new ContextNode($this->code_base, $this->context, $argument))->getOrCreateProperty($argument->children['prop']);
                     } catch (IssueException $exception) {
                         $exception->getIssueInstance()();
                     } catch (\Exception $exception) {
                         // If we can't figure out what kind of a call
                         // this is, don't worry about it
                     }
                 } else {
                     // This is stuff like `Class->$foo`. I'm ignoring
                     // it.
                 }
             }
         }
     }
     // Confirm the argument types are clean
     ArgumentType::analyze($method, $node, $this->context, $this->code_base);
     // Take another pass over pass-by-reference parameters
     // and assign types to passed in variables
     foreach ($argument_list->children as $i => $argument) {
         $parameter = $method->getParameterList()[$i] ?? null;
         if (!$parameter || !is_object($argument)) {
             continue;
         }
         if (Config::get()->dead_code_detection) {
             (new ArgumentVisitor($this->code_base, $this->context))($argument);
         }
         // If the parameter is pass-by-reference and we're
         // passing a variable in, see if we should pass
         // the parameter and variable types to eachother
         $variable = null;
         if ($parameter->isPassByReference()) {
             if ($argument->kind == \ast\AST_VAR) {
                 $variable = (new ContextNode($this->code_base, $this->context, $argument))->getOrCreateVariable();
             } elseif ($argument->kind == \ast\AST_STATIC_PROP || $argument->kind == \ast\AST_PROP) {
                 $property_name = $argument->children['prop'];
                 if (is_string($property_name)) {
                     // We don't do anything with it; just create it
                     // if it doesn't exist
                     try {
                         $variable = (new ContextNode($this->code_base, $this->context, $argument))->getOrCreateProperty($argument->children['prop']);
                     } catch (IssueException $exception) {
                         $exception->getIssueInstance()();
                     } catch (\Exception $exception) {
                         // If we can't figure out what kind of a call
                         // this is, don't worry about it
                     }
                 } else {
                     // This is stuff like `Class->$foo`. I'm ignoring
                     // it.
                 }
             }
             if ($variable) {
                 $variable->getUnionType()->addUnionType($parameter->getUnionType());
             }
         }
     }
     // If we're in quick mode, don't retest methods based on
     // parameter types passed in
     if (Config::get()->quick_mode) {
         return;
     }
     // We're going to hunt to see if any of the arguments
     // have a mismatch with the parameters. If so, we'll
     // re-check the method to see how the parameters impact
     // its return type
     $has_argument_parameter_mismatch = false;
     // Now that we've made sure the arguments are sufficient
     // for definitions on the method, we iterate over the
     // arguments again and add their types to the parameter
     // types so we can test the method again
     $argument_list = $node->children['args'];
     // We create a copy of the parameter list so we can switch
     // back to it after
     $original_parameter_list = $method->getParameterList();
     // Create a backup of the method's scope so that we can
     // reset it after f*****g with it below
     $original_method_scope = $method->getInternalScope();
     foreach ($argument_list->children as $i => $argument) {
         $parameter = $method->getParameterList()[$i] ?? null;
         if (!$parameter) {
             continue;
         }
         // If the parameter has no type, pass the
         // argument's type to it
         if ($parameter->getUnionType()->isEmpty()) {
             $has_argument_parameter_mismatch = true;
             $argument_type = UnionType::fromNode($this->context, $this->code_base, $argument);
             // If this isn't an internal function or method
             // and it has no type, add the argument's type
             // to it so we can compare it to subsequent
             // calls
             if (!$parameter->isInternal()) {
                 // Clone the parameter in the original
                 // parameter list so we can reset it
                 // later
                 $original_parameter_list[$i] = clone $parameter;
                 // Then set the new type on that parameter based
                 // on the argument's type. We'll use this to
                 // retest the method with the passed in types
                 $parameter->getUnionType()->addUnionType($argument_type);
                 if (!is_object($argument)) {
                     continue;
                 }
                 // If we're passing by reference, get the variable
                 // we're dealing with wrapped up and shoved into
                 // the scope of the method
                 if ($parameter->isPassByReference()) {
                     if ($argument->kind == \ast\AST_VAR) {
                         // Get the variable
                         $variable = (new ContextNode($this->code_base, $this->context, $argument))->getOrCreateVariable();
                         $pass_by_reference_variable = new PassByReferenceVariable($parameter, $variable);
                         $parameter_list = $method->getParameterList();
                         $parameter_list[$i] = $pass_by_reference_variable;
                         $method->setParameterList($parameter_list);
                         // Add it to the scope of the function wrapped
                         // in a way that makes it addressable as the
                         // parameter its mimicking
                         $method->getInternalScope()->addVariable($pass_by_reference_variable);
                     } else {
                         if ($argument->kind == \ast\AST_STATIC_PROP) {
                             // Get the variable
                             $property = (new ContextNode($this->code_base, $this->context, $argument))->getOrCreateProperty($argument->children['prop'] ?? '');
                             $pass_by_reference_variable = new PassByReferenceVariable($parameter, $property);
                             $parameter_list = $method->getParameterList();
                             $parameter_list[$i] = $pass_by_reference_variable;
                             $method->setParameterList($parameter_list);
                             // Add it to the scope of the function wrapped
                             // in a way that makes it addressable as the
                             // parameter its mimicking
                             $method->getInternalScope()->addVariable($pass_by_reference_variable);
                         }
                     }
                 } else {
                     // Overwrite the method's variable representation
                     // of the parameter with the parameter with the
                     // new type
                     $method->getInternalScope()->addVariable($parameter);
                 }
             }
         }
     }
     // Now that we know something about the parameters used
     // to call the method, we can reanalyze the method with
     // the types of the parameter, making sure we don't get
     // into an infinite loop of checking calls to the current
     // method in scope
     if ($has_argument_parameter_mismatch && !$method->isInternal() && (!$this->context->isInFunctionLikeScope() || $method->getFQSEN() !== $this->context->getFunctionLikeFQSEN())) {
         $method->analyze($method->getContext(), $code_base);
     }
     // Reset to the original parameter list after having
     // tested the parameters with the types passed in
     $method->setParameterList($original_parameter_list);
     // Reset the scope to its original version before we
     // put new parameters in it
     $method->setInternalScope($original_method_scope);
 }
Example #4
0
 /**
  * @param CodeBase $code_base
  * The global code base
  *
  * @param FunctionInterface $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, FunctionInterface $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::maybeEmit($code_base, $context, Issue::TypeNonVarPassByRef, $node->lineno ?? 0, $i + 1, (string) $method->getFQSEN());
             } else {
                 $variable_name = (new ContextNode($code_base, $context, $argument))->getVariableName();
                 if (Type::isSelfTypeString($variable_name) && !$context->isInClassScope() && $argument->kind == \ast\AST_STATIC_PROP && $argument->kind == \ast\AST_PROP) {
                     Issue::maybeEmit($code_base, $context, Issue::ContextNotObject, $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->isInternal()) {
                 Issue::maybeEmit($code_base, $context, Issue::TypeMismatchArgumentInternal, $node->lineno ?? 0, $i + 1, $parameter_name, $argument_type_expanded, (string) $method->getFQSEN(), (string) $parameter_type);
             } else {
                 Issue::maybeEmit($code_base, $context, Issue::TypeMismatchArgument, $node->lineno ?? 0, $i + 1, $parameter_name, $argument_type_expanded, (string) $method->getFQSEN(), (string) $parameter_type, $method->getFileRef()->getFile(), $method->getFileRef()->getLineNumberStart());
             }
         }
     }
 }