getFQSEN() public method

public getFQSEN ( ) : FullyQualifiedMethodName
return Phan\Language\FQSEN\FullyQualifiedMethodName
Example #1
0
 /**
  * @param CodeBase $code_base
  * The code base in which the method exists
  *
  * @param Method $method
  * A method being analyzed
  *
  * @return void
  */
 public function analyzeMethod(CodeBase $code_base, Method $method)
 {
     // Ignore methods inherited by subclasses
     if ($method->getFQSEN() !== $method->getDefiningFQSEN()) {
         return;
     }
     $this->analyzeTypedElement($code_base, $method);
 }
Example #2
0
 /**
  * Check to see if the given Clazz is a duplicate
  *
  * @return null
  */
 public static function analyzeDuplicateFunction(CodeBase $code_base, Method $method)
 {
     $fqsen = $method->getFQSEN();
     if (!$fqsen->isAlternate()) {
         return;
     }
     $original_fqsen = $fqsen->getCanonicalFQSEN();
     if (!$code_base->hasMethod($original_fqsen)) {
         return;
     }
     $original_method = $code_base->getMethod($original_fqsen);
     $method_name = $method->getName();
     if ('internal' === $original_method->getContext()->getFile()) {
         Issue::emit(Issue::RedefineFunctionInternal, $method->getContext()->getFile(), $method->getContext()->getLineNumberStart(), $method_name, $method->getContext()->getFile(), $method->getContext()->getLineNumberStart());
     } else {
         Issue::emit(Issue::RedefineFunction, $method->getContext()->getFile(), $method->getContext()->getLineNumberStart(), $method_name, $method->getContext()->getFile(), $method->getContext()->getLineNumberStart(), $original_method->getContext()->getFile(), $original_method->getContext()->getLineNumberStart());
     }
 }
Example #3
0
 /**
  * Check to see if the given Clazz is a duplicate
  *
  * @return null
  */
 public static function analyzeDuplicateFunction(CodeBase $code_base, Method $method)
 {
     $fqsen = $method->getFQSEN();
     if (!$fqsen->isAlternate()) {
         return;
     }
     $original_fqsen = $fqsen->getCanonicalFQSEN();
     if (!$code_base->hasMethod($original_fqsen)) {
         return;
     }
     $original_method = $code_base->getMethod($original_fqsen);
     $method_name = $method->getName();
     if ('internal' === $original_method->getContext()->getFile()) {
         // If its in an conditional and the original is an
         // internal method, presume its all OK.
         if ($method->getContext()->getIsConditional()) {
             return;
         }
         Log::err(Log::EREDEF, "Function {$method_name} defined at {$method->getContext()->getFile()}:{$method->getContext()->getLineNumberStart()} was previously defined internally", $method->getContext()->getFile(), $method->getContext()->getLineNumberStart());
     } else {
         Log::err(Log::EREDEF, "Function {$method_name} defined at {$method->getContext()->getFile()}:{$method->getContext()->getLineNumberStart()} was previously defined at {$original_method->getContext()->getFile()}:{$original_method->getContext()->getLineNumberStart()}", $method->getContext()->getFile(), $method->getContext()->getLineNumberStart());
     }
 }
