diff --git a/rules-tests/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector/FixtureComplexTypes/parse_url_with_second_arg.php.inc b/rules-tests/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector/FixtureComplexTypes/parse_url_with_second_arg.php.inc new file mode 100644 index 00000000000..1ce1f1a1f9b --- /dev/null +++ b/rules-tests/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector/FixtureComplexTypes/parse_url_with_second_arg.php.inc @@ -0,0 +1,31 @@ +host = parse_url($url, \PHP_URL_HOST); + } +} + +?> +----- +host = parse_url($url, \PHP_URL_HOST); + } +} + +?> diff --git a/rules/TypeDeclaration/TypeInferer/AssignToPropertyTypeInferer.php b/rules/TypeDeclaration/TypeInferer/AssignToPropertyTypeInferer.php index 3ff1e60a3a1..23e83321f11 100644 --- a/rules/TypeDeclaration/TypeInferer/AssignToPropertyTypeInferer.php +++ b/rules/TypeDeclaration/TypeInferer/AssignToPropertyTypeInferer.php @@ -86,11 +86,14 @@ private function resolveTypeWithVerifyDefaultValue(Property $property, array $as } $inferredType = $this->typeFactory->createMixedPassedOrUnionType($assignedExprTypes); + // to compare with default value, constant type must not be kept + // eg, use more general bool over false or true if ($this->shouldSkipWithDifferentDefaultValueType($defaultPropertyValue, $inferredType)) { return null; } - return $inferredType; + // returns with constant as final result + return $this->typeFactory->createMixedPassedOrUnionType($assignedExprTypes, true); } private function shouldSkipWithDifferentDefaultValueType(?Expr $expr, Type $inferredType): bool diff --git a/src/NodeAnalyzer/ExprAnalyzer.php b/src/NodeAnalyzer/ExprAnalyzer.php index a588d81ed2b..121637a3d02 100644 --- a/src/NodeAnalyzer/ExprAnalyzer.php +++ b/src/NodeAnalyzer/ExprAnalyzer.php @@ -40,12 +40,15 @@ public function isNonTypedFromParam(Expr $expr): bool } $nativeType = $scope->getNativeType($expr); - if ($nativeType instanceof MixedType && ! $nativeType->isExplicitMixed()) { + $type = $scope->getType($expr); + if ( + ($nativeType instanceof MixedType && ! $nativeType->isExplicitMixed()) + || + ($nativeType instanceof MixedType && ! $type instanceof MixedType) + ) { return true; } - $type = $scope->getType($expr); - if ($nativeType instanceof ObjectWithoutClassType && ! $type instanceof ObjectWithoutClassType) { return true; } diff --git a/src/NodeTypeResolver/NodeTypeResolver.php b/src/NodeTypeResolver/NodeTypeResolver.php index 9f48b1c5c42..3b58e3eb4e3 100644 --- a/src/NodeTypeResolver/NodeTypeResolver.php +++ b/src/NodeTypeResolver/NodeTypeResolver.php @@ -9,11 +9,13 @@ use PhpParser\Node\Expr\ArrayDimFetch; use PhpParser\Node\Expr\BinaryOp\Coalesce; use PhpParser\Node\Expr\ClassConstFetch; +use PhpParser\Node\Expr\FuncCall; use PhpParser\Node\Expr\MethodCall; use PhpParser\Node\Expr\New_; use PhpParser\Node\Expr\NullsafeMethodCall; use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Expr\Ternary; +use PhpParser\Node\Name; use PhpParser\Node\NullableType; use PhpParser\Node\Scalar\String_; use PhpParser\Node\Stmt\ClassConst; @@ -23,6 +25,7 @@ use PHPStan\Analyser\Scope; use PHPStan\Broker\ClassAutoloadingException; use PHPStan\Reflection\ClassReflection; +use PHPStan\Reflection\Native\NativeFunctionReflection; use PHPStan\Reflection\ReflectionProvider; use PHPStan\Type\ArrayType; use PHPStan\Type\Constant\ConstantArrayType; @@ -559,6 +562,23 @@ private function resolveNativeTypeWithBuiltinMethodCallFallback(Expr $expr, Scop } } + if ($expr instanceof FuncCall) { + if (! $expr->name instanceof Name) { + return $scope->getNativeType($expr); + } + + if (! $this->reflectionProvider->hasFunction($expr->name, $scope)) { + return $scope->getNativeType($expr); + } + + $functionReflection = $this->reflectionProvider->getFunction($expr->name, $scope); + if (! $functionReflection instanceof NativeFunctionReflection) { + return $scope->getNativeType($expr); + } + + return $scope->getType($expr); + } + return $scope->getNativeType($expr); } }