Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor TypeSpecifier::specifyTypesInCondition() for better readability #3705

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 118 additions & 45 deletions src/Analyser/TypeSpecifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ public function specifyTypesInCondition(
return new SpecifiedTypes([], [], false, [], $rootExpr);
}

// $expr instanceof $class
if ($expr instanceof Instanceof_) {
$exprNode = $expr->expr;
if ($expr->class instanceof Name) {
Expand Down Expand Up @@ -189,56 +190,85 @@ public function specifyTypesInCondition(
if ($context->true()) {
return $this->create($exprNode, new ObjectWithoutClassType(), $context, false, $scope, $rootExpr);
}
} elseif ($expr instanceof Node\Expr\BinaryOp\Identical) {

return new SpecifiedTypes([], [], false, [], $rootExpr);
}

// $left === $right
if ($expr instanceof Node\Expr\BinaryOp\Identical) {
return $this->resolveIdentical($expr, $scope, $context, $rootExpr);
}

} elseif ($expr instanceof Node\Expr\BinaryOp\NotIdentical) {
// $left !== $right
if ($expr instanceof Node\Expr\BinaryOp\NotIdentical) {
return $this->specifyTypesInCondition(
$scope,
new Node\Expr\BooleanNot(new Node\Expr\BinaryOp\Identical($expr->left, $expr->right)),
$context,
$rootExpr,
);
} elseif ($expr instanceof Expr\Cast\Bool_) {
}

// (bool) $expr
if ($expr instanceof Expr\Cast\Bool_) {
return $this->specifyTypesInCondition(
$scope,
new Node\Expr\BinaryOp\Equal($expr->expr, new ConstFetch(new Name\FullyQualified('true'))),
$context,
$rootExpr,
);
} elseif ($expr instanceof Expr\Cast\String_) {
}

// (string) $expr
if ($expr instanceof Expr\Cast\String_) {
return $this->specifyTypesInCondition(
$scope,
new Node\Expr\BinaryOp\NotEqual($expr->expr, new Node\Scalar\String_('')),
$context,
$rootExpr,
);
} elseif ($expr instanceof Expr\Cast\Int_) {
}

// (int) $expr
if ($expr instanceof Expr\Cast\Int_) {
return $this->specifyTypesInCondition(
$scope,
new Node\Expr\BinaryOp\NotEqual($expr->expr, new Node\Scalar\LNumber(0)),
$context,
$rootExpr,
);
} elseif ($expr instanceof Expr\Cast\Double) {
}

// (float) $expr
if ($expr instanceof Expr\Cast\Double) {
return $this->specifyTypesInCondition(
$scope,
new Node\Expr\BinaryOp\NotEqual($expr->expr, new Node\Scalar\DNumber(0.0)),
$context,
$rootExpr,
);
} elseif ($expr instanceof Node\Expr\BinaryOp\Equal) {
}

// $left == $right
if ($expr instanceof Node\Expr\BinaryOp\Equal) {
return $this->resolveEqual($expr, $scope, $context, $rootExpr);
} elseif ($expr instanceof Node\Expr\BinaryOp\NotEqual) {
}

// $left != $right
if ($expr instanceof Node\Expr\BinaryOp\NotEqual) {
return $this->specifyTypesInCondition(
$scope,
new Node\Expr\BooleanNot(new Node\Expr\BinaryOp\Equal($expr->left, $expr->right)),
$context,
$rootExpr,
);
}

} elseif ($expr instanceof Node\Expr\BinaryOp\Smaller || $expr instanceof Node\Expr\BinaryOp\SmallerOrEqual) {

// $left < $right
// $left <= $right
if ($expr instanceof Node\Expr\BinaryOp\Smaller
|| $expr instanceof Node\Expr\BinaryOp\SmallerOrEqual
) {
if (
$expr->left instanceof FuncCall
&& count($expr->left->getArgs()) >= 1
Expand Down Expand Up @@ -482,14 +512,20 @@ public function specifyTypesInCondition(
}

return $result;
}

} elseif ($expr instanceof Node\Expr\BinaryOp\Greater) {
// $left > $right
if ($expr instanceof Node\Expr\BinaryOp\Greater) {
return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\Smaller($expr->right, $expr->left), $context, $rootExpr);
}

} elseif ($expr instanceof Node\Expr\BinaryOp\GreaterOrEqual) {
// $left >= $right
if ($expr instanceof Node\Expr\BinaryOp\GreaterOrEqual) {
return $this->specifyTypesInCondition($scope, new Expr\BinaryOp\SmallerOrEqual($expr->right, $expr->left), $context, $rootExpr);
}

} elseif ($expr instanceof FuncCall && $expr->name instanceof Name) {
// name(...)
if ($expr instanceof FuncCall && $expr->name instanceof Name) {
if ($this->reflectionProvider->hasFunction($expr->name, $scope)) {
$functionReflection = $this->reflectionProvider->getFunction($expr->name, $scope);
foreach ($this->getFunctionTypeSpecifyingExtensions() as $extension) {
Expand Down Expand Up @@ -529,7 +565,10 @@ public function specifyTypesInCondition(
}

return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope);
} elseif ($expr instanceof MethodCall && $expr->name instanceof Node\Identifier) {
}

// $var->name(...)
if ($expr instanceof MethodCall && $expr->name instanceof Node\Identifier) {
$methodCalledOnType = $scope->getType($expr->var);
$methodReflection = $scope->getMethodReflection($methodCalledOnType, $expr->name->name);
if ($methodReflection !== null) {
Expand Down Expand Up @@ -577,7 +616,10 @@ public function specifyTypesInCondition(
}

return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope);
} elseif ($expr instanceof StaticCall && $expr->name instanceof Node\Identifier) {
}

// $class::name(...)
if ($expr instanceof StaticCall && $expr->name instanceof Node\Identifier) {
if ($expr->class instanceof Name) {
$calleeType = $scope->resolveTypeByName($expr->class);
} else {
Expand Down Expand Up @@ -630,7 +672,14 @@ public function specifyTypesInCondition(
}

return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope);
} elseif ($expr instanceof BooleanAnd || $expr instanceof LogicalAnd) {
}

// $left && $right
// $left and $right
if (
$expr instanceof BooleanAnd
|| $expr instanceof LogicalAnd
) {
if (!$scope instanceof MutatingScope) {
throw new ShouldNotHappenException();
}
Expand All @@ -654,7 +703,14 @@ public function specifyTypesInCondition(
}

return $types;
} elseif ($expr instanceof BooleanOr || $expr instanceof LogicalOr) {
}

// $left || $right
// $left or $right
if (
$expr instanceof BooleanOr
|| $expr instanceof LogicalOr
) {
if (!$scope instanceof MutatingScope) {
throw new ShouldNotHappenException();
}
Expand All @@ -678,9 +734,15 @@ public function specifyTypesInCondition(
}

return $types;
} elseif ($expr instanceof Node\Expr\BooleanNot && !$context->null()) {
}

// !$expr
if ($expr instanceof Node\Expr\BooleanNot && !$context->null()) {
return $this->specifyTypesInCondition($scope, $expr->expr, $context->negate(), $rootExpr);
} elseif ($expr instanceof Node\Expr\Assign) {
}

// $var = $expr
if ($expr instanceof Node\Expr\Assign) {
if (!$scope instanceof MutatingScope) {
throw new ShouldNotHappenException();
}
Expand All @@ -689,11 +751,10 @@ public function specifyTypesInCondition(
}

return $this->specifyTypesInCondition($scope->exitFirstLevelStatements(), $expr->var, $context, $rootExpr);
} elseif (
$expr instanceof Expr\Isset_
&& count($expr->vars) > 0
&& !$context->null()
) {
}

// isset(...$vars)
if ($expr instanceof Expr\Isset_ && count($expr->vars) > 0 && !$context->null()) {
// rewrite multi param isset() to and-chained single param isset()
if (count($expr->vars) > 1) {
$issets = [];
Expand Down Expand Up @@ -883,10 +944,10 @@ public function specifyTypesInCondition(
}

return $types;
} elseif (
$expr instanceof Expr\BinaryOp\Coalesce
&& !$context->null()
) {
}

// $a ?? $b
if ($expr instanceof Expr\BinaryOp\Coalesce && !$context->null()) {
if (!$context->true()) {
if (!$scope instanceof MutatingScope) {
throw new ShouldNotHappenException();
Expand Down Expand Up @@ -919,9 +980,11 @@ public function specifyTypesInCondition(
);
}

} elseif (
$expr instanceof Expr\Empty_
) {
return new SpecifiedTypes([], [], false, [], $rootExpr);
}

// empty($expr)
if ($expr instanceof Expr\Empty_) {
if (!$scope instanceof MutatingScope) {
throw new ShouldNotHappenException();
}
Expand All @@ -935,21 +998,25 @@ public function specifyTypesInCondition(
new Expr\BooleanNot(new Expr\Isset_([$expr->expr])),
new Expr\BooleanNot($expr->expr),
), $context, $rootExpr);
} elseif ($expr instanceof Expr\ErrorSuppress) {
}

// @$a
if ($expr instanceof Expr\ErrorSuppress) {
return $this->specifyTypesInCondition($scope, $expr->expr, $context, $rootExpr);
} elseif (
$expr instanceof Expr\Ternary
&& !$context->null()
&& $scope->getType($expr->else)->isFalse()->yes()
) {
}

// $cond ? $if : $else
if ($expr instanceof Expr\Ternary && !$context->null() && $scope->getType($expr->else)->isFalse()->yes()) {
$conditionExpr = $expr->cond;
if ($expr->if !== null) {
$conditionExpr = new BooleanAnd($conditionExpr, $expr->if);
}

return $this->specifyTypesInCondition($scope, $conditionExpr, $context, $rootExpr);
}

} elseif ($expr instanceof Expr\NullsafePropertyFetch && !$context->null()) {
// $var?->name(...)
if ($expr instanceof Expr\NullsafePropertyFetch && !$context->null()) {
$types = $this->specifyTypesInCondition(
$scope,
new BooleanAnd(
Expand All @@ -962,7 +1029,10 @@ public function specifyTypesInCondition(

$nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope);
return $context->true() ? $types->unionWith($nullSafeTypes) : $types->normalize($scope)->intersectWith($nullSafeTypes->normalize($scope));
} elseif ($expr instanceof Expr\NullsafeMethodCall && !$context->null()) {
}

// $var?->name(...)
if ($expr instanceof Expr\NullsafeMethodCall && !$context->null()) {
$types = $this->specifyTypesInCondition(
$scope,
new BooleanAnd(
Expand All @@ -975,11 +1045,10 @@ public function specifyTypesInCondition(

$nullSafeTypes = $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope);
return $context->true() ? $types->unionWith($nullSafeTypes) : $types->normalize($scope)->intersectWith($nullSafeTypes->normalize($scope));
} elseif (
$expr instanceof Expr\New_
&& $expr->class instanceof Name
&& $this->reflectionProvider->hasClass($expr->class->toString())
) {
}

// new $class(...)
if ($expr instanceof Expr\New_ && $expr->class instanceof Name && $this->reflectionProvider->hasClass($expr->class->toString())) {
$classReflection = $this->reflectionProvider->getClass($expr->class->toString());

if ($classReflection->hasConstructor()) {
Expand All @@ -1003,7 +1072,11 @@ public function specifyTypesInCondition(
}
}
}
} elseif (!$context->null()) {

return new SpecifiedTypes([], [], false, [], $rootExpr);
}

if (!$context->null()) {
return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope);
}

Expand Down
Loading