mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Fix #2739 - specify wildcards in constants
This commit is contained in:
parent
cecc5ed798
commit
dcc855de95
@ -1311,22 +1311,53 @@ class ExpressionAnalyzer
|
||||
return new Type\Atomic\TLiteralClassString($return_type->fq_classlike_name);
|
||||
}
|
||||
|
||||
try {
|
||||
$class_constant = $codebase->classlikes->getConstantForClass(
|
||||
$return_type->fq_classlike_name,
|
||||
$return_type->const_name,
|
||||
\ReflectionProperty::IS_PRIVATE
|
||||
);
|
||||
} catch (\Psalm\Exception\CircularReferenceException $e) {
|
||||
$class_constant = null;
|
||||
if (strpos($return_type->const_name, '*') !== false) {
|
||||
$class_storage = $codebase->classlike_storage_provider->get($return_type->fq_classlike_name);
|
||||
|
||||
$matching_constants = \array_keys($class_storage->class_constant_locations);
|
||||
|
||||
$const_name_part = \substr($return_type->const_name, 0, -1);
|
||||
|
||||
if ($const_name_part) {
|
||||
$matching_constants = \array_filter(
|
||||
$matching_constants,
|
||||
function ($constant_name) use ($const_name_part) {
|
||||
return $constant_name !== $const_name_part
|
||||
&& \strpos($constant_name, $const_name_part) === 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$matching_constants = [$return_type->const_name];
|
||||
}
|
||||
|
||||
if ($class_constant) {
|
||||
if ($class_constant->isSingle()) {
|
||||
$class_constant = clone $class_constant;
|
||||
$matching_constant_types = [];
|
||||
|
||||
return array_values($class_constant->getAtomicTypes())[0];
|
||||
foreach ($matching_constants as $matching_constant) {
|
||||
try {
|
||||
$class_constant = $codebase->classlikes->getConstantForClass(
|
||||
$return_type->fq_classlike_name,
|
||||
$matching_constant,
|
||||
\ReflectionProperty::IS_PRIVATE
|
||||
);
|
||||
} catch (\Psalm\Exception\CircularReferenceException $e) {
|
||||
$class_constant = null;
|
||||
}
|
||||
|
||||
if ($class_constant) {
|
||||
if ($class_constant->isSingle()) {
|
||||
$class_constant = clone $class_constant;
|
||||
|
||||
$matching_constant_types = \array_merge(
|
||||
\array_values($class_constant->getAtomicTypes()),
|
||||
$matching_constant_types
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($matching_constant_types) {
|
||||
return $matching_constant_types;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -547,7 +547,7 @@ class ParseTree
|
||||
$nexter_token = $i + 2 < $c ? $type_tokens[$i + 2] : null;
|
||||
|
||||
if (!$nexter_token
|
||||
|| (!preg_match('/^[a-zA-Z_][a-zA-Z_0-9]*$/', $nexter_token[0])
|
||||
|| (!preg_match('/^([a-zA-Z_][a-zA-Z_0-9]*\*?|\*)$/', $nexter_token[0])
|
||||
&& strtolower($nexter_token[0]) !== 'class')
|
||||
) {
|
||||
throw new TypeParseTreeException(
|
||||
|
@ -197,7 +197,7 @@ class SimpleNameResolver extends NodeVisitorAbstract
|
||||
* Resolve name, according to name resolver options.
|
||||
*
|
||||
* @param Name $name Function or constant name to resolve
|
||||
* @param int $type One of Stmt\Use_::TYPE_*
|
||||
* @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_*
|
||||
*
|
||||
* @return Name Resolved name, or original name with attribute
|
||||
*/
|
||||
|
@ -622,6 +622,42 @@ class ConstantTest extends TestCase
|
||||
public $foo = "a";
|
||||
}',
|
||||
],
|
||||
'wildcardEnum' => [
|
||||
'<?php
|
||||
class A {
|
||||
const C_1 = 1;
|
||||
const C_2 = 2;
|
||||
const C_3 = 3;
|
||||
|
||||
/**
|
||||
* @param self::C_* $i
|
||||
*/
|
||||
public static function foo(int $i) : void {}
|
||||
}
|
||||
|
||||
A::foo(1);
|
||||
A::foo(2);
|
||||
A::foo(3);',
|
||||
],
|
||||
'wildcardEnumAnyConstant' => [
|
||||
'<?php
|
||||
class A {
|
||||
const C_1 = 1;
|
||||
const C_2 = 2;
|
||||
const C_3 = 3;
|
||||
const D_4 = 4;
|
||||
|
||||
/**
|
||||
* @param self::* $i
|
||||
*/
|
||||
public static function foo(int $i) : void {}
|
||||
}
|
||||
|
||||
A::foo(1);
|
||||
A::foo(2);
|
||||
A::foo(3);
|
||||
A::foo(A::D_4);',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@ -790,6 +826,23 @@ class ConstantTest extends TestCase
|
||||
A::bar("d");',
|
||||
'error_message' => 'InvalidArgument',
|
||||
],
|
||||
'wildcardEnumBadValue' => [
|
||||
'<?php
|
||||
class A {
|
||||
const C_1 = 1;
|
||||
const C_2 = 2;
|
||||
const C_3 = 3;
|
||||
const D_4 = 4;
|
||||
|
||||
/**
|
||||
* @param self::C_* $i
|
||||
*/
|
||||
public static function foo(int $i) : void {}
|
||||
}
|
||||
|
||||
A::foo(A::D_4);',
|
||||
'error_message' => 'InvalidArgument'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user