Example #1
0
 public function testFullyQualifiedMethodName()
 {
     $this->assertFQSENEqual(FullyQualifiedMethodName::make(FullyQualifiedClassName::make('\\Name\\Space', 'a'), 'f'), '\\Name\\Space\\a::f');
     $this->assertFQSENEqual(FullyQualifiedMethodName::fromFullyQualifiedString('\\Name\\a::f'), '\\Name\\a::f');
     $this->assertFQSENEqual(FullyQualifiedMethodName::fromFullyQualifiedString('Name\\a::f'), '\\Name\\a::f');
     $this->assertFQSENEqual(FullyQualifiedMethodName::fromFullyQualifiedString('\\Name\\Space\\a::f,2'), '\\Name\\Space\\a::f,2');
     $this->assertFQSENEqual(FullyQualifiedMethodName::fromFullyQualifiedString('\\Name\\Space\\a,1::f,2'), '\\Name\\Space\\a,1::f,2');
     $this->assertFQSENEqual(FullyQualifiedMethodName::fromStringInContext('a::methodName', $this->context), '\\a::methodname');
 }
Example #2
0
 /**
  * @return Method[]
  */
 public static function methodListFromReflectionClassAndMethod(Context $context, CodeBase $code_base, \ReflectionClass $class, \ReflectionMethod $reflection_method) : array
 {
     $reflection_method = new \ReflectionMethod($class->getName(), $reflection_method->name);
     $method = new Method($context, $reflection_method->name, new UnionType(), $reflection_method->getModifiers());
     $method->setNumberOfRequiredParameters($reflection_method->getNumberOfRequiredParameters());
     $method->setNumberOfOptionalParameters($reflection_method->getNumberOfParameters() - $reflection_method->getNumberOfRequiredParameters());
     $method->setFQSEN(FullyQualifiedMethodName::fromStringInContext($method->getName(), $context));
     return self::functionListFromFunction($method, $code_base);
 }
Example #3
0
 /**
  * Visit a node with kind `\ast\AST_METHOD`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitMethod(Decl $node) : Context
 {
     // Bomb out if we're not in a class context
     $clazz = $this->getContextClass();
     $method_name = (string) $node->name;
     $method_fqsen = FullyQualifiedMethodName::fromStringInContext($method_name, $this->context);
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasMethodWithFQSEN($method_fqsen)) {
         $method_fqsen = $method_fqsen->withAlternateId(++$alternate_id);
     }
     // Create a new context with a new scope
     $context = $this->context->withScope(new Scope());
     $method = Method::fromNode($context, $this->code_base, $node);
     // Override the FQSEN with the found alternate ID
     $method->setFQSEN($method_fqsen);
     $clazz->addMethod($this->code_base, $method);
     if ('__construct' === $method_name) {
         $clazz->setIsParentConstructorCalled(false);
     } elseif ('__invoke' === $method_name) {
         $clazz->getUnionType()->addType(CallableType::instance());
     } elseif ('__toString' === $method_name && !$this->context->getIsStrictTypes()) {
         $clazz->getUnionType()->addType(StringType::instance());
     }
     // Send the context into the method and reset the scope
     $context = $this->context->withMethodFQSEN($method->getFQSEN());
     return $context;
 }
Example #4
0
 /**
  * @return FullyQualifiedFunctionName|FullyQualifiedMethodName
  */
 public function getFQSEN()
 {
     // Allow overrides
     if ($this->fqsen) {
         return $this->fqsen;
     }
     return FullyQualifiedMethodName::fromStringInContext($this->getName(), $this->getContext());
 }
