From e4a3696e4f86acc2361ff942da2d4f465eaf4b32 Mon Sep 17 00:00:00 2001 From: Martin Herndl Date: Thu, 1 Sep 2022 14:48:04 +0200 Subject: [PATCH] Introduce Type::getConstantArrays as successor for TypeUtils::getOldConstantArrays --- src/Analyser/NodeScopeResolver.php | 2 +- .../InitializerExprTypeResolver.php | 4 +-- .../NonexistentOffsetInArrayDimFetchCheck.php | 2 +- .../Comparison/ImpossibleCheckTypeHelper.php | 2 +- src/Rules/FunctionCallParametersCheck.php | 2 +- .../Regexp/RegularExpressionPatternRule.php | 2 +- src/Rules/RuleLevelHelper.php | 4 +-- src/Type/Accessory/AccessoryArrayListType.php | 5 ++++ src/Type/Accessory/NonEmptyArrayType.php | 5 ++++ src/Type/Accessory/OversizedArrayType.php | 5 ++++ src/Type/ArrayType.php | 5 ++++ src/Type/Constant/ConstantArrayType.php | 5 ++++ src/Type/IntersectionType.php | 5 ++++ src/Type/MixedType.php | 5 ++++ ...ArrayColumnFunctionReturnTypeExtension.php | 2 +- ...rayFillKeysFunctionReturnTypeExtension.php | 3 +-- ...rFunctionReturnTypeReturnTypeExtension.php | 2 +- .../ArrayFlipFunctionReturnTypeExtension.php | 3 +-- ...ntersectKeyFunctionReturnTypeExtension.php | 3 +-- ...rrayKeyFirstDynamicReturnTypeExtension.php | 3 +-- ...ArrayKeyLastDynamicReturnTypeExtension.php | 3 +-- .../ArrayMapFunctionReturnTypeExtension.php | 2 +- ...terFunctionsDynamicReturnTypeExtension.php | 3 +-- .../ArrayPopFunctionReturnTypeExtension.php | 3 +-- ...ArrayReduceFunctionReturnTypeExtension.php | 3 +-- .../ArrayShiftFunctionReturnTypeExtension.php | 3 +-- .../Php/CountFunctionReturnTypeExtension.php | 3 +-- src/Type/StaticType.php | 5 ++++ src/Type/Traits/LateResolvableTypeTrait.php | 5 ++++ src/Type/Traits/MaybeArrayTypeTrait.php | 5 ++++ src/Type/Traits/NonArrayTypeTrait.php | 5 ++++ src/Type/Type.php | 4 +++ src/Type/TypeUtils.php | 4 +++ src/Type/UnionType.php | 5 ++++ src/Type/UnionTypeHelper.php | 25 +++++++++++++++---- .../Levels/data/arrayDimFetches-3.json | 5 ++++ .../data/arrayDimFetches-7-missing.json | 7 ++++++ .../data/arrayDimFetches-8-missing.json | 7 ++++++ .../data/arrayDimFetches-9-missing.json | 7 ++++++ 39 files changed, 136 insertions(+), 37 deletions(-) create mode 100644 tests/PHPStan/Levels/data/arrayDimFetches-7-missing.json create mode 100644 tests/PHPStan/Levels/data/arrayDimFetches-8-missing.json create mode 100644 tests/PHPStan/Levels/data/arrayDimFetches-9-missing.json diff --git a/src/Analyser/NodeScopeResolver.php b/src/Analyser/NodeScopeResolver.php index 9087957b71..fbaac083b4 100644 --- a/src/Analyser/NodeScopeResolver.php +++ b/src/Analyser/NodeScopeResolver.php @@ -1893,7 +1893,7 @@ function (MutatingScope $scope) use ($expr, $nodeCallback, $context): Expression } }; - $constantArrays = TypeUtils::getOldConstantArrays($arrayType); + $constantArrays = $arrayType->getConstantArrays(); if (count($constantArrays) > 0) { $newArrayTypes = []; $prepend = $functionReflection->getName() === 'array_unshift'; diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index 8401bbdba7..66a382364c 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -907,8 +907,8 @@ public function getPlusType(Expr $left, Expr $right, callable $getTypeCallback): return TypeCombinator::union(...$resultTypes); } - $leftConstantArrays = TypeUtils::getOldConstantArrays($leftType); - $rightConstantArrays = TypeUtils::getOldConstantArrays($rightType); + $leftConstantArrays = $leftType->getConstantArrays(); + $rightConstantArrays = $rightType->getConstantArrays(); $leftCount = count($leftConstantArrays); $rightCount = count($rightConstantArrays); diff --git a/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php b/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php index 52f54e34ed..924c162958 100644 --- a/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php +++ b/src/Rules/Arrays/NonexistentOffsetInArrayDimFetchCheck.php @@ -48,7 +48,7 @@ public function check( $hasOffsetValueType = $type->hasOffsetValueType($dimType); $report = $hasOffsetValueType->no(); if ($hasOffsetValueType->maybe()) { - $constantArrays = TypeUtils::getOldConstantArrays($type); + $constantArrays = $type->getConstantArrays(); if (count($constantArrays) > 0) { foreach ($constantArrays as $constantArray) { if ($constantArray->hasOffsetValueType($dimType)->no()) { diff --git a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php index 9bd7c0ec6a..44625a998b 100644 --- a/src/Rules/Comparison/ImpossibleCheckTypeHelper.php +++ b/src/Rules/Comparison/ImpossibleCheckTypeHelper.php @@ -87,7 +87,7 @@ public function findSpecifiedType( return null; } - $constantArrays = TypeUtils::getOldConstantArrays($haystackType); + $constantArrays = $haystackType->getConstantArrays(); $needleType = $scope->getType($node->getArgs()[0]->value); $valueType = $haystackType->getIterableValueType(); $constantNeedleTypesCount = count(TypeUtils::getConstantScalars($needleType)); diff --git a/src/Rules/FunctionCallParametersCheck.php b/src/Rules/FunctionCallParametersCheck.php index 37be0e0d9a..744adc9afe 100644 --- a/src/Rules/FunctionCallParametersCheck.php +++ b/src/Rules/FunctionCallParametersCheck.php @@ -100,7 +100,7 @@ public function check( $argumentName = $arg->name->toString(); } if ($arg->unpack) { - $arrays = TypeUtils::getOldConstantArrays($type); + $arrays = $type->getConstantArrays(); if (count($arrays) > 0) { $minKeys = null; foreach ($arrays as $array) { diff --git a/src/Rules/Regexp/RegularExpressionPatternRule.php b/src/Rules/Regexp/RegularExpressionPatternRule.php index 3a6155ecc5..56da7deda1 100644 --- a/src/Rules/Regexp/RegularExpressionPatternRule.php +++ b/src/Rules/Regexp/RegularExpressionPatternRule.php @@ -83,7 +83,7 @@ private function extractPatterns(FuncCall $functionCall, Scope $scope): array $patternStrings[] = $constantStringType->getValue(); } - foreach (TypeUtils::getOldConstantArrays($patternType) as $constantArrayType) { + foreach ($patternType->getConstantArrays() as $constantArrayType) { if ( in_array($functionName, [ 'preg_replace', diff --git a/src/Rules/RuleLevelHelper.php b/src/Rules/RuleLevelHelper.php index cba600b029..981dc2f2ad 100644 --- a/src/Rules/RuleLevelHelper.php +++ b/src/Rules/RuleLevelHelper.php @@ -111,8 +111,8 @@ public function accepts(Type $acceptingType, Type $acceptedType, bool $strictTyp $acceptedType->isArray()->yes() && $acceptingType->isArray()->yes() && !$acceptingType->isIterableAtLeastOnce()->yes() - && count(TypeUtils::getOldConstantArrays($acceptedType)) === 0 - && count(TypeUtils::getOldConstantArrays($acceptingType)) === 0 + && count($acceptedType->getConstantArrays()) === 0 + && count($acceptingType->getConstantArrays()) === 0 ) { return self::accepts( $acceptingType->getIterableKeyType(), diff --git a/src/Type/Accessory/AccessoryArrayListType.php b/src/Type/Accessory/AccessoryArrayListType.php index 02a87af34c..08e825f26c 100644 --- a/src/Type/Accessory/AccessoryArrayListType.php +++ b/src/Type/Accessory/AccessoryArrayListType.php @@ -44,6 +44,11 @@ public function getReferencedClasses(): array return []; } + public function getConstantArrays(): array + { + return []; + } + public function accepts(Type $type, bool $strictTypes): TrinaryLogic { if ($type instanceof CompoundType) { diff --git a/src/Type/Accessory/NonEmptyArrayType.php b/src/Type/Accessory/NonEmptyArrayType.php index cba8208a22..cc5fff662c 100644 --- a/src/Type/Accessory/NonEmptyArrayType.php +++ b/src/Type/Accessory/NonEmptyArrayType.php @@ -41,6 +41,11 @@ public function getReferencedClasses(): array return []; } + public function getConstantArrays(): array + { + return []; + } + public function accepts(Type $type, bool $strictTypes): TrinaryLogic { if ($type instanceof CompoundType) { diff --git a/src/Type/Accessory/OversizedArrayType.php b/src/Type/Accessory/OversizedArrayType.php index 35cb5fd799..1b208ae0ed 100644 --- a/src/Type/Accessory/OversizedArrayType.php +++ b/src/Type/Accessory/OversizedArrayType.php @@ -40,6 +40,11 @@ public function getReferencedClasses(): array return []; } + public function getConstantArrays(): array + { + return []; + } + public function accepts(Type $type, bool $strictTypes): TrinaryLogic { if ($type instanceof CompoundType) { diff --git a/src/Type/ArrayType.php b/src/Type/ArrayType.php index 1f112cb44b..b0b1a1d8c2 100644 --- a/src/Type/ArrayType.php +++ b/src/Type/ArrayType.php @@ -73,6 +73,11 @@ public function getReferencedClasses(): array ); } + public function getConstantArrays(): array + { + return []; + } + public function accepts(Type $type, bool $strictTypes): TrinaryLogic { if ($type instanceof CompoundType) { diff --git a/src/Type/Constant/ConstantArrayType.php b/src/Type/Constant/ConstantArrayType.php index b5f8c0df76..c10e202aa9 100644 --- a/src/Type/Constant/ConstantArrayType.php +++ b/src/Type/Constant/ConstantArrayType.php @@ -108,6 +108,11 @@ public function __construct( ); } + public function getConstantArrays(): array + { + return [$this]; + } + public function isEmpty(): bool { return count($this->keyTypes) === 0; diff --git a/src/Type/IntersectionType.php b/src/Type/IntersectionType.php index ae17a61440..c928f6adc5 100644 --- a/src/Type/IntersectionType.php +++ b/src/Type/IntersectionType.php @@ -100,6 +100,11 @@ public function getReferencedClasses(): array return UnionTypeHelper::getReferencedClasses($this->types); } + public function getConstantArrays(): array + { + return UnionTypeHelper::getConstantArrays($this->getTypes()); + } + public function accepts(Type $otherType, bool $strictTypes): TrinaryLogic { foreach ($this->types as $type) { diff --git a/src/Type/MixedType.php b/src/Type/MixedType.php index b389875ce2..79dcff7b5c 100644 --- a/src/Type/MixedType.php +++ b/src/Type/MixedType.php @@ -63,6 +63,11 @@ public function getReferencedClasses(): array return []; } + public function getConstantArrays(): array + { + return []; + } + public function accepts(Type $type, bool $strictTypes): TrinaryLogic { return TrinaryLogic::createYes(); diff --git a/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php b/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php index 58e15a025a..a4b6f3c886 100644 --- a/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayColumnFunctionReturnTypeExtension.php @@ -47,7 +47,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $columnType = $scope->getType($functionCall->getArgs()[1]->value); $indexType = $numArgs >= 3 ? $scope->getType($functionCall->getArgs()[2]->value) : null; - $constantArrayTypes = TypeUtils::getOldConstantArrays($arrayType); + $constantArrayTypes = $arrayType->getConstantArrays(); if (count($constantArrayTypes) === 1) { $type = $this->handleConstantArray($constantArrayTypes[0], $columnType, $indexType, $scope); if ($type !== null) { diff --git a/src/Type/Php/ArrayFillKeysFunctionReturnTypeExtension.php b/src/Type/Php/ArrayFillKeysFunctionReturnTypeExtension.php index e912e4b828..5884e9cab8 100644 --- a/src/Type/Php/ArrayFillKeysFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayFillKeysFunctionReturnTypeExtension.php @@ -14,7 +14,6 @@ use PHPStan\Type\NeverType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeUtils; use function count; class ArrayFillKeysFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension @@ -33,7 +32,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $valueType = $scope->getType($functionCall->getArgs()[1]->value); $keysType = $scope->getType($functionCall->getArgs()[0]->value); - $constantArrays = TypeUtils::getOldConstantArrays($keysType); + $constantArrays = $keysType->getConstantArrays(); if (count($constantArrays) === 0) { if ($keysType->isArray()->yes()) { $itemType = $keysType->getIterableValueType(); diff --git a/src/Type/Php/ArrayFilterFunctionReturnTypeReturnTypeExtension.php b/src/Type/Php/ArrayFilterFunctionReturnTypeReturnTypeExtension.php index e38b58c30d..78fab895ee 100644 --- a/src/Type/Php/ArrayFilterFunctionReturnTypeReturnTypeExtension.php +++ b/src/Type/Php/ArrayFilterFunctionReturnTypeReturnTypeExtension.php @@ -164,7 +164,7 @@ private function filterByTruthyValue(Scope $scope, Error|Variable|null $itemVar, throw new ShouldNotHappenException(); } - $constantArrays = TypeUtils::getOldConstantArrays($arrayType); + $constantArrays = $arrayType->getConstantArrays(); if (count($constantArrays) > 0) { $results = []; foreach ($constantArrays as $constantArray) { diff --git a/src/Type/Php/ArrayFlipFunctionReturnTypeExtension.php b/src/Type/Php/ArrayFlipFunctionReturnTypeExtension.php index 29d53b6432..74dd9b2749 100644 --- a/src/Type/Php/ArrayFlipFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayFlipFunctionReturnTypeExtension.php @@ -12,7 +12,6 @@ use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeUtils; use function count; class ArrayFlipFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension @@ -32,7 +31,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, $array = $functionCall->getArgs()[0]->value; $argType = $scope->getType($array); - $constantArrays = TypeUtils::getOldConstantArrays($argType); + $constantArrays = $argType->getConstantArrays(); if (count($constantArrays) > 0) { $flipped = []; foreach ($constantArrays as $constantArray) { diff --git a/src/Type/Php/ArrayIntersectKeyFunctionReturnTypeExtension.php b/src/Type/Php/ArrayIntersectKeyFunctionReturnTypeExtension.php index c8a969539c..43aadecdb4 100644 --- a/src/Type/Php/ArrayIntersectKeyFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayIntersectKeyFunctionReturnTypeExtension.php @@ -11,7 +11,6 @@ use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeUtils; use function array_slice; use function count; @@ -47,7 +46,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return $firstArray; } - $constantArrays = TypeUtils::getOldConstantArrays($firstArray); + $constantArrays = $firstArray->getConstantArrays(); if (count($constantArrays) === 0) { return new ArrayType($firstArray->getIterableKeyType(), $firstArray->getIterableValueType()); } diff --git a/src/Type/Php/ArrayKeyFirstDynamicReturnTypeExtension.php b/src/Type/Php/ArrayKeyFirstDynamicReturnTypeExtension.php index d920391a2d..3d627259b9 100644 --- a/src/Type/Php/ArrayKeyFirstDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArrayKeyFirstDynamicReturnTypeExtension.php @@ -11,7 +11,6 @@ use PHPStan\Type\NullType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeUtils; use function count; class ArrayKeyFirstDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension @@ -34,7 +33,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return new NullType(); } - $constantArrays = TypeUtils::getOldConstantArrays($argType); + $constantArrays = $argType->getConstantArrays(); if (count($constantArrays) > 0) { $keyTypes = []; foreach ($constantArrays as $constantArray) { diff --git a/src/Type/Php/ArrayKeyLastDynamicReturnTypeExtension.php b/src/Type/Php/ArrayKeyLastDynamicReturnTypeExtension.php index fbe3f8739e..4ada15cef2 100644 --- a/src/Type/Php/ArrayKeyLastDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArrayKeyLastDynamicReturnTypeExtension.php @@ -10,7 +10,6 @@ use PHPStan\Type\NullType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeUtils; use function count; class ArrayKeyLastDynamicReturnTypeExtension implements DynamicFunctionReturnTypeExtension @@ -33,7 +32,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return new NullType(); } - $constantArrays = TypeUtils::getOldConstantArrays($argType); + $constantArrays = $argType->getConstantArrays(); if (count($constantArrays) > 0) { $keyTypes = []; foreach ($constantArrays as $constantArray) { diff --git a/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php b/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php index b41aee0bf7..897a698dea 100644 --- a/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayMapFunctionReturnTypeExtension.php @@ -63,7 +63,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, if ($callableIsNull) { return $arrayType; } - $constantArrays = TypeUtils::getOldConstantArrays($arrayType); + $constantArrays = $arrayType->getConstantArrays(); if (count($constantArrays) > 0) { $arrayTypes = []; foreach ($constantArrays as $constantArray) { diff --git a/src/Type/Php/ArrayPointerFunctionsDynamicReturnTypeExtension.php b/src/Type/Php/ArrayPointerFunctionsDynamicReturnTypeExtension.php index c4fd56bdc7..bbf101ee8a 100644 --- a/src/Type/Php/ArrayPointerFunctionsDynamicReturnTypeExtension.php +++ b/src/Type/Php/ArrayPointerFunctionsDynamicReturnTypeExtension.php @@ -10,7 +10,6 @@ use PHPStan\Type\DynamicFunctionReturnTypeExtension; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeUtils; use function count; use function in_array; @@ -44,7 +43,7 @@ public function getTypeFromFunctionCall( return new ConstantBooleanType(false); } - $constantArrays = TypeUtils::getOldConstantArrays($argType); + $constantArrays = $argType->getConstantArrays(); if (count($constantArrays) > 0) { $keyTypes = []; foreach ($constantArrays as $constantArray) { diff --git a/src/Type/Php/ArrayPopFunctionReturnTypeExtension.php b/src/Type/Php/ArrayPopFunctionReturnTypeExtension.php index 2d0436de43..4bd6e39005 100644 --- a/src/Type/Php/ArrayPopFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayPopFunctionReturnTypeExtension.php @@ -10,7 +10,6 @@ use PHPStan\Type\NullType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeUtils; use function count; class ArrayPopFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension @@ -33,7 +32,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return new NullType(); } - $constantArrays = TypeUtils::getOldConstantArrays($argType); + $constantArrays = $argType->getConstantArrays(); if (count($constantArrays) > 0) { $valueTypes = []; foreach ($constantArrays as $constantArray) { diff --git a/src/Type/Php/ArrayReduceFunctionReturnTypeExtension.php b/src/Type/Php/ArrayReduceFunctionReturnTypeExtension.php index 0f9487203f..690ad91f37 100644 --- a/src/Type/Php/ArrayReduceFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayReduceFunctionReturnTypeExtension.php @@ -11,7 +11,6 @@ use PHPStan\Type\NullType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeUtils; use function count; class ArrayReduceFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension @@ -46,7 +45,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, } $arraysType = $scope->getType($functionCall->getArgs()[0]->value); - $constantArrays = TypeUtils::getOldConstantArrays($arraysType); + $constantArrays = $arraysType->getConstantArrays(); if (count($constantArrays) > 0) { $onlyEmpty = TrinaryLogic::createYes(); $onlyNonEmpty = TrinaryLogic::createYes(); diff --git a/src/Type/Php/ArrayShiftFunctionReturnTypeExtension.php b/src/Type/Php/ArrayShiftFunctionReturnTypeExtension.php index f569e852fc..1b38aaf047 100644 --- a/src/Type/Php/ArrayShiftFunctionReturnTypeExtension.php +++ b/src/Type/Php/ArrayShiftFunctionReturnTypeExtension.php @@ -10,7 +10,6 @@ use PHPStan\Type\NullType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeUtils; use function count; class ArrayShiftFunctionReturnTypeExtension implements DynamicFunctionReturnTypeExtension @@ -33,7 +32,7 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection, return new NullType(); } - $constantArrays = TypeUtils::getOldConstantArrays($argType); + $constantArrays = $argType->getConstantArrays(); if (count($constantArrays) > 0) { $valueTypes = []; foreach ($constantArrays as $constantArray) { diff --git a/src/Type/Php/CountFunctionReturnTypeExtension.php b/src/Type/Php/CountFunctionReturnTypeExtension.php index b037a8422d..283baebc37 100644 --- a/src/Type/Php/CountFunctionReturnTypeExtension.php +++ b/src/Type/Php/CountFunctionReturnTypeExtension.php @@ -11,7 +11,6 @@ use PHPStan\Type\IntegerRangeType; use PHPStan\Type\Type; use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeUtils; use function count; use function in_array; use const COUNT_RECURSIVE; @@ -42,7 +41,7 @@ public function getTypeFromFunctionCall( } $argType = $scope->getType($functionCall->getArgs()[0]->value); - $constantArrays = TypeUtils::getOldConstantArrays($scope->getType($functionCall->getArgs()[0]->value)); + $constantArrays = $scope->getType($functionCall->getArgs()[0]->value)->getConstantArrays(); if (count($constantArrays) === 0) { if ($argType->isIterableAtLeastOnce()->yes()) { return IntegerRangeType::fromInterval(1, null); diff --git a/src/Type/StaticType.php b/src/Type/StaticType.php index 202c1d772a..2d4c279aba 100644 --- a/src/Type/StaticType.php +++ b/src/Type/StaticType.php @@ -104,6 +104,11 @@ public function getReferencedClasses(): array return $this->getStaticObjectType()->getReferencedClasses(); } + public function getConstantArrays(): array + { + return $this->getStaticObjectType()->getConstantArrays(); + } + public function accepts(Type $type, bool $strictTypes): TrinaryLogic { if ($type instanceof CompoundType) { diff --git a/src/Type/Traits/LateResolvableTypeTrait.php b/src/Type/Traits/LateResolvableTypeTrait.php index ca948e179c..265604533f 100644 --- a/src/Type/Traits/LateResolvableTypeTrait.php +++ b/src/Type/Traits/LateResolvableTypeTrait.php @@ -21,6 +21,11 @@ trait LateResolvableTypeTrait private ?Type $result = null; + public function getConstantArrays(): array + { + return $this->resolve()->getConstantArrays(); + } + public function accepts(Type $type, bool $strictTypes): TrinaryLogic { return $this->resolve()->accepts($type, $strictTypes); diff --git a/src/Type/Traits/MaybeArrayTypeTrait.php b/src/Type/Traits/MaybeArrayTypeTrait.php index 0bd040032f..a1976fb760 100644 --- a/src/Type/Traits/MaybeArrayTypeTrait.php +++ b/src/Type/Traits/MaybeArrayTypeTrait.php @@ -7,6 +7,11 @@ trait MaybeArrayTypeTrait { + public function getConstantArrays(): array + { + return []; + } + public function isArray(): TrinaryLogic { return TrinaryLogic::createMaybe(); diff --git a/src/Type/Traits/NonArrayTypeTrait.php b/src/Type/Traits/NonArrayTypeTrait.php index 5fef6c7d42..8640a51500 100644 --- a/src/Type/Traits/NonArrayTypeTrait.php +++ b/src/Type/Traits/NonArrayTypeTrait.php @@ -7,6 +7,11 @@ trait NonArrayTypeTrait { + public function getConstantArrays(): array + { + return []; + } + public function isArray(): TrinaryLogic { return TrinaryLogic::createNo(); diff --git a/src/Type/Type.php b/src/Type/Type.php index 4fd4cd1faa..9134fe1b80 100644 --- a/src/Type/Type.php +++ b/src/Type/Type.php @@ -10,6 +10,7 @@ use PHPStan\Reflection\Type\UnresolvedMethodPrototypeReflection; use PHPStan\Reflection\Type\UnresolvedPropertyPrototypeReflection; use PHPStan\TrinaryLogic; +use PHPStan\Type\Constant\ConstantArrayType; use PHPStan\Type\Generic\TemplateTypeMap; use PHPStan\Type\Generic\TemplateTypeReference; use PHPStan\Type\Generic\TemplateTypeVariance; @@ -23,6 +24,9 @@ interface Type */ public function getReferencedClasses(): array; + /** @return list */ + public function getConstantArrays(): array; + public function accepts(Type $type, bool $strictTypes): TrinaryLogic; public function isSuperTypeOf(Type $type): TrinaryLogic; diff --git a/src/Type/TypeUtils.php b/src/Type/TypeUtils.php index ce6819a1ac..bfde30b510 100644 --- a/src/Type/TypeUtils.php +++ b/src/Type/TypeUtils.php @@ -63,6 +63,8 @@ public static function getArrays(Type $type): array /** * @return ConstantArrayType[] + * + * @deprecated Use PHPStan\Type\Type::getConstantArrays() instead and handle optional keys if necessary. */ public static function getConstantArrays(Type $type): array { @@ -185,6 +187,8 @@ public static function getEnumCaseObjects(Type $type): array /** * @internal * @return ConstantArrayType[] + * + * @deprecated Use PHPStan\Type\Type::getConstantArrays(). */ public static function getOldConstantArrays(Type $type): array { diff --git a/src/Type/UnionType.php b/src/Type/UnionType.php index b51d1e5640..55e778b28d 100644 --- a/src/Type/UnionType.php +++ b/src/Type/UnionType.php @@ -97,6 +97,11 @@ public function getReferencedClasses(): array return UnionTypeHelper::getReferencedClasses($this->getTypes()); } + public function getConstantArrays(): array + { + return UnionTypeHelper::getConstantArrays($this->getTypes()); + } + public function accepts(Type $type, bool $strictTypes): TrinaryLogic { if ( diff --git a/src/Type/UnionTypeHelper.php b/src/Type/UnionTypeHelper.php index 4e89b1121b..4df8a30626 100644 --- a/src/Type/UnionTypeHelper.php +++ b/src/Type/UnionTypeHelper.php @@ -8,6 +8,7 @@ use PHPStan\Type\Constant\ConstantFloatType; use PHPStan\Type\Constant\ConstantIntegerType; use PHPStan\Type\Constant\ConstantStringType; +use function array_map; use function array_merge; use function count; use function strcasecmp; @@ -23,12 +24,26 @@ class UnionTypeHelper */ public static function getReferencedClasses(array $types): array { - $subTypeClasses = []; - foreach ($types as $type) { - $subTypeClasses[] = $type->getReferencedClasses(); - } + return array_merge( + ...array_map( + static fn (Type $type) => $type->getReferencedClasses(), + $types, + ), + ); + } - return array_merge(...$subTypeClasses); + /** + * @param Type[] $types + * @return list + */ + public static function getConstantArrays(array $types): array + { + return array_merge( + ...array_map( + static fn (Type $type) => $type->getConstantArrays(), + $types, + ), + ); } /** diff --git a/tests/PHPStan/Levels/data/arrayDimFetches-3.json b/tests/PHPStan/Levels/data/arrayDimFetches-3.json index 73c0481c0e..58332eeecb 100644 --- a/tests/PHPStan/Levels/data/arrayDimFetches-3.json +++ b/tests/PHPStan/Levels/data/arrayDimFetches-3.json @@ -3,5 +3,10 @@ "message": "Offset 'b' does not exist on array{a: 1}.", "line": 21, "ignorable": true + }, + { + "message": "Offset 'b' does not exist on array{a: 1}|stdClass.", + "line": 28, + "ignorable": true } ] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/arrayDimFetches-7-missing.json b/tests/PHPStan/Levels/data/arrayDimFetches-7-missing.json new file mode 100644 index 0000000000..8093fba622 --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayDimFetches-7-missing.json @@ -0,0 +1,7 @@ +[ + { + "message": "Offset 'b' does not exist on array{a: 1}|stdClass.", + "line": 28, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/arrayDimFetches-8-missing.json b/tests/PHPStan/Levels/data/arrayDimFetches-8-missing.json new file mode 100644 index 0000000000..8093fba622 --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayDimFetches-8-missing.json @@ -0,0 +1,7 @@ +[ + { + "message": "Offset 'b' does not exist on array{a: 1}|stdClass.", + "line": 28, + "ignorable": true + } +] \ No newline at end of file diff --git a/tests/PHPStan/Levels/data/arrayDimFetches-9-missing.json b/tests/PHPStan/Levels/data/arrayDimFetches-9-missing.json new file mode 100644 index 0000000000..8093fba622 --- /dev/null +++ b/tests/PHPStan/Levels/data/arrayDimFetches-9-missing.json @@ -0,0 +1,7 @@ +[ + { + "message": "Offset 'b' does not exist on array{a: 1}|stdClass.", + "line": 28, + "ignorable": true + } +] \ No newline at end of file