Skip to content

Commit

Permalink
[NodeTypeResolver] Handle optional array shape on native function lik…
Browse files Browse the repository at this point in the history
…e with ArrayDimFetch (#5062)

* [TypeDeclaration] Skip ArrayDimFetch for native array-shapes

* Update native_array_shape.php.inc

* Update skip_native_optional_array_shape.php.inc

* Update native_array_shape.php.inc

* Apply suggestions from code review

Co-authored-by: Abdul Malik Ikhsan <samsonasik@gmail.com>

* Apply suggestions from code review

Co-authored-by: Abdul Malik Ikhsan <samsonasik@gmail.com>

* Fix

* [ci-review] Rector Rectify

* [ci-review] Rector Rectify

* Fix

* fix

* Revert "[ci-review] Rector Rectify"

This reverts commit 2edc906.

* revert

* Fix

* Fix

* add space

* clean up

* move comment before

---------

Co-authored-by: Markus Staab <markus.staab@redaxo.de>
Co-authored-by: GitHub Action <actions@github.com>
  • Loading branch information
3 people committed Sep 21, 2023
1 parent 36f0b4a commit c3d2ccf
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 21 deletions.
81 changes: 61 additions & 20 deletions packages/NodeTypeResolver/NodeTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\NullableType;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\UnionType as NodeUnionType;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassAutoloadingException;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ArrayType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\MixedType;
use PHPStan\Type\NullType;
use PHPStan\Type\ObjectType;
Expand Down Expand Up @@ -238,26 +241,7 @@ public function getNativeType(Expr $expr): Type

$type = $scope->getNativeType($expr);
if ($expr instanceof ArrayDimFetch) {
/**
* Allow pull type from
*
* - native function
* - always defined by assignment
*
* eg:
*
* $parts = parse_url($url);
* if (!empty($parts['host'])) { }
*
* or
*
* $parts = ['host' => 'foo'];
* if (!empty($parts['host'])) { }
*/
$variableType = $scope->getNativeType($expr->var);
if (! $variableType instanceof MixedType && (! $variableType instanceof ArrayType || ! $variableType->getItemType() instanceof MixedType)) {
$type = $scope->getType($expr);
}
$type = $this->resolveArrayDimFetchType($expr, $scope, $type);
}

if (! $type instanceof UnionType) {
Expand Down Expand Up @@ -343,6 +327,63 @@ public function isMethodStaticCallOrClassMethodObjectType(Node $node, ObjectType
return $classReflection->isSubclassOf($objectType->getClassName());
}

/**
* Allow pull type from
*
* - native function
* - always defined by assignment
*
* eg:
*
* $parts = parse_url($url);
* if (!empty($parts['host'])) { }
*
* or
*
* $parts = ['host' => 'foo'];
* if (!empty($parts['host'])) { }
*/
private function resolveArrayDimFetchType(
ArrayDimFetch $arrayDimFetch,
Scope $scope,
Type $originalNativeType
): Type {
$nativeVariableType = $scope->getNativeType($arrayDimFetch->var);
if ($nativeVariableType instanceof MixedType || ($nativeVariableType instanceof ArrayType && $nativeVariableType->getItemType() instanceof MixedType)) {
return $originalNativeType;
}

$type = $scope->getType($arrayDimFetch);

if (! $arrayDimFetch->dim instanceof String_) {
return $type;
}

$variableType = $scope->getType($arrayDimFetch->var);
if (! $variableType instanceof ConstantArrayType) {
return $type;
}

$optionalKeys = $variableType->getOptionalKeys();
foreach ($variableType->getKeyTypes() as $key => $type) {
if (! $type instanceof ConstantStringType) {
continue;
}

if ($type->getValue() !== $arrayDimFetch->dim->value) {
continue;
}

if (! in_array($key, $optionalKeys, true)) {
continue;
}

return $originalNativeType;
}

return $type;
}

private function resolveNativeUnionType(UnionType $unionType): Type
{
$hasChanged = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddMethodCallBasedStrictParamTypeRector\Fixture;

final class NativeArrayShape {
private function doFoo() {
$shape = pathinfo('/www/htdocs/inc/lib.inc.php');
$this->doBar($shape['basename']);
}

private function doBar($param) {

}
}
?>
-----
<?php

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddMethodCallBasedStrictParamTypeRector\Fixture;

final class NativeArrayShape {
private function doFoo() {
$shape = pathinfo('/www/htdocs/inc/lib.inc.php');
$this->doBar($shape['basename']);
}

private function doBar(string $param) {

}
}
?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddMethodCallBasedStrictParamTypeRector\Fixture;

final class SkipNativeOptionalShape {
private function doFoo() {
$shape = pathinfo('');
$this->doBar($shape['dirname']); // dirname is only conditionally returned
}

private function doBar($param) {

}
}
?>
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ final class PathInfoReturn
*
* @psalm-assert-if-true =non-empty-string $filename
*/
public static function extension($filename): string|array
public static function extension($filename): array|string
{
return pathinfo($filename, PATHINFO_EXTENSION);
}
Expand Down

0 comments on commit c3d2ccf

Please sign in to comment.