Skip to content

Commit

Permalink
Make null-safe shortcircuiting optional
Browse files Browse the repository at this point in the history
  • Loading branch information
olsavmic committed Sep 24, 2021
1 parent 6568103 commit be93bda
Show file tree
Hide file tree
Showing 29 changed files with 82 additions and 33 deletions.
3 changes: 2 additions & 1 deletion src/Rules/Arrays/ArrayDestructuringRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ private function getErrors(Scope $scope, Expr $var, Expr $expr): array
'',
static function (Type $varType): bool {
return $varType->isArray()->yes();
}
},
false
);
$exprType = $exprTypeResult->getType();
if ($exprType instanceof ErrorType) {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Arrays/IterableInForeachRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public function processNode(Node $node, Scope $scope): array
'Iterating over an object of an unknown class %s.',
static function (Type $type): bool {
return $type->isIterable()->yes();
}
},
false
);
$type = $typeResult->getType();
if ($type instanceof ErrorType) {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ public function check(
$unknownClassPattern,
static function (Type $type) use ($dimType): bool {
return $type->hasOffsetValueType($dimType)->yes();
}
},
true
);
$type = $typeResult->getType();
if ($type instanceof ErrorType) {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Arrays/NonexistentOffsetInArrayDimFetchRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ public function processNode(\PhpParser\Node $node, Scope $scope): array
$unknownClassPattern,
static function (Type $type): bool {
return $type->isOffsetAccessible()->yes();
}
},
true
);
$isOffsetAccessibleType = $isOffsetAccessibleTypeResult->getType();
if ($isOffsetAccessibleType instanceof ErrorType) {
Expand Down
6 changes: 4 additions & 2 deletions src/Rules/Arrays/OffsetAccessAssignOpRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ public function processNode(\PhpParser\Node $node, Scope $scope): array
static function (Type $varType) use ($potentialDimType): bool {
$arrayDimType = $varType->setOffsetValueType($potentialDimType, new MixedType());
return !($arrayDimType instanceof ErrorType);
}
},
true
);
$varType = $varTypeResult->getType();

Expand All @@ -61,7 +62,8 @@ static function (Type $varType) use ($potentialDimType): bool {
static function (Type $dimType) use ($varType): bool {
$arrayDimType = $varType->setOffsetValueType($dimType, new MixedType());
return !($arrayDimType instanceof ErrorType);
}
},
true
);
$dimType = $dimTypeResult->getType();
if ($varType->hasOffsetValueType($dimType)->no()) {
Expand Down
6 changes: 4 additions & 2 deletions src/Rules/Arrays/OffsetAccessAssignmentRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public function processNode(\PhpParser\Node $node, Scope $scope): array
static function (Type $varType) use ($potentialDimType): bool {
$arrayDimType = $varType->setOffsetValueType($potentialDimType, new MixedType());
return !($arrayDimType instanceof ErrorType);
}
},
true
);
$varType = $varTypeResult->getType();
if ($varType instanceof ErrorType) {
Expand All @@ -64,7 +65,8 @@ static function (Type $varType) use ($potentialDimType): bool {
static function (Type $dimType) use ($varType): bool {
$arrayDimType = $varType->setOffsetValueType($dimType, new MixedType());
return !($arrayDimType instanceof ErrorType);
}
},
true
);
$dimType = $dimTypeResult->getType();
} else {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Arrays/OffsetAccessValueAssignmentRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public function processNode(\PhpParser\Node $node, Scope $scope): array
static function (Type $varType) use ($assignedValueType): bool {
$result = $varType->setOffsetValueType(new MixedType(), $assignedValueType);
return !($result instanceof ErrorType);
}
},
true
);
$arrayType = $arrayTypeResult->getType();
if ($arrayType instanceof ErrorType) {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Arrays/UnpackIterableInArrayRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public function processNode(Node $node, Scope $scope): array
'',
static function (Type $type): bool {
return $type->isIterable()->yes();
}
},
false
);
$type = $typeResult->getType();
if ($type instanceof ErrorType) {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Cast/EchoRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ public function processNode(Node $node, Scope $scope): array
'',
static function (Type $type): bool {
return !$type->toString() instanceof ErrorType;
}
},
false
);

