1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 13:21:22 +01:00

Flag invalid enum case value types

Fixes vimeo/psalm#8267
This commit is contained in:
Bruce Weirdan 2022-11-10 01:59:34 -04:00
parent 410c7bb474
commit 6effd1bd2d
3 changed files with 60 additions and 15 deletions

View File

@ -75,3 +75,28 @@ enum Status: string
case Open = "open";
}
```
## Case with a type that back an enum
Case type should be either `int` or `string`.
```php
<?php
enum Status: int {
case Open = [];
}
```
### How to fix
Change the case value so that it's one of the allowed types (and matches the backing type)
```php
<?php
enum Status: int
{
case Open = 1;
}
```

View File

@ -43,6 +43,7 @@ use Psalm\Issue\DuplicateConstant;
use Psalm\Issue\DuplicateEnumCase;
use Psalm\Issue\InvalidDocblock;
use Psalm\Issue\InvalidEnumBackingType;
use Psalm\Issue\InvalidEnumCaseValue;
use Psalm\Issue\InvalidTypeImport;
use Psalm\Issue\MissingDocblockType;
use Psalm\Issue\ParseError;
@ -314,6 +315,17 @@ class ClassLikeNodeScanner
if ($node->scalarType) {
if ($node->scalarType->name === 'string' || $node->scalarType->name === 'int') {
$storage->enum_type = $node->scalarType->name;
$storage->class_implements['backedenum'] = 'BackedEnum';
$storage->direct_class_interfaces['backedenum'] = 'BackedEnum';
$this->file_storage->required_interfaces['backedenum'] = 'BackedEnum';
$this->codebase->scanner->queueClassLikeForScanning('BackedEnum');
$storage->declaring_method_ids['from'] = new MethodIdentifier('BackedEnum', 'from');
$storage->appearing_method_ids['from'] = $storage->declaring_method_ids['from'];
$storage->declaring_method_ids['tryfrom'] = new MethodIdentifier(
'BackedEnum',
'tryfrom'
);
$storage->appearing_method_ids['tryfrom'] = $storage->declaring_method_ids['tryfrom'];
} else {
IssueBuffer::maybeAdd(
new InvalidEnumBackingType(
@ -325,17 +337,6 @@ class ClassLikeNodeScanner
$this->file_storage->has_visitor_issues = true;
$storage->has_visitor_issues = true;
}
$storage->class_implements['backedenum'] = 'BackedEnum';
$storage->direct_class_interfaces['backedenum'] = 'BackedEnum';
$this->file_storage->required_interfaces['backedenum'] = 'BackedEnum';
$this->codebase->scanner->queueClassLikeForScanning('BackedEnum');
$storage->declaring_method_ids['from'] = new MethodIdentifier('BackedEnum', 'from');
$storage->appearing_method_ids['from'] = $storage->declaring_method_ids['from'];
$storage->declaring_method_ids['tryfrom'] = new MethodIdentifier(
'BackedEnum',
'tryfrom'
);
$storage->appearing_method_ids['tryfrom'] = $storage->declaring_method_ids['tryfrom'];
}
$this->codebase->scanner->queueClassLikeForScanning('UnitEnum');
@ -710,7 +711,11 @@ class ClassLikeNodeScanner
} elseif ($node_stmt instanceof PhpParser\Node\Stmt\EnumCase
&& $node instanceof PhpParser\Node\Stmt\Enum_
) {
$this->visitEnumDeclaration($node_stmt, $storage, $fq_classlike_name);
$this->visitEnumDeclaration(
$node_stmt,
$storage,
$fq_classlike_name
);
}
}
@ -1364,6 +1369,8 @@ class ClassLikeNodeScanner
$enum_value = null;
$case_location = new CodeLocation($this->file_scanner, $stmt);
if ($stmt->expr !== null) {
$case_type = SimpleTypeInferer::infer(
$this->codebase,
@ -1381,8 +1388,12 @@ class ClassLikeNodeScanner
} elseif ($case_type->isSingleStringLiteral()) {
$enum_value = $case_type->getSingleStringLiteral()->value;
} else {
throw new RuntimeException(
'Unexpected: case value for ' . $stmt->name->name . ' is ' . $case_type->getId()
IssueBuffer::maybeAdd(
new InvalidEnumCaseValue(
'Case of a backed enum should have either string or int value',
$case_location,
$fq_classlike_name
)
);
}
} else {
@ -1390,7 +1401,6 @@ class ClassLikeNodeScanner
}
}
$case_location = new CodeLocation($this->file_scanner, $stmt);
if (!isset($storage->enum_cases[$stmt->name->name])) {
$case = new EnumCaseStorage(

View File

@ -559,6 +559,16 @@ class EnumTest extends TestCase
'ignored_issues' => [],
'php_version' => '8.1',
],
'invalidCaseTypeForBackedEnum' => [
'code' => '<?php
enum Status: int {
case Open = [];
}
',
'error_message' => 'InvalidEnumCaseValue',
'ignored_issues' => [],
'php_version' => '8.1',
],
'duplicateValues' => [
'code' => '<?php
enum Status: string