diff --git a/psalm.xml b/psalm.xml index bb4ac1f..71e33ca 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,14 +1,17 @@ + @@ -30,6 +33,11 @@ + + + + + diff --git a/src/Doctrine/PlatenumDoctrineType.php b/src/Doctrine/PlatenumDoctrineType.php index 8c194fc..586e438 100644 --- a/src/Doctrine/PlatenumDoctrineType.php +++ b/src/Doctrine/PlatenumDoctrineType.php @@ -6,7 +6,10 @@ use Doctrine\DBAL\Types\Type; use Thunder\Platenum\Enum\EnumTrait; -/** @psalm-suppress PropertyNotSetInConstructor, MissingConstructor */ +/** + * @psalm-suppress PropertyNotSetInConstructor, MissingConstructor + * @psalm-external-mutation-free + */ final class PlatenumDoctrineType extends Type { /** @var class-string */ @@ -107,6 +110,7 @@ public function getName(): string public function getSQLDeclaration(array $column, AbstractPlatform $platform): string { + /** @psalm-suppress ImpureFunctionCall */ return ($this->platenumSql)($column, $platform); } @@ -120,7 +124,7 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) throw new \LogicException(sprintf($message, self::class, gettype($value))); } - /** @psalm-suppress MixedMethodCall */ + /** @psalm-suppress MixedMethodCall,ImpureFunctionCall */ return ($this->platenumCallback)($value->getValue()); } @@ -130,7 +134,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) return null; } - /** @psalm-suppress MixedMethodCall */ + /** @psalm-suppress MixedMethodCall,ImpureFunctionCall */ return ($this->platenumClass)::fromValue(($this->platenumCallback)($value)); } diff --git a/src/Enum/AbstractCallbackEnum.php b/src/Enum/AbstractCallbackEnum.php index 49d812f..6543a16 100644 --- a/src/Enum/AbstractCallbackEnum.php +++ b/src/Enum/AbstractCallbackEnum.php @@ -4,8 +4,11 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ abstract class AbstractCallbackEnum implements \JsonSerializable { + /** @use CallbackEnumTrait */ use CallbackEnumTrait; } diff --git a/src/Enum/AbstractConstantsEnum.php b/src/Enum/AbstractConstantsEnum.php index 696b0d6..cb3faf4 100644 --- a/src/Enum/AbstractConstantsEnum.php +++ b/src/Enum/AbstractConstantsEnum.php @@ -4,8 +4,11 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ abstract class AbstractConstantsEnum implements \JsonSerializable { + /** @use ConstantsEnumTrait */ use ConstantsEnumTrait; } diff --git a/src/Enum/AbstractDocblockEnum.php b/src/Enum/AbstractDocblockEnum.php index d7d994c..2ae7bc8 100644 --- a/src/Enum/AbstractDocblockEnum.php +++ b/src/Enum/AbstractDocblockEnum.php @@ -4,8 +4,11 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ abstract class AbstractDocblockEnum implements \JsonSerializable { + /** @use DocblockEnumTrait */ use DocblockEnumTrait; } diff --git a/src/Enum/AbstractStaticEnum.php b/src/Enum/AbstractStaticEnum.php index 6f347fa..fb16bb2 100644 --- a/src/Enum/AbstractStaticEnum.php +++ b/src/Enum/AbstractStaticEnum.php @@ -4,9 +4,12 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ abstract class AbstractStaticEnum implements \JsonSerializable { + /** @use StaticEnumTrait */ use StaticEnumTrait; /** @var array */ diff --git a/src/Enum/CallbackEnumTrait.php b/src/Enum/CallbackEnumTrait.php index 6c8b773..a45cf07 100644 --- a/src/Enum/CallbackEnumTrait.php +++ b/src/Enum/CallbackEnumTrait.php @@ -6,9 +6,12 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ trait CallbackEnumTrait { + /** @use EnumTrait */ use EnumTrait; /** @var non-empty-array> */ diff --git a/src/Enum/ConstantsEnumTrait.php b/src/Enum/ConstantsEnumTrait.php index 4a1aea5..4930e1f 100644 --- a/src/Enum/ConstantsEnumTrait.php +++ b/src/Enum/ConstantsEnumTrait.php @@ -4,9 +4,12 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ trait ConstantsEnumTrait { + /** @use EnumTrait */ use EnumTrait; private static function resolve(): array diff --git a/src/Enum/DocblockEnumTrait.php b/src/Enum/DocblockEnumTrait.php index 0784a7d..5bf71b4 100644 --- a/src/Enum/DocblockEnumTrait.php +++ b/src/Enum/DocblockEnumTrait.php @@ -6,9 +6,12 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ trait DocblockEnumTrait { + /** @use EnumTrait */ use EnumTrait; private static function resolve(): array diff --git a/src/Enum/EnumTrait.php b/src/Enum/EnumTrait.php index 6bd7e27..0a7b514 100644 --- a/src/Enum/EnumTrait.php +++ b/src/Enum/EnumTrait.php @@ -6,20 +6,22 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ trait EnumTrait { /** @var string */ private $member; - /** @var int|string */ + /** @psalm-var T */ private $value; - /** @var non-empty-array> */ + /** @psalm-var non-empty-array> */ protected static $members = []; /** @var array> */ protected static $instances = []; - /** @param int|string $value */ + /** @psalm-param T $value */ /* final */ private function __construct(string $member, $value) { $this->member = $member; @@ -51,8 +53,18 @@ final public static function fromMember(string $member): self static::throwDefaultInvalidMemberException($member); } + /** @psalm-suppress PropertyTypeCoercion */ + return static::$instances[$class][$member] = static::fromMemberAndValue($member, static::$members[$class][$member]); + } + + /** + * @psalm-param int|string $value + * @psalm-return static + */ + /* final */ private static function fromMemberAndValue(string $member, $value): self + { /** @psalm-suppress UnsafeInstantiation */ - return static::$instances[$class][$member] = new static($member, static::$members[$class][$member]); + return new static($member, $value); } /** @@ -91,12 +103,15 @@ final public static function fromEnum($enum): self } /** - * @param static $enum - * @param-out AbstractConstantsEnum|AbstractDocblockEnum|AbstractStaticEnum|AbstractCallbackEnum|AbstractAttributeEnum $enum + * @param self &$enum + * @param-out self $enum + * @psalm-suppress ReferenceConstraintViolation */ final public function fromInstance(&$enum): void { - $enum = static::fromEnum($enum); + /** @psalm-suppress ImpureMethodCall,ArgumentTypeCoercion */ + $instance = static::fromEnum($enum); + $enum = $instance; } /** @@ -154,12 +169,13 @@ final public function getMember(): string return $this->member; } - /** @return int|string */ + /** @psalm-return T */ final public function getValue() { return $this->value; } + /** @psalm-return T */ #[\ReturnTypeWillChange] final public function jsonSerialize() { @@ -209,7 +225,7 @@ final public function hasMember(string $members): bool return $members === $this->member; } - /** @param int|string $value */ + /** @psalm-param T $value */ final public function hasValue($value): bool { return $value === $this->value; @@ -293,7 +309,7 @@ private static function resolveMembers(): void // reflection instead of method_exists because of PHP 7.4 bug #78632 // @see https://bugs.php.net/bug.php?id=78632 $hasResolve = (new \ReflectionClass($class))->hasMethod('resolve'); - /** @var array $members */ + /** @psalm-var array $members */ $members = $hasResolve ? static::resolve() : $throwMissingResolve($class); if(empty($members)) { throw PlatenumException::fromEmptyMembers($class); @@ -308,6 +324,7 @@ private static function resolveMembers(): void throw PlatenumException::fromNonUniformMemberValues($class, $members); } + /** @psalm-suppress MixedPropertyTypeCoercion */ static::$members[$class] = $members; } diff --git a/src/Enum/StaticEnumTrait.php b/src/Enum/StaticEnumTrait.php index 738cee2..01a54eb 100644 --- a/src/Enum/StaticEnumTrait.php +++ b/src/Enum/StaticEnumTrait.php @@ -6,9 +6,12 @@ /** * @author Tomasz Kowalczyk + * @psalm-template T + * @psalm-immutable */ trait StaticEnumTrait { + /** @use EnumTrait */ use EnumTrait; private static function resolve(): array diff --git a/tests/Psalm/PsalmConstantsExtendsEnum.php b/tests/Psalm/PsalmConstantsExtendsEnum.php new file mode 100644 index 0000000..54be986 --- /dev/null +++ b/tests/Psalm/PsalmConstantsExtendsEnum.php @@ -0,0 +1,18 @@ + + * @psalm-immutable + * @psalm-suppress PropertyNotSetInConstructor + */ +final class PsalmConstantsExtendsEnum extends AbstractConstantsEnum +{ + public const FIRST = 1; + public const SECOND = 2; +} diff --git a/tests/Psalm/PsalmConstantsTraitEnum.php b/tests/Psalm/PsalmConstantsTraitEnum.php new file mode 100644 index 0000000..d9e06e8 --- /dev/null +++ b/tests/Psalm/PsalmConstantsTraitEnum.php @@ -0,0 +1,20 @@ + */ + use ConstantsEnumTrait; + + public const FIRST = 1; + public const SECOND = 2; +} diff --git a/tests/Psalm/PsalmEnum.php b/tests/Psalm/PsalmEnum.php new file mode 100644 index 0000000..7c465c6 --- /dev/null +++ b/tests/Psalm/PsalmEnum.php @@ -0,0 +1,17 @@ +