mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Forbid implementing some interfaces
- `Throwable` can only be implemented when classes extend one of `Exception` or `Error` - `UnitEnum` and `BackedEnum` cannot be implemented by user-defined classes Refs vimeo/psalm#7722
This commit is contained in:
parent
0fb0714141
commit
085e8f6fb2
@ -272,6 +272,7 @@
|
||||
<xs:element name="InvalidFalsableReturnType" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="InvalidFunctionCall" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="InvalidGlobal" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="InvalidInterfaceImplementation" type="ClassIssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="InvalidIterator" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="InvalidLiteralArgument" type="ArgumentIssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="InvalidMethodCall" type="IssueHandlerType" minOccurs="0" />
|
||||
|
@ -48,6 +48,7 @@ Level 5 and above allows a more non-verifiable code, and higher levels are even
|
||||
- [InvalidEnumMethod](issues/InvalidEnumMethod.md)
|
||||
- [InvalidExtendClass](issues/InvalidExtendClass.md)
|
||||
- [InvalidGlobal](issues/InvalidGlobal.md)
|
||||
- [InvalidInterfaceImplementation](issues/InvalidInterfaceImplementation.md)
|
||||
- [InvalidParamDefault](issues/InvalidParamDefault.md)
|
||||
- [InvalidParent](issues/InvalidParent.md)
|
||||
- [InvalidPassByReference](issues/InvalidPassByReference.md)
|
||||
|
@ -75,6 +75,7 @@
|
||||
- [InvalidFalsableReturnType](issues/InvalidFalsableReturnType.md)
|
||||
- [InvalidFunctionCall](issues/InvalidFunctionCall.md)
|
||||
- [InvalidGlobal](issues/InvalidGlobal.md)
|
||||
- [InvalidInterfaceImplementation](issues/InvalidInterfaceImplementation.md)
|
||||
- [InvalidIterator](issues/InvalidIterator.md)
|
||||
- [InvalidLiteralArgument](issues/InvalidLiteralArgument.md)
|
||||
- [InvalidMethodCall](issues/InvalidMethodCall.md)
|
||||
|
15
docs/running_psalm/issues/InvalidInterfaceImplementation.md
Normal file
15
docs/running_psalm/issues/InvalidInterfaceImplementation.md
Normal file
@ -0,0 +1,15 @@
|
||||
# InvalidInterfaceImplementation
|
||||
|
||||
Emitted when trying to implement interface that cannot be implemented (e.g. `Throwable`, `UnitEnum`, `BackedEnum`).
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
class E implements UnitEnum
|
||||
{
|
||||
public static function cases(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
```
|
@ -39,6 +39,7 @@ use Psalm\Issue\InaccessibleMethod;
|
||||
use Psalm\Issue\InternalClass;
|
||||
use Psalm\Issue\InvalidEnumCaseValue;
|
||||
use Psalm\Issue\InvalidExtendClass;
|
||||
use Psalm\Issue\InvalidInterfaceImplementation;
|
||||
use Psalm\Issue\InvalidTraversableImplementation;
|
||||
use Psalm\Issue\MethodSignatureMismatch;
|
||||
use Psalm\Issue\MismatchingDocblockPropertyType;
|
||||
@ -2114,6 +2115,35 @@ class ClassAnalyzer extends ClassLikeAnalyzer
|
||||
);
|
||||
}
|
||||
|
||||
if ($fq_interface_name_lc === 'throwable'
|
||||
&& $codebase->analysis_php_version_id >= 7_00_00
|
||||
&& !$storage->abstract
|
||||
&& !isset($storage->parent_classes['exception'])
|
||||
&& !isset($storage->parent_classes['error'])
|
||||
) {
|
||||
IssueBuffer::maybeAdd(
|
||||
new InvalidInterfaceImplementation(
|
||||
'Classes implementing Throwable should extend Exception or Error',
|
||||
$code_location,
|
||||
$fq_class_name,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (($fq_interface_name_lc === 'unitenum'
|
||||
|| $fq_interface_name_lc === 'backedenum')
|
||||
&& !$storage->is_enum
|
||||
&& $codebase->analysis_php_version_id >= 8_01_00
|
||||
) {
|
||||
IssueBuffer::maybeAdd(
|
||||
new InvalidInterfaceImplementation(
|
||||
$fq_interface_name . ' cannot be implemented by classes',
|
||||
$code_location,
|
||||
$fq_class_name,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if ($interface_storage->deprecated) {
|
||||
IssueBuffer::maybeAdd(
|
||||
new DeprecatedInterface(
|
||||
|
9
src/Psalm/Issue/InvalidInterfaceImplementation.php
Normal file
9
src/Psalm/Issue/InvalidInterfaceImplementation.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class InvalidInterfaceImplementation extends ClassIssue
|
||||
{
|
||||
const ERROR_LEVEL = -1;
|
||||
const SHORTCODE = 317;
|
||||
}
|
@ -1202,6 +1202,14 @@ class ClassTest extends TestCase
|
||||
',
|
||||
'error_message' => 'MixedMethodCall',
|
||||
],
|
||||
'forbiddenThrowableImplementation' => [
|
||||
'code' => '<?php
|
||||
class C implements Throwable {}
|
||||
',
|
||||
'error_message' => 'InvalidInterfaceImplementation',
|
||||
'ignored_issues' => [],
|
||||
'php_version' => '7.0',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -308,6 +308,7 @@ class DocumentationTest extends TestCase
|
||||
case 'InvalidEnumMethod':
|
||||
case 'NoEnumProperties':
|
||||
case 'OverriddenFinalConstant':
|
||||
case 'InvalidInterfaceImplementation':
|
||||
$php_version = '8.1';
|
||||
break;
|
||||
}
|
||||
|
@ -765,6 +765,46 @@ class EnumTest extends TestCase
|
||||
'ignored_issues' => [],
|
||||
'php_version' => '8.1',
|
||||
],
|
||||
'forbiddenUnitEnumImplementation' => [
|
||||
'code' => '<?php
|
||||
class Foo implements UnitEnum {
|
||||
/** @psalm-pure */
|
||||
public static function cases(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
',
|
||||
'error_message' => 'InvalidInterfaceImplementation',
|
||||
'ignored_issues' => [],
|
||||
'php_version' => '8.1',
|
||||
],
|
||||
'forbiddenBackedEnumImplementation' => [
|
||||
'code' => '<?php
|
||||
class Foo implements BackedEnum {
|
||||
/** @psalm-pure */
|
||||
public static function cases(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/** @psalm-pure */
|
||||
public static function from(int|string $value): static
|
||||
{
|
||||
throw new Exception;
|
||||
}
|
||||
|
||||
/** @psalm-pure */
|
||||
public static function tryFrom(int|string $value): ?static
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
',
|
||||
'error_message' => 'InvalidInterfaceImplementation',
|
||||
'ignored_issues' => [],
|
||||
'php_version' => '8.1',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user