Example #4
0
 /**
  * @param Method $method
  * Get a list of methods hydrated with type information
  * for the given partial method
  *
  * @param CodeBase $code_base
  * The global code base holding all state
  *
  * @return Method[]
  * A list of typed methods based on the given method
  */
 private static function methodListFromMethod(Method $method, CodeBase $code_base) : array
 {
     // See if we have any type information for this
     // internal function
     $map_list = UnionType::internalFunctionSignatureMapForFQSEN($method->getFQSEN());
     if (!$map_list) {
         return [$method];
     }
     $alternate_id = 0;
     return array_map(function ($map) use($method, &$alternate_id) : Method {
         $alternate_method = clone $method;
         $alternate_method->setFQSEN($alternate_method->getFQSEN()->withAlternateId($alternate_id++));
         // Set the return type if one is defined
         if (!empty($map['return_type'])) {
             $alternate_method->setUnionType($map['return_type']);
         }
         // Load properties if defined
         foreach ($map['property_name_type_map'] ?? [] as $parameter_name => $parameter_type) {
             $flags = 0;
             $is_optional = false;
             // Check to see if its a pass-by-reference parameter
             if (strpos($parameter_name, '&') === 0) {
                 $flags |= \ast\flags\PARAM_REF;
                 $parameter_name = substr($parameter_name, 1);
             }
             // Check to see if its variadic
             if (strpos($parameter_name, '...') !== false) {
                 $flags |= \ast\flags\PARAM_VARIADIC;
                 $parameter_name = str_replace('...', '', $parameter_name);
             }
             // Check to see if its an optional parameter
             if (strpos($parameter_name, '=') !== false) {
                 $is_optional = true;
                 $parameter_name = str_replace('=', '', $parameter_name);
             }
             $parameter = new Parameter($method->getContext(), $parameter_name, $parameter_type, $flags);
             if ($is_optional) {
                 $parameter->setDefaultValue(null, NullType::instance()->asUnionType());
             }
             // Add the parameter
             $alternate_method->parameter_list[] = $parameter;
         }
         return $alternate_method;
     }, $map_list);
 }
Example #5
0
 /**
  * Check to see if the given Clazz is a duplicate
  *
  * @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
  *
  * @param CodeBase $code_base
  *
  * @return null
  *
  * @see \Phan\Deprecated\Pass2::arg_check
  * Formerly `function arg_check`
  */
 private static function analyzeInternalArgumentType(Method $method, Node $node, Context $context, CodeBase $code_base)
 {
     $arglist = $node->children['args'];
     $argcount = count($arglist->children);
     switch ($method->getName()) {
         case 'join':
         case 'implode':
             // (string glue, array pieces),
             // (array pieces, string glue) or
             // (array pieces)
             if ($argcount == 1) {
                 self::analyzeNodeUnionTypeCast($arglist->children[0], $context, $code_base, ArrayType::instance()->asUnionType(), "arg#1(pieces) is %s but {$method->getFQSEN()}() takes array when passed only 1 arg");
                 return;
             } else {
                 if ($argcount == 2) {
                     $arg1_type = UnionType::fromNode($context, $code_base, $arglist->children[0]);
                     $arg2_type = UnionType::fromNode($context, $code_base, $arglist->children[1]);
                     if ((string) $arg1_type == 'array') {
                         if (!$arg1_type->canCastToUnionType(StringType::instance()->asUnionType())) {
                             Log::err(Log::EPARAM, "arg#2(glue) is {$arg2_type} but {$method->getFQSEN()}() takes string when arg#1 is array", $context->getFile(), $context->getLineNumberStart());
                         }
                     } else {
                         if ((string) $arg1_type == 'string') {
                             if (!$arg2_type->canCastToUnionType(ArrayType::instance()->asUnionType())) {
                                 Log::err(Log::EPARAM, "arg#2(pieces) is {$arg2_type} but {$method->getFQSEN()}() takes array when arg#1 is string", $context->getFile(), $context->getLineNumberStart());
                             }
                         }
                     }
                     return;
                 }
             }
             // Any other arg counts we will let the regular
             // checks handle
             break;
         case 'array_udiff':
         case 'array_diff_uassoc':
         case 'array_uintersect_assoc':
         case 'array_intersect_ukey':
             if ($argcount < 3) {
                 Log::err(Log::EPARAM, "call with {$argcount} arg(s) to {$method->getFQSEN()}() which requires {$method->getNumberOfRequiredParameters()} arg(s)", $context->getFile(), $context->getLineNumberStart());
                 return;
             }
             self::analyzeNodeUnionTypeCast($arglist->children[$argcount - 1], $context, $code_base, CallableType::instance()->asUnionType(), "The last argument to {$method->getFQSEN()} must be a callable");
             for ($i = 0; $i < $argcount - 1; $i++) {
                 self::analyzeNodeUnionTypeCast($arglist->children[$i], $context, $code_base, CallableType::instance()->asUnionType(), "arg#" . ($i + 1) . " is %s but {$method->getFQSEN()}() takes array");
             }
             return;
         case 'array_diff_uassoc':
         case 'array_uintersect_uassoc':
             if ($argcount < 4) {
                 Log::err(Log::EPARAM, "call with {$argcount} arg(s) to {$method->getFQSEN()}() which requires {$method->getNumberOfRequiredParameters()} arg(s)", $context->getFile(), $context->getLineNumberStart());
                 return;
             }
             // The last 2 arguments must be a callable and there
             // can be a variable number of arrays before it
             self::analyzeNodeUnionTypeCast($arglist->children[$argcount - 1], $context, $code_base, CallableType::instance()->asUnionType(), "The last argument to {$method->getFQSEN()} must be a callable");
             self::analyzeNodeUnionTypeCast($arglist->children[$argcount - 2], $context, $code_base, CallableType::instance()->asUnionType(), "The second last argument to {$method->getFQSEN()} must be a callable");
             for ($i = 0; $i < $argcount - 2; $i++) {
                 self::analyzeNodeUnionTypeCast($arglist->children[$i], $context, $code_base, ArrayType::instance()->asUnionType(), "arg#" . ($i + 1) . " is %s but {$method->getFQSEN()}() takes array");
             }
             return;
         case 'strtok':
             // (string str, string token) or (string token)
             if ($argcount == 1) {
                 // If we have just one arg it must be a string token
                 self::analyzeNodeUnionTypeCast($arglist->children[0], $context, $code_base, ArrayType::instance()->asUnionType(), "arg#1(token) is %s but {$method->getFQSEN()}() takes string when passed only one arg");
             }
             // The arginfo check will handle the other case
             break;
         case 'min':
         case 'max':
             if ($argcount == 1) {
                 // If we have just one arg it must be an array
                 if (!self::analyzeNodeUnionTypeCast($arglist->children[0], $context, $code_base, ArrayType::instance()->asUnionType(), "arg#1(values) is %s but {$method->getFQSEN()}() takes array when passed only one arg")) {
                     return;
                 }
             }
             // The arginfo check will handle the other case
             break;
         default:
             break;
     }
 }
