mirror of
https://github.com/danog/psalm.git
synced 2024-12-02 09:37:59 +01:00
Support templated @mixin
This commit is contained in:
parent
83fe3a2fd9
commit
d88c31f461
@ -253,6 +253,53 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer
|
|||||||
$statements_analyzer->getFilePath()
|
$statements_analyzer->getFilePath()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!$naive_method_exists
|
||||||
|
&& $class_storage->mixin_param
|
||||||
|
&& $lhs_type_part instanceof Type\Atomic\TGenericObject
|
||||||
|
&& $class_storage->template_types
|
||||||
|
) {
|
||||||
|
$param_position = \array_search(
|
||||||
|
$class_storage->mixin_param,
|
||||||
|
\array_keys($class_storage->template_types)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($param_position !== false
|
||||||
|
&& isset($lhs_type_part->type_params[$param_position])
|
||||||
|
) {
|
||||||
|
if ($lhs_type_part->type_params[$param_position]->isSingle()) {
|
||||||
|
$lhs_type_part_new = array_values(
|
||||||
|
$lhs_type_part->type_params[$param_position]->getAtomicTypes()
|
||||||
|
)[0];
|
||||||
|
|
||||||
|
if ($lhs_type_part_new instanceof Type\Atomic\TNamedObject) {
|
||||||
|
$new_method_id = new MethodIdentifier(
|
||||||
|
$lhs_type_part_new->value,
|
||||||
|
$method_name_lc
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($codebase->methods->methodExists(
|
||||||
|
$new_method_id,
|
||||||
|
$context->calling_method_id,
|
||||||
|
$codebase->collect_locations
|
||||||
|
? new CodeLocation($source, $stmt->name)
|
||||||
|
: null,
|
||||||
|
!$context->collect_initializations
|
||||||
|
&& !$context->collect_mutations
|
||||||
|
? $statements_analyzer
|
||||||
|
: null,
|
||||||
|
$statements_analyzer->getFilePath()
|
||||||
|
)) {
|
||||||
|
$lhs_type_part = $lhs_type_part_new;
|
||||||
|
$class_storage = $codebase->classlike_storage_provider->get($lhs_type_part->value);
|
||||||
|
|
||||||
|
$naive_method_exists = true;
|
||||||
|
$method_id = $new_method_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$naive_method_exists
|
if (!$naive_method_exists
|
||||||
|| !MethodAnalyzer::isMethodVisible(
|
|| !MethodAnalyzer::isMethodVisible(
|
||||||
$method_id,
|
$method_id,
|
||||||
|
@ -1261,10 +1261,7 @@ class ReflectorVisitor extends PhpParser\NodeVisitorAbstract implements PhpParse
|
|||||||
|
|
||||||
if ($docblock_info->mixin) {
|
if ($docblock_info->mixin) {
|
||||||
if (isset($this->class_template_types[$docblock_info->mixin])) {
|
if (isset($this->class_template_types[$docblock_info->mixin])) {
|
||||||
$storage->docblock_issues[] = new InvalidDocblock(
|
$storage->mixin_param = $docblock_info->mixin;
|
||||||
'Templates are not currently supported for @mixin',
|
|
||||||
$name_location ?: $class_location
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
$mixin_fqcln = Type::getFQCLNFromString(
|
$mixin_fqcln = Type::getFQCLNFromString(
|
||||||
$docblock_info->mixin,
|
$docblock_info->mixin,
|
||||||
|
@ -96,6 +96,21 @@ interface Iterator extends Traversable {
|
|||||||
public function rewind();
|
public function rewind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @template TIterator as IteratorAggregate|RecursiveIterator
|
||||||
|
* @mixin TIterator
|
||||||
|
*/
|
||||||
|
class RecursiveIteratorIterator {
|
||||||
|
/**
|
||||||
|
* @param TIterator $iterator
|
||||||
|
* @param int $mode
|
||||||
|
* @param int $flags
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($iterator, $mode = 0, $flags = 0) {}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template-covariant TKey
|
* @template-covariant TKey
|
||||||
* @template-covariant TValue
|
* @template-covariant TValue
|
||||||
|
@ -102,6 +102,11 @@ class ClassLikeStorage
|
|||||||
*/
|
*/
|
||||||
public $mixin_fqcln = null;
|
public $mixin_fqcln = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var null|string
|
||||||
|
*/
|
||||||
|
public $mixin_param = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array<string, bool>
|
* @var array<string, bool>
|
||||||
*/
|
*/
|
||||||
|
@ -95,6 +95,20 @@ class MixinAnnotationTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
class A extends AParent {}'
|
class A extends AParent {}'
|
||||||
],
|
],
|
||||||
|
'implicitMixin' => [
|
||||||
|
'<?php
|
||||||
|
function foo(string $dir) : void {
|
||||||
|
$iterator = new \RecursiveIteratorIterator(
|
||||||
|
new \RecursiveDirectoryIterator($dir)
|
||||||
|
);
|
||||||
|
|
||||||
|
while ($iterator->valid()) {
|
||||||
|
if (!$iterator->isDot() && $iterator->isLink()) {}
|
||||||
|
|
||||||
|
$iterator->next();
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user