mirror of
https://github.com/danog/psalm.git
synced 2025-01-22 05:41:20 +01:00
Add TTypeAlias object with a creation path
This commit is contained in:
parent
190c9ce27e
commit
2327a0db6b
@ -8,6 +8,16 @@ class TypeAlias
|
||||
*/
|
||||
public $replacement_tokens = null;
|
||||
|
||||
/**
|
||||
* @var ?string
|
||||
*/
|
||||
public $declaring_fq_classlike_name = null;
|
||||
|
||||
/**
|
||||
* @var ?string
|
||||
*/
|
||||
public $alias_name = null;
|
||||
|
||||
/**
|
||||
* @param list<array{0: string, 1: int}>|null $replacement_tokens
|
||||
*/
|
||||
|
@ -53,13 +53,15 @@ class TypeParser
|
||||
* @param list<array{0: string, 1: int}> $type_tokens
|
||||
* @param array{int,int}|null $php_version
|
||||
* @param array<string, array<string, array{Union}>> $template_type_map
|
||||
* @param array<string, TypeAlias> $type_aliases
|
||||
*
|
||||
* @return Union
|
||||
*/
|
||||
public static function parseTokens(
|
||||
array $type_tokens,
|
||||
array $php_version = null,
|
||||
array $template_type_map = []
|
||||
array $template_type_map = [],
|
||||
array $type_aliases = []
|
||||
) {
|
||||
if (count($type_tokens) === 1) {
|
||||
$only_token = $type_tokens[0];
|
||||
@ -89,7 +91,8 @@ class TypeParser
|
||||
$parse_tree,
|
||||
$codebase,
|
||||
$php_version,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
|
||||
if (!($parsed_type instanceof Union)) {
|
||||
@ -103,6 +106,7 @@ class TypeParser
|
||||
* @param ParseTree $parse_tree
|
||||
* @param array{int,int}|null $php_version
|
||||
* @param array<string, array<string, array{Union}>> $template_type_map
|
||||
* @param array<string, TypeAlias> $type_aliases
|
||||
*
|
||||
* @return Atomic|Union
|
||||
*/
|
||||
@ -110,7 +114,8 @@ class TypeParser
|
||||
ParseTree $parse_tree,
|
||||
Codebase $codebase,
|
||||
array $php_version = null,
|
||||
array $template_type_map = []
|
||||
array $template_type_map = [],
|
||||
array $type_aliases = []
|
||||
) {
|
||||
if ($parse_tree instanceof ParseTree\GenericTree) {
|
||||
$generic_type = $parse_tree->value;
|
||||
@ -122,7 +127,8 @@ class TypeParser
|
||||
$child_tree,
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
|
||||
if ($generic_type === 'class-string-map'
|
||||
@ -339,7 +345,8 @@ class TypeParser
|
||||
$child_tree->children[0],
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
$has_null = true;
|
||||
} else {
|
||||
@ -347,7 +354,8 @@ class TypeParser
|
||||
$child_tree,
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
}
|
||||
|
||||
@ -380,12 +388,13 @@ class TypeParser
|
||||
/**
|
||||
* @return Atomic
|
||||
*/
|
||||
function (ParseTree $child_tree) use ($codebase, $template_type_map) {
|
||||
function (ParseTree $child_tree) use ($codebase, $template_type_map, $type_aliases) {
|
||||
$atomic_type = self::getTypeFromTree(
|
||||
$child_tree,
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
|
||||
if (!$atomic_type instanceof Atomic) {
|
||||
@ -492,7 +501,8 @@ class TypeParser
|
||||
$property_branch,
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
$property_maybe_undefined = false;
|
||||
$property_key = (string)$i;
|
||||
@ -501,7 +511,8 @@ class TypeParser
|
||||
$property_branch->children[0],
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
$property_maybe_undefined = $property_branch->possibly_undefined;
|
||||
$property_key = $property_branch->value;
|
||||
@ -558,7 +569,8 @@ class TypeParser
|
||||
$parse_tree->children[0],
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
|
||||
if (!$callable_type instanceof TCallable && !$callable_type instanceof TFn) {
|
||||
@ -573,7 +585,8 @@ class TypeParser
|
||||
$parse_tree->children[1],
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
|
||||
$callable_type->return_type = $return_type instanceof Union ? $return_type : new Union([$return_type]);
|
||||
@ -586,7 +599,7 @@ class TypeParser
|
||||
/**
|
||||
* @return FunctionLikeParameter
|
||||
*/
|
||||
function (ParseTree $child_tree) use ($codebase, $template_type_map) {
|
||||
function (ParseTree $child_tree) use ($codebase, $template_type_map, $type_aliases) {
|
||||
$is_variadic = false;
|
||||
$is_optional = false;
|
||||
|
||||
@ -595,7 +608,8 @@ class TypeParser
|
||||
$child_tree->children[0],
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
$is_variadic = $child_tree->variadic;
|
||||
$is_optional = $child_tree->has_default;
|
||||
@ -604,7 +618,13 @@ class TypeParser
|
||||
$child_tree->value = preg_replace('/(.+)\$.*/', '$1', $child_tree->value);
|
||||
}
|
||||
|
||||
$tree_type = self::getTypeFromTree($child_tree, $codebase, null, $template_type_map);
|
||||
$tree_type = self::getTypeFromTree(
|
||||
$child_tree,
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
}
|
||||
|
||||
$tree_type = $tree_type instanceof Union ? $tree_type : new Union([$tree_type]);
|
||||
@ -636,7 +656,13 @@ class TypeParser
|
||||
}
|
||||
|
||||
if ($parse_tree instanceof ParseTree\EncapsulationTree) {
|
||||
return self::getTypeFromTree($parse_tree->children[0], $codebase, null, $template_type_map);
|
||||
return self::getTypeFromTree(
|
||||
$parse_tree->children[0],
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
}
|
||||
|
||||
if ($parse_tree instanceof ParseTree\NullableTree) {
|
||||
@ -648,7 +674,8 @@ class TypeParser
|
||||
$parse_tree->children[0],
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
|
||||
if ($non_nullable_type instanceof Union) {
|
||||
@ -740,21 +767,24 @@ class TypeParser
|
||||
$parse_tree->condition->children[0],
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
|
||||
$if_type = self::getTypeFromTree(
|
||||
$parse_tree->children[0],
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
|
||||
$else_type = self::getTypeFromTree(
|
||||
$parse_tree->children[1],
|
||||
$codebase,
|
||||
null,
|
||||
$template_type_map
|
||||
$template_type_map,
|
||||
$type_aliases
|
||||
);
|
||||
|
||||
if ($conditional_type instanceof Atomic) {
|
||||
@ -821,7 +851,7 @@ class TypeParser
|
||||
|
||||
$atomic_type_string = TypeTokenizer::fixScalarTerms($parse_tree->value, $php_version);
|
||||
|
||||
$atomic_type = Atomic::create($atomic_type_string, $php_version, $template_type_map);
|
||||
$atomic_type = Atomic::create($atomic_type_string, $php_version, $template_type_map, $type_aliases);
|
||||
|
||||
$atomic_type->offset_start = $parse_tree->offset_start;
|
||||
$atomic_type->offset_end = $parse_tree->offset_end;
|
||||
|
@ -15,6 +15,7 @@ use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
|
||||
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
||||
use Psalm\Internal\Analyzer\TypeAnalyzer;
|
||||
use Psalm\Internal\Type\TemplateResult;
|
||||
use Psalm\Internal\Type\TypeAlias;
|
||||
use Psalm\Issue\InvalidTemplateParam;
|
||||
use Psalm\Issue\MissingTemplateParam;
|
||||
use Psalm\Issue\ReservedWord;
|
||||
@ -60,6 +61,7 @@ use Psalm\Type\Atomic\TString;
|
||||
use Psalm\Type\Atomic\TTemplateParam;
|
||||
use Psalm\Type\Atomic\TTraitString;
|
||||
use Psalm\Type\Atomic\TTrue;
|
||||
use Psalm\Type\Atomic\TTypeAlias;
|
||||
use Psalm\Type\Atomic\TVoid;
|
||||
use function reset;
|
||||
use function strpos;
|
||||
@ -98,13 +100,15 @@ abstract class Atomic implements TypeNode
|
||||
* @param string $value
|
||||
* @param array{int,int}|null $php_version
|
||||
* @param array<string, array<string, array{Union}>> $template_type_map
|
||||
* @param array<string, TypeAlias> $type_aliases
|
||||
*
|
||||
* @return Atomic
|
||||
*/
|
||||
public static function create(
|
||||
$value,
|
||||
array $php_version = null,
|
||||
array $template_type_map = []
|
||||
array $template_type_map = [],
|
||||
array $type_aliases = []
|
||||
) {
|
||||
switch ($value) {
|
||||
case 'int':
|
||||
@ -254,6 +258,16 @@ abstract class Atomic implements TypeNode
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($type_aliases[$value])) {
|
||||
$type_alias = $type_aliases[$value];
|
||||
|
||||
if ($type_alias->declaring_fq_classlike_name && $type_alias->alias_name) {
|
||||
return new TTypeAlias($type_alias->declaring_fq_classlike_name, $type_alias->alias_name);
|
||||
}
|
||||
|
||||
throw new \UnexpectedValueException('This should never happen');
|
||||
}
|
||||
|
||||
return new TNamedObject($value);
|
||||
}
|
||||
|
||||
|
93
src/Psalm/Type/Atomic/TTypeAlias.php
Normal file
93
src/Psalm/Type/Atomic/TTypeAlias.php
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
namespace Psalm\Type\Atomic;
|
||||
|
||||
use Psalm\CodeLocation;
|
||||
use Psalm\StatementsSource;
|
||||
|
||||
class TTypeAlias extends \Psalm\Type\Atomic
|
||||
{
|
||||
/** @var string */
|
||||
public $declaring_fq_classlike_name;
|
||||
|
||||
/** @var string */
|
||||
public $alias_name;
|
||||
|
||||
public function __construct(string $declaring_fq_classlike_name, string $alias_name)
|
||||
{
|
||||
$this->declaring_fq_classlike_name = $declaring_fq_classlike_name;
|
||||
$this->alias_name = $alias_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getKey(bool $include_extra = true)
|
||||
{
|
||||
return 'type-alias(' . $this->declaring_fq_classlike_name . '::' . $this->alias_name . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId(bool $nested = false)
|
||||
{
|
||||
return $this->getKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $namespace
|
||||
* @param array<string> $aliased_classes
|
||||
* @param string|null $this_class
|
||||
* @param int $php_major_version
|
||||
* @param int $php_minor_version
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function toPhpString(
|
||||
$namespace,
|
||||
array $aliased_classes,
|
||||
$this_class,
|
||||
$php_major_version,
|
||||
$php_minor_version
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function canBeFullyExpressedInPhp()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $namespace
|
||||
* @param array<string, string> $aliased_classes
|
||||
* @param string|null $this_class
|
||||
* @param bool $use_phpdoc_format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toNamespacedString(
|
||||
?string $namespace,
|
||||
array $aliased_classes,
|
||||
?string $this_class,
|
||||
bool $use_phpdoc_format
|
||||
) {
|
||||
return $this->getKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAssertionString()
|
||||
{
|
||||
return 'mixed';
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user