Example #6
0
 /**
  * @return array
  * Get a map from column name to row values for
  * this instance
  */
 public function toRow() : array
 {
     return ['scope_name' => $this->primaryKeyValue(), 'fqsen' => (string) $this->method->getFQSEN(), 'name' => (string) $this->method->getName(), 'type' => (string) $this->method->getUnionType(), 'flags' => $this->method->getFlags(), 'context' => base64_encode(serialize($this->method->getContext())), 'is_deprecated' => $this->method->isDeprecated(), 'number_of_required_parameters' => $this->method->getNumberOfRequiredParameters(), 'number_of_optional_parameters' => $this->method->getNumberOfOptionalParameters(), 'is_dynamic' => $this->method->isDynamic()];
 }
Example #7
0
 /**
  * Check to see if the given Clazz is a duplicate
  *
  * @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
  *
  * @param CodeBase $code_base
  *
  * @return null
  *
  * @see \Phan\Deprecated\Pass2::arg_check
  * Formerly `function arg_check`
  */
 private static function analyzeInternalArgumentType(Method $method, Node $node, Context $context, CodeBase $code_base)
 {
     $arglist = $node->children['args'];
     $argcount = count($arglist->children);
     switch ($method->getName()) {
         case 'join':
         case 'implode':
             // (string glue, array pieces),
             // (array pieces, string glue) or
             // (array pieces)
             if ($argcount == 1) {
                 self::analyzeNodeUnionTypeCast($arglist->children[0], $context, $code_base, ArrayType::instance()->asUnionType(), function (UnionType $node_type) use($context, $method) {
                     // "arg#1(pieces) is %s but {$method->getFQSEN()}() takes array when passed only 1 arg"
                     return Issue::fromType(Issue::ParamSpecial2)($context->getFile(), $context->getLineNumberStart(), [1, 'pieces', (string) $method->getFQSEN(), 'string', 'array']);
                 });
                 return;
             } else {
                 if ($argcount == 2) {
                     $arg1_type = UnionType::fromNode($context, $code_base, $arglist->children[0]);
                     $arg2_type = UnionType::fromNode($context, $code_base, $arglist->children[1]);
                     if ((string) $arg1_type == 'array') {
                         if (!$arg1_type->canCastToUnionType(StringType::instance()->asUnionType())) {
                             Issue::emit(Issue::ParamSpecial1, $context->getFile(), $context->getLineNumberStart(), 2, 'glue', (string) $arg2_type, (string) $method->getFQSEN(), 'string', 1, 'array');
                         }
                     } else {
                         if ((string) $arg1_type == 'string') {
                             if (!$arg2_type->canCastToUnionType(ArrayType::instance()->asUnionType())) {
                                 Issue::emit(Issue::ParamSpecial1, $context->getFile(), $context->getLineNumberStart(), 2, 'pieces', (string) $arg2_type, (string) $method->getFQSEN(), 'array', 1, 'string');
                             }
                         }
                     }
                     return;
                 }
             }
             // Any other arg counts we will let the regular
             // checks handle
             break;
         case 'array_udiff':
         case 'array_diff_uassoc':
         case 'array_uintersect_assoc':
         case 'array_intersect_ukey':
             if ($argcount < 3) {
                 Issue::emit(Issue::ParamTooFewInternal, $context->getFile(), $context->getLineNumberStart(), $argcount, (string) $method->getFQSEN(), $method->getNumberOfRequiredParameters());
                 return;
             }
             self::analyzeNodeUnionTypeCast($arglist->children[$argcount - 1], $context, $code_base, CallableType::instance()->asUnionType(), function (UnionType $node_type) use($context, $method) {
                 // "The last argument to {$method->getFQSEN()} must be a callable"
                 return Issue::fromType(Issue::ParamSpecial3)($context->getFile(), $context->getLineNumberStart(), [(string) $method->getFQSEN(), 'callable']);
             });
             for ($i = 0; $i < $argcount - 1; $i++) {
                 self::analyzeNodeUnionTypeCast($arglist->children[$i], $context, $code_base, CallableType::instance()->asUnionType(), function (UnionType $node_type) use($context, $method, $i) {
                     // "arg#".($i+1)." is %s but {$method->getFQSEN()}() takes array"
                     return Issue::fromType(Issue::ParamTypeMismatch)($context->getFile(), $context->getLineNumberStart(), [$i + 1, (string) $node_type, (string) $method->getFQSEN(), 'array']);
                 });
             }
             return;
         case 'array_diff_uassoc':
         case 'array_uintersect_uassoc':
             if ($argcount < 4) {
                 Issue::emit(Issue::ParamTooFewInternal, $context->getFile(), $context->getLineNumberStart(), $argcount, (string) $method->getFQSEN(), $method->getNumberOfRequiredParameters());
                 return;
             }
             // The last 2 arguments must be a callable and there
             // can be a variable number of arrays before it
             self::analyzeNodeUnionTypeCast($arglist->children[$argcount - 1], $context, $code_base, CallableType::instance()->asUnionType(), function (UnionType $node_type) use($context, $method) {
                 // "The last argument to {$method->getFQSEN()} must be a callable"
                 return Issue::fromType(Issue::ParamSpecial3)($context->getFile(), $context->getLineNumberStart(), [(string) $method->getFQSEN(), 'callable']);
             });
             self::analyzeNodeUnionTypeCast($arglist->children[$argcount - 2], $context, $code_base, CallableType::instance()->asUnionType(), function (UnionType $node_type) use($context, $method) {
                 // "The second last argument to {$method->getFQSEN()} must be a callable"
                 return Issue::fromType(Issue::ParamSpecial4)($context->getFile(), $context->getLineNumberStart(), [(string) $method->getFQSEN(), 'callable']);
             });
             for ($i = 0; $i < $argcount - 2; $i++) {
                 self::analyzeNodeUnionTypeCast($arglist->children[$i], $context, $code_base, ArrayType::instance()->asUnionType(), function (UnionType $node_type) use($context, $method, $i) {
                     // "arg#".($i+1)." is %s but {$method->getFQSEN()}() takes array"
                     return Issue::fromType(Issue::ParamTypeMismatch)($context->getFile(), $context->getLineNumberStart(), [$i + 1, (string) $node_type, (string) $method->getFQSEN(), 'array']);
                 });
             }
             return;
         case 'strtok':
             // (string str, string token) or (string token)
             if ($argcount == 1) {
                 // If we have just one arg it must be a string token
                 self::analyzeNodeUnionTypeCast($arglist->children[0], $context, $code_base, ArrayType::instance()->asUnionType(), function (UnionType $node_type) use($context, $method) {
                     // "arg#1(token) is %s but {$method->getFQSEN()}() takes string when passed only one arg"
                     return Issue::fromType(Issue::ParamSpecial2)($context->getFile(), $context->getLineNumberStart(), [1, 'token', (string) $node_type, (string) $method->getFQSEN(), 'string']);
                 });
             }
             // The arginfo check will handle the other case
             break;
         case 'min':
         case 'max':
             if ($argcount == 1) {
                 // If we have just one arg it must be an array
                 if (!self::analyzeNodeUnionTypeCast($arglist->children[0], $context, $code_base, ArrayType::instance()->asUnionType(), function (UnionType $node_type) use($context, $method) {
                     // "arg#1(values) is %s but {$method->getFQSEN()}() takes array when passed only one arg"
                     return Issue::fromType(Issue::ParamSpecial2)($context->getFile(), $context->getLineNumberStart(), [1, 'values', (string) $node_type, (string) $method->getFQSEN(), 'array']);
                 })) {
                     return;
                 }
             }
             // The arginfo check will handle the other case
             break;
         default:
             break;
     }
 }
