Prevent UnionTypes rule from removing literal value scalar types (#1666)

This commit is contained in:
Simon Podlipsky 2022-01-14 15:58:11 +01:00 committed by GitHub
parent fda8d1af45
commit 0947481ee6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 10 deletions

View File

@ -12,6 +12,7 @@ use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\ArrayType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\ConstantScalarType;
use PHPStan\Type\Generic\GenericClassStringType;
use PHPStan\Type\IntegerType;
use PHPStan\Type\MixedType;
@ -103,18 +104,11 @@ final class TypeComparator
return false;
}
// special case for non-final $this/self compare; in case of interface/abstract class, it can be another $this
if ($phpStanDocType instanceof ThisType && $phpParserNodeType instanceof ThisType) {
$scope = $node->getAttribute(AttributeKey::SCOPE);
if ($scope instanceof Scope) {
$classReflection = $scope->getClassReflection();
if ($classReflection instanceof ClassReflection) {
return $classReflection->isFinal();
}
}
if ($this->areTypesSameWithLiteralTypeInPhpDoc($areDifferentScalarTypes, $phpStanDocType, $phpParserNodeType)) {
return false;
}
return true;
return $this->isThisTypeInFinalClass($phpStanDocType, $phpParserNodeType, $node);
}
public function isSubtype(Type $checkedType, Type $mainType): bool
@ -264,4 +258,31 @@ final class TypeComparator
&& $phpParserNodeType instanceof ThisType
&& $phpStanDocTypeNode->getAttribute(PhpDocAttributeKey::PARENT) instanceof ParamTagValueNode;
}
private function areTypesSameWithLiteralTypeInPhpDoc(
bool $areDifferentScalarTypes,
Type $phpStanDocType,
Type $phpParserNodeType
): bool
{
return $areDifferentScalarTypes
&& $phpStanDocType instanceof ConstantScalarType
&& $phpParserNodeType->isSuperTypeOf($phpStanDocType)->yes();
}
private function isThisTypeInFinalClass(Type $phpStanDocType, Type $phpParserNodeType, Node $node) : bool
{
// special case for non-final $this/self compare; in case of interface/abstract class, it can be another $this
if ($phpStanDocType instanceof ThisType && $phpParserNodeType instanceof ThisType) {
$scope = $node->getAttribute(AttributeKey::SCOPE);
if ($scope instanceof Scope) {
$classReflection = $scope->getClassReflection();
if ($classReflection instanceof ClassReflection) {
return $classReflection->isFinal();
}
}
}
return true;
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace Rector\Tests\Php80\Rector\FunctionLike\UnionTypesRector\Fixture;
final class SkipLiteralValueStringUnionType
{
/**
* @param 'a' $message
*/
private function getMessage(string $message): string
{
return $message;
}
}