Example #5
0
 /**
  * Visit a node with kind `\ast\AST_METHOD`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitMethod(Decl $node) : Context
 {
     // Bomb out if we're not in a class context
     $class = $this->getContextClass();
     $method_name = (string) $node->name;
     $method_fqsen = FullyQualifiedMethodName::fromStringInContext($method_name, $this->context);
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasMethodWithFQSEN($method_fqsen)) {
         $method_fqsen = $method_fqsen->withAlternateId(++$alternate_id);
     }
     $method = Method::fromNode(clone $this->context, $this->code_base, $node, $method_fqsen);
     $class->addMethod($this->code_base, $method, new None());
     if ('__construct' === $method_name) {
         $class->setIsParentConstructorCalled(false);
         if ($class->isGeneric()) {
             // Get the set of template type identifiers defined on
             // the class
             $template_type_identifiers = array_keys($class->getTemplateTypeMap());
             // Get the set of template type identifiers defined
             // across all parameter types
             $parameter_template_type_identifiers = [];
             foreach ($method->getParameterList() as $parameter) {
                 foreach ($parameter->getUnionType()->getTypeSet() as $type) {
                     if ($type instanceof TemplateType) {
                         $parameter_template_type_identifiers[] = $type->getName();
                     }
                 }
             }
             $missing_template_type_identifiers = array_diff($template_type_identifiers, $parameter_template_type_identifiers);
             if ($missing_template_type_identifiers) {
                 $this->emitIssue(Issue::GenericConstructorTypes, $node->lineno ?? 0, implode(',', $missing_template_type_identifiers), (string) $class->getFQSEN());
             }
         }
     } elseif ('__invoke' === $method_name) {
         $class->getUnionType()->addType(CallableType::instance());
     } elseif ('__toString' === $method_name && !$this->context->getIsStrictTypes()) {
         $class->getUnionType()->addType(StringType::instance());
     }
     // Create a new context with a new scope
     return $this->context->withScope($method->getInternalScope());
 }
Example #6
0
 /**
  * Visit a node with kind `\ast\AST_METHOD`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitMethod(Node $node) : Context
 {
     // Bomb out if we're not in a class context
     $clazz = $this->getContextClass();
     $method_name = $node->name;
     $method_fqsen = FullyQualifiedMethodName::fromStringInContext($method_name, $this->context);
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasMethod($method_fqsen)) {
         $method_fqsen = $method_fqsen->withAlternateId(++$alternate_id);
     }
     $method = Method::fromNode(clone $this->context, $this->code_base, $node);
     // Override the FQSEN with the found alternate ID
     $method->setFQSEN($method_fqsen);
     $clazz->addMethod($this->code_base, $method);
     if ('__construct' === $method_name) {
         $clazz->setIsParentConstructorCalled(false);
     } else {
         if ('__invoke' === $method_name) {
             $clazz->getUnionType()->addType(CallableType::instance());
         } else {
             if ('__toString' === $method_name) {
                 $clazz->getUnionType()->addType(StringType::instance());
             }
         }
     }
     // Send the context into the method
     $context = $this->context->withMethodFQSEN($method->getFQSEN());
     // Add each method parameter to the scope. We clone it
     // so that changes to the variable don't alter the
     // parameter definition
     foreach ($method->getParameterList() as $parameter) {
         $context->addScopeVariable(clone $parameter);
     }
     return $context;
 }
Example #7
0
 /**
  * Visit a node with kind `\ast\AST_METHOD`
  *
  * @param Node $node
  * A node to parse
  *
  * @return Context
  * A new or an unchanged context resulting from
  * parsing the node
  */
 public function visitMethod(Decl $node) : Context
 {
     // Bomb out if we're not in a class context
     $clazz = $this->getContextClass();
     $method_name = (string) $node->name;
     $method_fqsen = FullyQualifiedMethodName::fromStringInContext($method_name, $this->context);
     // Hunt for an available alternate ID if necessary
     $alternate_id = 0;
     while ($this->code_base->hasMethod($method_fqsen)) {
         $method_fqsen = $method_fqsen->withAlternateId(++$alternate_id);
     }
     // Create a new context with a new scope
     $context = $this->context->withScope(new Scope());
     // Add $this to the scope of non-static methods
     if (!($node->flags & \ast\flags\MODIFIER_STATIC)) {
         assert($clazz->getContext()->getScope()->hasVariableWithName('this'), "Classes must have a \$this variable.");
         $context = $context->withScopeVariable($clazz->getContext()->getScope()->getVariableWithName('this'));
     }
     $method = Method::fromNode($context, $this->code_base, $node);
     // Override the FQSEN with the found alternate ID
     $method->setFQSEN($method_fqsen);
     $clazz->addMethod($this->code_base, $method);
     if ('__construct' === $method_name) {
         $clazz->setIsParentConstructorCalled(false);
     } else {
         if ('__invoke' === $method_name) {
             $clazz->getUnionType()->addType(CallableType::instance());
         } else {
             if ('__toString' === $method_name && !$this->context->getIsStrictTypes()) {
                 $clazz->getUnionType()->addType(StringType::instance());
             }
         }
     }
     // Add each method parameter to the scope. We clone it
     // so that changes to the variable don't alter the
     // parameter definition
     foreach ($method->getParameterList() as $parameter) {
         $method->getContext()->addScopeVariable(clone $parameter);
     }
     // Send the context into the method and reset the scope
     $context = $method->getContext()->withMethodFQSEN($method->getFQSEN());
     return $context;
 }