Example #8
0
File: Clazz.php Project: etsy/phan
 /**
  * Add a method to this class
  *
  * @param CodeBase $code_base
  * A reference to the code base in which the ancestor exists
  *
  * @param Method $method
  * The method to copy onto this class
  *
  * @param Option<Type>|None $type_option
  * A possibly defined type used to define template
  * parameter types when importing the method
  *
  * @return null
  */
 public function addMethod(CodeBase $code_base, Method $method, $type_option)
 {
     $method_fqsen = FullyQualifiedMethodName::make($this->getFQSEN(), $method->getName(), $method->getFQSEN()->getAlternateId());
     // Don't overwrite overridden methods with
     // parent methods
     if ($code_base->hasMethodWithFQSEN($method_fqsen)) {
         // Note that we're overriding something
         $existing_method = $code_base->getMethodByFQSEN($method_fqsen);
         $existing_method->setIsOverride(true);
         // Don't add the method
         return;
     }
     if ($method->getFQSEN() !== $method_fqsen) {
         $method = clone $method;
         $method->setDefiningFQSEN($method->getFQSEN());
         $method->setFQSEN($method_fqsen);
         // If we have a parent type defined, map the method's
         // return type and parameter types through it
         if ($type_option->isDefined()) {
             // Map the method's return type
             if ($method->getUnionType()->hasTemplateType()) {
                 $method->setUnionType($method->getUnionType()->withTemplateParameterTypeMap($type_option->get()->getTemplateParameterTypeMap($code_base)));
             }
             // Map each method parameter
             $method->setParameterList(array_map(function (Parameter $parameter) use($type_option, $code_base) : Parameter {
                 if (!$parameter->getUnionType()->hasTemplateType()) {
                     return $parameter;
                 }
                 $mapped_parameter = clone $parameter;
                 $mapped_parameter->setUnionType($mapped_parameter->getUnionType()->withTemplateParameterTypeMap($type_option->get()->getTemplateParameterTypeMap($code_base)));
                 return $mapped_parameter;
             }, $method->getParameterList()));
         }
     }
     if ($method->getHasYield()) {
         // There's no phpdoc standard for template types of Generators at the moment.
         $newType = UnionType::fromFullyQualifiedString('\\Generator');
         $oldType = $method->getUnionType();
         if (!$newType->canCastToUnionType($method->getUnionType())) {
             $method->setUnionType($newType);
         }
     }
     $code_base->addMethod($method);
 }
