mirror of
https://github.com/danog/psalm.git
synced 2024-12-02 09:37:59 +01:00
Merge branch 'master' into fix-shepherd-without-custom-domain
This commit is contained in:
commit
73f90229bb
@ -62,7 +62,9 @@ use Psalm\Type\Atomic\TString;
|
|||||||
use Psalm\Type\Atomic\TTemplateParam;
|
use Psalm\Type\Atomic\TTemplateParam;
|
||||||
use Psalm\Type\Union;
|
use Psalm\Type\Union;
|
||||||
|
|
||||||
|
use function array_filter;
|
||||||
use function array_keys;
|
use function array_keys;
|
||||||
|
use function array_map;
|
||||||
use function array_search;
|
use function array_search;
|
||||||
use function count;
|
use function count;
|
||||||
use function in_array;
|
use function in_array;
|
||||||
@ -70,6 +72,8 @@ use function is_int;
|
|||||||
use function is_string;
|
use function is_string;
|
||||||
use function strtolower;
|
use function strtolower;
|
||||||
|
|
||||||
|
use const ARRAY_FILTER_USE_KEY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ -198,7 +202,7 @@ class AtomicPropertyFetchAnalyzer
|
|||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
} elseif ($prop_name === 'value' && $class_storage->enum_type !== null && $class_storage->enum_cases) {
|
} elseif ($prop_name === 'value' && $class_storage->enum_type !== null && $class_storage->enum_cases) {
|
||||||
self::handleEnumValue($statements_analyzer, $stmt, $class_storage);
|
self::handleEnumValue($statements_analyzer, $stmt, $stmt_var_type, $class_storage);
|
||||||
} elseif ($prop_name === 'name') {
|
} elseif ($prop_name === 'name') {
|
||||||
self::handleEnumName($statements_analyzer, $stmt, $lhs_type_part);
|
self::handleEnumName($statements_analyzer, $stmt, $lhs_type_part);
|
||||||
} else {
|
} else {
|
||||||
@ -941,11 +945,31 @@ class AtomicPropertyFetchAnalyzer
|
|||||||
private static function handleEnumValue(
|
private static function handleEnumValue(
|
||||||
StatementsAnalyzer $statements_analyzer,
|
StatementsAnalyzer $statements_analyzer,
|
||||||
PropertyFetch $stmt,
|
PropertyFetch $stmt,
|
||||||
|
Union $stmt_var_type,
|
||||||
ClassLikeStorage $class_storage
|
ClassLikeStorage $class_storage
|
||||||
): void {
|
): void {
|
||||||
|
$relevant_enum_cases = array_filter(
|
||||||
|
$stmt_var_type->getAtomicTypes(),
|
||||||
|
static fn(Atomic $type): bool => $type instanceof TEnumCase,
|
||||||
|
);
|
||||||
|
$relevant_enum_case_names = array_map(
|
||||||
|
static fn(TEnumCase $enumCase): string => $enumCase->case_name,
|
||||||
|
$relevant_enum_cases,
|
||||||
|
);
|
||||||
|
|
||||||
|
$enum_cases = $class_storage->enum_cases;
|
||||||
|
if (!empty($relevant_enum_case_names)) {
|
||||||
|
// If we have a known subset of enum cases, include only those
|
||||||
|
$enum_cases = array_filter(
|
||||||
|
$enum_cases,
|
||||||
|
static fn(string $key) => in_array($key, $relevant_enum_case_names, true),
|
||||||
|
ARRAY_FILTER_USE_KEY,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$case_values = [];
|
$case_values = [];
|
||||||
|
|
||||||
foreach ($class_storage->enum_cases as $enum_case) {
|
foreach ($enum_cases as $enum_case) {
|
||||||
if (is_string($enum_case->value)) {
|
if (is_string($enum_case->value)) {
|
||||||
$case_values[] = new TLiteralString($enum_case->value);
|
$case_values[] = new TLiteralString($enum_case->value);
|
||||||
} elseif (is_int($enum_case->value)) {
|
} elseif (is_int($enum_case->value)) {
|
||||||
@ -956,7 +980,6 @@ class AtomicPropertyFetchAnalyzer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: this is suboptimal when we reference enum directly, e.g. Status::Open->value
|
|
||||||
/** @psalm-suppress ArgumentTypeCoercion */
|
/** @psalm-suppress ArgumentTypeCoercion */
|
||||||
$statements_analyzer->node_data->setType(
|
$statements_analyzer->node_data->setType(
|
||||||
$stmt,
|
$stmt,
|
||||||
|
@ -36,17 +36,19 @@ class DocCommentTest extends BaseTestCase
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
$expectedDoc = '/**
|
$expectedDoc = <<<'PHP'
|
||||||
* some desc
|
/**
|
||||||
*
|
* some desc
|
||||||
* @param string $bli
|
*
|
||||||
* @param int $bla
|
* @param string $bli
|
||||||
*
|
* @param int $bla
|
||||||
* @throws \Exception
|
*
|
||||||
*
|
* @throws \Exception
|
||||||
* @return bool
|
*
|
||||||
*/
|
* @return bool
|
||||||
';
|
*/
|
||||||
|
|
||||||
|
PHP;
|
||||||
|
|
||||||
$this->assertSame($expectedDoc, $docComment->render(''));
|
$this->assertSame($expectedDoc, $docComment->render(''));
|
||||||
}
|
}
|
||||||
@ -74,15 +76,17 @@ class DocCommentTest extends BaseTestCase
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
$expectedDoc = '/**
|
$expectedDoc = <<<'PHP'
|
||||||
* some desc
|
/**
|
||||||
*
|
* some desc
|
||||||
* @param string $bli
|
*
|
||||||
* @param int $bla
|
* @param string $bli
|
||||||
* @throws \Exception
|
* @param int $bla
|
||||||
* @return bool
|
* @throws \Exception
|
||||||
*/
|
* @return bool
|
||||||
';
|
*/
|
||||||
|
|
||||||
|
PHP;
|
||||||
|
|
||||||
$this->assertSame($expectedDoc, $docComment->render(''));
|
$this->assertSame($expectedDoc, $docComment->render(''));
|
||||||
}
|
}
|
||||||
@ -110,17 +114,19 @@ class DocCommentTest extends BaseTestCase
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
$expectedDoc = '/**
|
$expectedDoc = <<<'PHP'
|
||||||
* some desc
|
/**
|
||||||
*
|
* some desc
|
||||||
* @param string $bli
|
*
|
||||||
* @param int $bla
|
* @param string $bli
|
||||||
*
|
* @param int $bla
|
||||||
* @throws \Exception
|
*
|
||||||
*
|
* @throws \Exception
|
||||||
* @return bool
|
*
|
||||||
*/
|
* @return bool
|
||||||
';
|
*/
|
||||||
|
|
||||||
|
PHP;
|
||||||
|
|
||||||
$this->assertSame($expectedDoc, $docComment->render(''));
|
$this->assertSame($expectedDoc, $docComment->render(''));
|
||||||
}
|
}
|
||||||
@ -129,17 +135,19 @@ class DocCommentTest extends BaseTestCase
|
|||||||
{
|
{
|
||||||
ParsedDocblock::addNewLineBetweenAnnotations(true);
|
ParsedDocblock::addNewLineBetweenAnnotations(true);
|
||||||
|
|
||||||
$expectedDoc = '/**
|
$expectedDoc = <<<'PHP'
|
||||||
* some desc
|
/**
|
||||||
*
|
* some desc
|
||||||
* @param string $bli
|
*
|
||||||
* @param int $bla
|
* @param string $bli
|
||||||
*
|
* @param int $bla
|
||||||
* @throws \Exception
|
*
|
||||||
*
|
* @throws \Exception
|
||||||
* @return bool
|
*
|
||||||
*/
|
* @return bool
|
||||||
';
|
*/
|
||||||
|
|
||||||
|
PHP;
|
||||||
$docComment = DocComment::parsePreservingLength(
|
$docComment = DocComment::parsePreservingLength(
|
||||||
new Doc($expectedDoc),
|
new Doc($expectedDoc),
|
||||||
);
|
);
|
||||||
@ -151,17 +159,21 @@ class DocCommentTest extends BaseTestCase
|
|||||||
{
|
{
|
||||||
ParsedDocblock::addNewLineBetweenAnnotations(true);
|
ParsedDocblock::addNewLineBetweenAnnotations(true);
|
||||||
|
|
||||||
$expectedDoc = '/**
|
$expectedDoc = <<<'PHP'
|
||||||
* some desc
|
/**
|
||||||
*
|
* some desc
|
||||||
* @param string $bli
|
*
|
||||||
* @param int $bla
|
* @param string $bli
|
||||||
*
|
* @param int $bla
|
||||||
* @throws \Exception
|
*
|
||||||
*
|
* @throws \Exception
|
||||||
* @return bool
|
*
|
||||||
*/
|
* @return bool
|
||||||
';
|
*/
|
||||||
|
|
||||||
|
PHP
|
||||||
|
. " ";
|
||||||
|
|
||||||
$docComment = DocComment::parsePreservingLength(
|
$docComment = DocComment::parsePreservingLength(
|
||||||
new Doc($expectedDoc),
|
new Doc($expectedDoc),
|
||||||
);
|
);
|
||||||
@ -173,19 +185,21 @@ class DocCommentTest extends BaseTestCase
|
|||||||
{
|
{
|
||||||
ParsedDocblock::addNewLineBetweenAnnotations(true);
|
ParsedDocblock::addNewLineBetweenAnnotations(true);
|
||||||
|
|
||||||
$expectedDoc = '/**
|
$expectedDoc = <<<'PHP'
|
||||||
* some self-referential desc with " * @return bool
|
/**
|
||||||
* " as part of it.
|
* some self-referential desc with " * @return bool
|
||||||
*
|
* " as part of it.
|
||||||
* @param string $bli
|
*
|
||||||
* @param string $bli_this_suffix_is_kept
|
* @param string $bli
|
||||||
* @param int $bla
|
* @param string $bli_this_suffix_is_kept
|
||||||
*
|
* @param int $bla
|
||||||
* @throws \Exception
|
*
|
||||||
*
|
* @throws \Exception
|
||||||
* @return bool
|
*
|
||||||
*/
|
* @return bool
|
||||||
';
|
*/
|
||||||
|
|
||||||
|
PHP;
|
||||||
$docComment = DocComment::parsePreservingLength(
|
$docComment = DocComment::parsePreservingLength(
|
||||||
new Doc($expectedDoc),
|
new Doc($expectedDoc),
|
||||||
);
|
);
|
||||||
|
@ -94,12 +94,70 @@ class EnumTest extends TestCase
|
|||||||
$z = Mask::Two->value;
|
$z = Mask::Two->value;
|
||||||
',
|
',
|
||||||
'assertions' => [
|
'assertions' => [
|
||||||
// xxx: we should be able to do better when we reference a case explicitly, like above
|
'$z===' => '2',
|
||||||
|
],
|
||||||
|
'ignored_issues' => [],
|
||||||
|
'php_version' => '8.1',
|
||||||
|
],
|
||||||
|
'EnumCaseValue #8568' => [
|
||||||
|
'code' => '<?php
|
||||||
|
enum Mask: int {
|
||||||
|
case One = 1 << 0;
|
||||||
|
case Two = 1 << 1;
|
||||||
|
}
|
||||||
|
/** @return Mask */
|
||||||
|
function a() {
|
||||||
|
return Mask::One;
|
||||||
|
}
|
||||||
|
|
||||||
|
$z = a()->value;
|
||||||
|
',
|
||||||
|
'assertions' => [
|
||||||
'$z===' => '1|2',
|
'$z===' => '1|2',
|
||||||
],
|
],
|
||||||
'ignored_issues' => [],
|
'ignored_issues' => [],
|
||||||
'php_version' => '8.1',
|
'php_version' => '8.1',
|
||||||
],
|
],
|
||||||
|
'EnumUnionAsCaseValue #8568' => [
|
||||||
|
'code' => '<?php
|
||||||
|
enum Mask: int {
|
||||||
|
case One = 1 << 0;
|
||||||
|
case Two = 1 << 1;
|
||||||
|
case Four = 1 << 2;
|
||||||
|
}
|
||||||
|
/** @return Mask::One|Mask::Two */
|
||||||
|
function a() {
|
||||||
|
return Mask::One;
|
||||||
|
}
|
||||||
|
|
||||||
|
$z = a()->value;
|
||||||
|
',
|
||||||
|
'assertions' => [
|
||||||
|
'$z===' => '1|2',
|
||||||
|
],
|
||||||
|
'ignored_issues' => [],
|
||||||
|
'php_version' => '8.1',
|
||||||
|
],
|
||||||
|
'matchCaseOnEnumValue #8812' => [
|
||||||
|
'code' => '<?php
|
||||||
|
enum SomeType: string
|
||||||
|
{
|
||||||
|
case FOO = "FOO";
|
||||||
|
case BAR = "BAR";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSomething(string $moduleString): int
|
||||||
|
{
|
||||||
|
return match ($moduleString) {
|
||||||
|
SomeType::FOO->value => 1,
|
||||||
|
SomeType::BAR->value => 2,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
',
|
||||||
|
'assertions' => [],
|
||||||
|
'ignored_issues' => [],
|
||||||
|
'php_version' => '8.1',
|
||||||
|
],
|
||||||
'namePropertyFromOutside' => [
|
'namePropertyFromOutside' => [
|
||||||
'code' => '<?php
|
'code' => '<?php
|
||||||
enum Status
|
enum Status
|
||||||
|
Loading…
Reference in New Issue
Block a user