if ($typeResult->getType() instanceof ErrorType
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Cast/InvalidCastRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ static function (Type $type) use ($castTypeCallback): bool {
}

return !$castType instanceof ErrorType;
}
},
false
);
$type = $typeResult->getType();
if ($type instanceof ErrorType) {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Cast/InvalidPartOfEncapsedStringRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ public function processNode(Node $node, Scope $scope): array
'',
static function (Type $type): bool {
return !$type->toString() instanceof ErrorType;
}
},
false
);
$partType = $typeResult->getType();
if ($partType instanceof ErrorType) {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Cast/PrintRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ public function processNode(Node $node, Scope $scope): array
'',
static function (Type $type): bool {
return !$type->toString() instanceof ErrorType;
}
},
false
);

if (!$typeResult->getType() instanceof ErrorType
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Classes/ClassConstantRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ public function processNode(Node $node, Scope $scope): array
sprintf('Access to constant %s on an unknown class %%s.', SprintfHelper::escapeFormatString($constantName)),
static function (Type $type) use ($constantName): bool {
return $type->canAccessConstants()->yes() && $type->hasConstant($constantName)->yes();
}
},
true
);
$classType = $classTypeResult->getType();
if ($classType instanceof ErrorType) {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/FunctionCallParametersCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,8 @@ public function check(
'',
static function (Type $type): bool {
return $type->isIterable()->yes();
}
},
true
);
$iterableTypeResultType = $iterableTypeResult->getType();
if (
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Functions/CallCallablesRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public function processNode(
'Invoking callable on an unknown class %s.',
static function (Type $type): bool {
return $type->isCallable()->yes();
}
},
true
);
$type = $typeResult->getType();
if ($type instanceof ErrorType) {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Functions/ImplodeFunctionRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public function processNode(Node $node, Scope $scope): array
'',
static function (Type $type): bool {
return !$type->getIterableValueType()->toString() instanceof ErrorType;
}
},
false
);

if ($typeResult->getType() instanceof ErrorType
Expand Down
4 changes: 3 additions & 1 deletion src/Rules/Methods/CallMethodsRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,15 @@ public function processNode(Node $node, Scope $scope): array
}

$name = $node->name->name;

$typeResult = $this->ruleLevelHelper->findTypeToCheck(
$scope,
$node->var,
sprintf('Call to method %s() on an unknown class %%s.', SprintfHelper::escapeFormatString($name)),
static function (Type $type) use ($name): bool {
return $type->canCallMethods()->yes() && $type->hasMethod($name)->yes();
}
},
true
);
$type = $typeResult->getType();
if ($type instanceof ErrorType) {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Methods/CallStaticMethodsRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ public function processNode(Node $node, Scope $scope): array
sprintf('Call to static method %s() on an unknown class %%s.', SprintfHelper::escapeFormatString($methodName)),
static function (Type $type) use ($methodName): bool {
return $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes();
}
},
true
);
$classType = $classTypeResult->getType();
if ($classType instanceof ErrorType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public function processNode(Node $node, Scope $scope): array
'',
static function (Type $type) use ($methodName): bool {
return $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes();
}
},
true
);
$calledOnType = $typeResult->getType();
if ($calledOnType instanceof ErrorType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ public function processNode(Node $node, Scope $scope): array
'',
static function (Type $type) use ($methodName): bool {
return $type->canCallMethods()->yes() && $type->hasMethod($methodName)->yes();
}
},
true
);
$calledOnType = $typeResult->getType();
if ($calledOnType instanceof ErrorType) {
Expand Down
6 changes: 4 additions & 2 deletions src/Rules/Operators/InvalidBinaryOperationRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ public function processNode(\PhpParser\Node $node, Scope $scope): array
$scope,
$left,
'',
$callback
$callback,
false
)->getType();
if ($leftType instanceof ErrorType) {
return [];
Expand All @@ -87,7 +88,8 @@ public function processNode(\PhpParser\Node $node, Scope $scope): array
$scope,
$right,
'',
$callback
$callback,
false
)->getType();
if ($rightType instanceof ErrorType) {
return [];
Expand Down
8 changes: 5 additions & 3 deletions src/Rules/Operators/InvalidComparisonOperationRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ private function isNumberType(Scope $scope, Node\Expr $expr): bool
return $acceptedType->accepts($type, true)->yes();
};