Example #9
0
 private function addMethodWithScopeAndName(Method $method, string $scope, string $name)
 {
     $this->method_map[$scope][$name] = $method;
     // For elements that aren't internal PHP classes
     // if (!$method->getContext()->isInternal()) {
     // Associate the element with the file it was found in
     $this->getFileByPath($method->getContext()->getFile())->addMethodFQSEN($method->getFQSEN());
     // }
 }
Example #10
0
 /**
  * @return null
  */
 public function addMethod(CodeBase $code_base, Method $method)
 {
     $method_fqsen = FullyQualifiedMethodName::make($this->getFQSEN(), $method->getName());
     // Don't overwrite overridden methods with
     // parent methods
     if ($code_base->hasMethodWithFQSEN($method_fqsen)) {
         // Note that we're overriding something
         $existing_method = $code_base->getMethodByFQSEN($method_fqsen);
         $existing_method->setIsOverride(true);
         // Don't add the method
         return;
     }
     if ($method->getFQSEN() !== $method_fqsen) {
         $method = clone $method;
         $method->setFQSEN($method_fqsen);
     }
     $code_base->addMethod($method);
 }
Example #11
0
 /**
  * @return void
  */
 public function addMethod(Method $method)
 {
     $this->method_map[strtolower($method->getFQSEN()->getNameWithAlternateId())] = $method;
 }
