public function testDeclareVar() { $scope = new Scope($this->getMock('PHPParser_Node')); $this->assertNull($scope->getVar('x')); $scope->declareVar('x', $this->registry->getNativeType('integer')); $this->assertNotNull($var = $scope->getVar('x')); $this->assertSame($this->registry->getNativeType('integer'), $var->getType()); $this->assertTrue($var->isTypeInferred()); }
public function getSlot($name) { if (isset($this->symbols[$name])) { return $this->symbols[$name]; } return $this->functionScope->getVar($name); }
private function removeFromUseIfLocal($name, UseLattice $uses) { $var = $this->scope->getVar($name); if (null === $var) { return; } unset($uses[$var]); }
/** * Declares a variable. * * @param string $name * @param array $types * @param boolean $typesInferred */ private function declareVar($name, PhpType $type = null, $typeInferred = true, \PHPParser_Node $nameNode = null) { if ($this->scope->isDeclared($name)) { return $this->scope->getVar($name); } $var = $this->scope->declareVar($name, $type, $typeInferred); if ($nameNode) { $var->setNameNode($nameNode); } return $var; }
private function checkParameterAssignment(\PHPParser_Node_Param $node) { $builder = new UnionTypeBuilder($this->typeRegistry); if (null !== $node->default) { $this->attachLiteralTypes($node->default); $type = $node->default->getAttribute('type'); if ($type) { $builder->addAlternate($type); } } if ('array' === $node->type) { $type = $this->typeRegistry->getNativeType('array'); // If the annotated type also contains the array type, we use the annotated // type as it is potentially more specific, e.g. "array<string>" or "array|null". $annotatedType = $this->commentParser->getTypeFromParamAnnotation($node->getAttribute('parent'), $node->name); if (null !== ($containedArrayType = $this->getContainedArrayType($annotatedType))) { $type = $containedArrayType; } $builder->addAlternate($type); } else { if ($node->type instanceof \PHPParser_Node_Name) { $builder->addAlternate($this->typeRegistry->getClassOrCreate(implode("\\", $node->type->parts))); } } $type = $builder->build(); if ($type->isNoType()) { $type = $this->commentParser->getTypeFromParamAnnotation($node->getAttribute('parent'), $node->name); } else { if ($type->isNullType()) { $commentType = $this->commentParser->getTypeFromParamAnnotation($node->getAttribute('parent'), $node->name); if ($commentType) { $type = $this->typeRegistry->createNullableType($commentType); } else { $type = null; } } else { if ($type->isBooleanType()) { $commentType = $this->commentParser->getTypeFromParamAnnotation($node->getAttribute('parent'), $node->name); if ($commentType) { $type = $this->typeRegistry->createUnionType(array($type, $commentType)); } } } } if (null === $type) { $type = $this->typeRegistry->getNativeType('unknown'); } $node->setAttribute('type', $type); // This could be the case if the same name is used twice as parameter. if (false === $this->scope->isDeclared($node->name)) { $var = $this->scope->declareVar($node->name, $type, null === $type); $var->setNameNode($node); $var->setReference($node->byRef); } else { $var = $this->scope->getVar($node->name); if ($varType = $var->getType()) { $var->setType($this->typeRegistry->createUnionType(array($varType, $type))); } else { if (null !== $type) { $var->setType($type); $var->setTypeInferred(true); } } $var->setReference($node->byRef); } }
private function updateScopeForTypeChange(LinkedFlowScope $scope, \PHPParser_Node $left, PhpType $leftType = null, PhpType $resultType = null, array $castTypes = array()) { assert('null !== $resultType'); switch (true) { case $left instanceof \PHPParser_Node_Expr_Variable && is_string($left->name): $var = $this->syntacticScope->getVar($left->name); // If an explicit type has been annotated for the variable, we // use this instead of whatever the type inference engine has found. if (isset($castTypes[$left->name])) { $resultType = $castTypes[$left->name]; } $this->redeclareSimpleVar($scope, $left, $resultType); $left->setAttribute('type', $resultType); if (null !== $var && $var->isTypeInferred()) { $oldType = $var->getType(); $newType = null === $oldType ? $resultType : $oldType->getLeastSupertype($resultType); $var->setType($newType); } break; case $left instanceof \PHPParser_Node_Expr_ArrayDimFetch: if ($left->var instanceof \PHPParser_Node_Expr_Variable && is_string($left->var->name)) { $varType = $this->getType($left->var); // If the variable type is not known yet, then it has not yet // been initialized. In such a case, it must be an array. if (null === $varType || $varType->isUnknownType()) { $this->redeclareSimpleVar($scope, $left->var, $this->getRefinedArrayType($this->typeRegistry->getNativeType('array'), $resultType, $left)); } else { if ($varType->isArrayType()) { $this->redeclareSimpleVar($scope, $left->var, $this->getRefinedArrayType($varType, $resultType, $left)); } } } else { if (($left->var instanceof \PHPParser_Node_Expr_PropertyFetch || $left->var instanceof \PHPParser_Node_Expr_StaticPropertyFetch) && null !== ($qualifiedName = self::getQualifiedName($left->var))) { $bottomType = $this->getType($left->var); if (null === $bottomType || $bottomType->isUnknownType()) { $refinedArrayType = $this->getRefinedArrayType($this->typeRegistry->getNativeType('array'), $resultType, $left); $scope->inferQualifiedSlot($left->var, $qualifiedName, $bottomType, $refinedArrayType); $left->setAttribute('type', $refinedArrayType); $this->ensurePropertyDefined($left->var, $refinedArrayType); } else { if ($bottomType->isArrayType()) { $refinedArrayType = $this->getRefinedArrayType($bottomType, $resultType, $left); $scope->inferQualifiedSlot($left->var, $qualifiedName, $bottomType, $refinedArrayType); $left->setAttribute('type', $refinedArrayType); $this->ensurePropertyDefined($left->var, $refinedArrayType); } } } } break; case $left instanceof \PHPParser_Node_Expr_PropertyFetch: case $left instanceof \PHPParser_Node_Expr_StaticPropertyFetch: if (null === ($qualifiedName = self::getQualifiedName($left))) { break; } $bottomType = $leftType ?: $this->typeRegistry->getNativeType('unknown'); $scope->inferQualifiedSlot($left, $qualifiedName, $bottomType, $resultType); $left->setAttribute('type', $resultType); $this->ensurePropertyDefined($left, $resultType); break; } }