$type = $this->ruleLevelHelper->findTypeToCheck($scope, $expr, '', $onlyNumber)->getType();
$type = $this->ruleLevelHelper->findTypeToCheck($scope, $expr, '', $onlyNumber, false)->getType();

if (
$type instanceof ErrorType
Expand All @@ -96,7 +96,8 @@ private function isObjectType(Scope $scope, Node\Expr $expr): bool
'',
static function (Type $type) use ($acceptedType): bool {
return $acceptedType->isSuperTypeOf($type)->yes();
}
},
false
)->getType();

if ($type instanceof ErrorType) {
Expand All @@ -119,7 +120,8 @@ private function isArrayType(Scope $scope, Node\Expr $expr): bool
'',
static function (Type $type): bool {
return $type->isArray()->yes();
}
},
false
)->getType();

return !($type instanceof ErrorType) && $type->isArray()->yes();
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Properties/AccessPropertiesRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ private function processSingleProperty(Scope $scope, PropertyFetch $node, string
sprintf('Access to property $%s on an unknown class %%s.', SprintfHelper::escapeFormatString($name)),
static function (Type $type) use ($name): bool {
return $type->canAccessProperties()->yes() && $type->hasProperty($name)->yes();
}
},
true
);
$type = $typeResult->getType();
if ($type instanceof ErrorType) {
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Properties/AccessStaticPropertiesRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ private function processSingleProperty(Scope $scope, StaticPropertyFetch $node,
sprintf('Access to static property $%s on an unknown class %%s.', SprintfHelper::escapeFormatString($name)),
static function (Type $type) use ($name): bool {
return $type->canAccessProperties()->yes() && $type->hasProperty($name)->yes();
}
},
true
);
$classType = $classTypeResult->getType();
if ($classType instanceof ErrorType) {
Expand Down
5 changes: 3 additions & 2 deletions src/Rules/RuleLevelHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ public function findTypeToCheck(
Scope $scope,
Expr $var,
string $unknownClassErrorPattern,
callable $unionTypeCriteriaCallback
callable $unionTypeCriteriaCallback,
bool $shouldShortCircuitNullSafeOperator = false
): FoundTypeResult
{
if ($this->checkThisOnly && !$this->isThis($var)) {
Expand All @@ -143,7 +144,7 @@ public function findTypeToCheck(
$type = \PHPStan\Type\TypeCombinator::removeNull($type);
}

if (TypeCombinator::containsNull($type)) {
if ($shouldShortCircuitNullSafeOperator && TypeCombinator::containsNull($type)) {
$type = $scope->getType(NullsafeOperatorHelper::getNullsafeShortcircuitedExpr($var));
}

Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Variables/ThrowTypeRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ public function processNode(Node $node, Scope $scope): array
'Throwing object of an unknown class %s.',
static function (Type $type) use ($throwableType): bool {
return $throwableType->isSuperTypeOf($type)->yes();
}
},
false
);

$foundType = $typeResult->getType();
Expand Down
3 changes: 2 additions & 1 deletion src/Rules/Variables/VariableCloningRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ public function processNode(Node $node, Scope $scope): array
'Cloning object of an unknown class %s.',
static function (Type $type): bool {
return $type->isCloneable()->yes();
}
},
false
);
$type = $typeResult->getType();
if ($type instanceof ErrorType) {
Expand Down
4 changes: 4 additions & 0 deletions tests/PHPStan/Rules/Arrays/ArrayDestructuringRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public function testRule(): void
'Offset \'a\' does not exist on array(\'b\' => 1).',
22,
],
[
'Cannot use array destructuring on array|null.',
27,
],
]);
}

Expand Down
13 changes: 13 additions & 0 deletions tests/PHPStan/Rules/Arrays/data/array-destructuring.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,17 @@ public function doBar(): void
['a' => $a] = ['b' => 1];
}

public function doFooBar(?Bar $bar): void
{
[$a] = $bar?->getArray();
}

}

class Bar
{
public function getArray(): array
{
return [];
}
}

0 comments on commit be93bda

Please sign in to comment.