Example #12
0
 /**
  * @param CodeBase $code_base
  * The code base in which the method exists
  *
  * @param Method $method
  * A method being analyzed
  *
  * @return void
  */
 public function analyzeMethod(CodeBase $code_base, Method $method)
 {
     // As an example, we test to see if the name of the
     // method is `function`, and emit an issue if it is.
     if ($method->getName() == 'function') {
         $this->emitIssue($code_base, $method->getContext(), 'DemoPluginMethodName', "Method {$method->getFQSEN()} cannot be called `function`");
     }
 }
Example #13
0
 private function addMethodWithScopeAndName(Method $method, string $scope, string $name)
 {
     $this->method_map[$scope][$name] = $method;
     // If we're doing dead code detection, map the name
     // directly to the method so we can quickly look up
     // all methods with that name to add a possible
     // reference
     if (Config::get()->dead_code_detection) {
         $this->method_name_map[strtolower($name)][] = $method;
     }
     // Associate the element with the file it was found in
     $this->getFileByPath($method->getContext()->getFile())->addMethodFQSEN($method->getFQSEN());
 }
Example #14
0
File: Clazz.php Project: tpunt/phan
 /**
  * Add a method to this class
  *
  * @param CodeBase $code_base
  * A reference to the code base in which the ancestor exists
  *
  * @param Method $method
  * The method to copy onto this class
  *
  * @param Option<Type> $type_option
  * A possibly defined type used to define template
  * parameter types when importing the method
  *
  * @return null
  */
 public function addMethod(CodeBase $code_base, Method $method, $type_option)
 {
     $method_fqsen = FullyQualifiedMethodName::make($this->getFQSEN(), $method->getName());
     // Don't overwrite overridden methods with
     // parent methods
     if ($code_base->hasMethodWithFQSEN($method_fqsen)) {
         // Note that we're overriding something
         $existing_method = $code_base->getMethodByFQSEN($method_fqsen);
         $existing_method->setIsOverride(true);
         // Don't add the method
         return;
     }
     if ($method->getFQSEN() !== $method_fqsen) {
         $method = clone $method;
         $method->setDefiningFQSEN($method->getFQSEN());
         $method->setFQSEN($method_fqsen);
         // If we have a parent type defined, map the method's
         // return type and parameter types through it
         if ($type_option->isDefined()) {
             // Map the method's return type
             if ($method->getUnionType()->hasTemplateType()) {
                 $method->setUnionType($method->getUnionType()->withTemplateParameterTypeMap($type_option->get()->getTemplateParameterTypeMap($code_base)));
             }
             // Map each method parameter
             $method->setParameterList(array_map(function (Parameter $parameter) use($type_option, $code_base) : Parameter {
                 if (!$parameter->getUnionType()->hasTemplateType()) {
                     return $parameter;
                 }
                 $mapped_parameter = clone $parameter;
                 $mapped_parameter->setUnionType($mapped_parameter->getUnionType()->withTemplateParameterTypeMap($type_option->get()->getTemplateParameterTypeMap($code_base)));
                 return $mapped_parameter;
             }, $method->getParameterList()));
         }
     }
     $code_base->addMethod($method);
 }