mirror of
https://github.com/rectorphp/rector.git
synced 2024-06-01 17:00:51 +00:00
use templates (#5116)
This commit is contained in:
parent
bd62164c85
commit
bc0113dbd7
|
@ -88,7 +88,9 @@ abstract class AbstractPhpDocInfoTest extends AbstractKernelTestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @param class-string $nodeType
|
||||
* @template T as Node
|
||||
* @param class-string<T> $nodeType
|
||||
* @return T
|
||||
*/
|
||||
private function parseFileAndGetFirstNodeOfType(SmartFileInfo $fileInfo, string $nodeType): Node
|
||||
{
|
||||
|
|
|
@ -31,7 +31,7 @@ final class ScopeNestingComparator
|
|||
|
||||
public function isNodeConditionallyScoped(Node $node): bool
|
||||
{
|
||||
$foundParentType = $this->betterNodeFinder->findFirstParentInstanceOf(
|
||||
$foundParentType = $this->betterNodeFinder->findParentTypes(
|
||||
$node,
|
||||
ControlStructure::CONDITIONAL_NODE_SCOPE_TYPES + [FunctionLike::class]
|
||||
);
|
||||
|
@ -45,6 +45,6 @@ final class ScopeNestingComparator
|
|||
|
||||
private function findParentControlStructure(Node $node): ?Node
|
||||
{
|
||||
return $this->betterNodeFinder->findFirstParentInstanceOf($node, ControlStructure::BREAKING_SCOPE_NODE_TYPES);
|
||||
return $this->betterNodeFinder->findParentTypes($node, ControlStructure::BREAKING_SCOPE_NODE_TYPES);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,9 @@ abstract class AbstractNodeTypeResolverTest extends AbstractKernelTestCase
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Node[]
|
||||
* @template T as Node
|
||||
* @param class-string<T> $type
|
||||
* @return T[]
|
||||
*/
|
||||
protected function getNodesForFileOfType(string $file, string $type): array
|
||||
{
|
||||
|
|
|
@ -136,12 +136,12 @@ final class NodesToRemoveCollector implements NodeCollectorInterface
|
|||
return false;
|
||||
}
|
||||
|
||||
$hasArgParent = (bool) $this->betterNodeFinder->findFirstParentInstanceOf($variable, Arg::class);
|
||||
$hasArgParent = (bool) $this->betterNodeFinder->findParentType($variable, Arg::class);
|
||||
if (! $hasArgParent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! (bool) $this->betterNodeFinder->findFirstParentInstanceOf($variable, [StaticCall::class]);
|
||||
return ! (bool) $this->betterNodeFinder->findParentType($variable, StaticCall::class);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -86,10 +86,7 @@ final class ReadWritePropertyAnalyzer
|
|||
|
||||
private function isNotInsideIssetUnset(ArrayDimFetch $arrayDimFetch): bool
|
||||
{
|
||||
return ! (bool) $this->betterNodeFinder->findFirstParentInstanceOf(
|
||||
$arrayDimFetch,
|
||||
[Isset_::class, Unset_::class]
|
||||
);
|
||||
return ! (bool) $this->betterNodeFinder->findParentTypes($arrayDimFetch, [Isset_::class, Unset_::class]);
|
||||
}
|
||||
|
||||
private function unwrapPostPreIncDec(Node $node): Node
|
||||
|
|
|
@ -5,10 +5,12 @@ declare(strict_types=1);
|
|||
namespace Rector\StaticTypeMapper\Naming;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Stmt\ClassLike;
|
||||
use PhpParser\Node\Stmt\Use_;
|
||||
use PhpParser\Node\Stmt\UseUse;
|
||||
use PHPStan\Analyser\NameScope;
|
||||
use PHPStan\Type\Generic\TemplateTypeMap;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
|
||||
use Rector\Core\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
@ -87,16 +89,34 @@ final class NameScopeFactory
|
|||
|
||||
private function templateTemplateTypeMap(Node $node): TemplateTypeMap
|
||||
{
|
||||
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
$nodeTemplateTypes = $this->resolveTemplateTypesFromNode($node);
|
||||
|
||||
$templateTypes = [];
|
||||
if ($phpDocInfo instanceof PhpDocInfo) {
|
||||
foreach ($phpDocInfo->getTemplateTagValueNodes() as $templateTagValueNode) {
|
||||
$phpstanType = $this->staticTypeMapper->mapPHPStanPhpDocTypeToPHPStanType($templateTagValueNode, $node);
|
||||
$templateTypes[$templateTagValueNode->name] = $phpstanType;
|
||||
}
|
||||
$class = $node->getAttribute(AttributeKey::CLASS_NODE);
|
||||
$classTemplateTypes = [];
|
||||
if ($class instanceof ClassLike) {
|
||||
$classTemplateTypes = $this->resolveTemplateTypesFromNode($class);
|
||||
}
|
||||
|
||||
$templateTypes = array_merge($nodeTemplateTypes, $classTemplateTypes);
|
||||
return new TemplateTypeMap($templateTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Type[]
|
||||
*/
|
||||
private function resolveTemplateTypesFromNode(Node $node): array
|
||||
{
|
||||
$phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
|
||||
if (! $phpDocInfo instanceof PhpDocInfo) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$templateTypes = [];
|
||||
foreach ($phpDocInfo->getTemplateTagValueNodes() as $templateTagValueNode) {
|
||||
$phpstanType = $this->staticTypeMapper->mapPHPStanPhpDocTypeToPHPStanType($templateTagValueNode, $node);
|
||||
$templateTypes[$templateTagValueNode->name] = $phpstanType;
|
||||
}
|
||||
|
||||
return $templateTypes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,8 @@ final class TestingParser
|
|||
}
|
||||
|
||||
/**
|
||||
* @template T of Node
|
||||
* @param class-string<T> $nodeClass
|
||||
* @return Node[]
|
||||
*/
|
||||
public function parseFileToDecoratedNodesAndFindNodesByType(string $file, string $nodeClass): array
|
||||
|
|
13
phpstan.neon
13
phpstan.neon
|
@ -596,3 +596,16 @@ parameters:
|
|||
- '#File "ClassInCorrectNamespaceRector\.php" should have prefix "Skip" prefix#'
|
||||
- '#File "HaveSameStarts\.php" should have prefix "Skip" prefix#'
|
||||
- '#File "AbstractSkip\.php" should have prefix "Skip" prefix#'
|
||||
|
||||
# generics nullable bugs
|
||||
- '#Method (.*?) should return T of PhpParser\\Node\|null but returns PhpParser\\Node\|null#'
|
||||
- '#Method (.*?) should return T of PhpParser\\Node\|null but returns PhpParser\\Node#'
|
||||
- '#Method (.*?) should return (.*?)\|null but returns PhpParser\\Node\|null#'
|
||||
- '#Method (.*?) should return array<T of PhpParser\\Node\> but returns array<PhpParser\\Node\>#'
|
||||
- '#Method (.*?) should return array<T of PhpParser\\Node\> but returns array<T of PhpParser\\Node\>#'
|
||||
|
||||
- '#Parameter \#1 \$node of method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder<PhpParser\\Node\>\:\:findFirstAncestorInstanceOf\(\) expects PhpParser\\Node, PhpParser\\Node\\Expr\\Variable\|null given#'
|
||||
- '#Parameter \#1 \$nodes of method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder<PhpParser\\Node\>\:\:findFirst\(\) expects array<PhpParser\\Node\>\|PhpParser\\Node, array<PhpParser\\Node\\Stmt\>\|null given#'
|
||||
- '#Parameter \#2 \$type of method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder<T of PhpParser\\Node\>\:\:findInstanceOfName\(\) expects class\-string<T of PhpParser\\Node\>, string given#'
|
||||
- '#Method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder\:\:findVariableOfName\(\) should return PhpParser\\Node\\Expr\\Variable\|null but returns T of PhpParser\\Node\|null#'
|
||||
- '#Method Rector\\BetterPhpDocParser\\Tests\\PhpDocParser\\AbstractPhpDocInfoTest\:\:parseFileAndGetFirstNodeOfType\(\) should return T of PhpParser\\Node but returns PhpParser\\Node\|null#'
|
||||
|
|
|
@ -204,7 +204,7 @@ CODE_SAMPLE
|
|||
|
||||
private function isInsideLoopStmts(Node $node): bool
|
||||
{
|
||||
$loopNode = $this->betterNodeFinder->findFirstParentInstanceOf(
|
||||
$loopNode = $this->betterNodeFinder->findParentTypes(
|
||||
$node,
|
||||
[For_::class, While_::class, Foreach_::class, Do_::class]
|
||||
);
|
||||
|
|
|
@ -199,7 +199,7 @@ final class LocalPropertyAnalyzer
|
|||
*/
|
||||
private function isPartOfClosureBind(PropertyFetch $propertyFetch): bool
|
||||
{
|
||||
$parentStaticCall = $this->betterNodeFinder->findFirstParentInstanceOf($propertyFetch, StaticCall::class);
|
||||
$parentStaticCall = $this->betterNodeFinder->findParentType($propertyFetch, StaticCall::class);
|
||||
if (! $parentStaticCall instanceof StaticCall) {
|
||||
return false;
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ final class LocalPropertyAnalyzer
|
|||
|
||||
private function isPartOfClosureBindTo(PropertyFetch $propertyFetch): bool
|
||||
{
|
||||
$parentMethodCall = $this->betterNodeFinder->findFirstParentInstanceOf($propertyFetch, MethodCall::class);
|
||||
$parentMethodCall = $this->betterNodeFinder->findParentType($propertyFetch, MethodCall::class);
|
||||
if (! $parentMethodCall instanceof MethodCall) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ CODE_SAMPLE
|
|||
|
||||
private function isInsideProperty(Array_ $array): bool
|
||||
{
|
||||
$parentProperty = $this->betterNodeFinder->findFirstParentInstanceOf($array, [Property::class]);
|
||||
$parentProperty = $this->betterNodeFinder->findParentType($array, Property::class);
|
||||
|
||||
return $parentProperty !== null;
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ CODE_SAMPLE
|
|||
|
||||
private function shouldSkipAsPartOfNestedForeach(Foreach_ $foreach): bool
|
||||
{
|
||||
$foreachParent = $this->betterNodeFinder->findFirstParentInstanceOf($foreach, Foreach_::class);
|
||||
$foreachParent = $this->betterNodeFinder->findParentType($foreach, Foreach_::class);
|
||||
return $foreachParent !== null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -245,7 +245,7 @@ CODE_SAMPLE
|
|||
|
||||
private function isIfInLoop(If_ $if): bool
|
||||
{
|
||||
$parentLoop = $this->betterNodeFinder->findFirstParentInstanceOf($if, self::LOOP_TYPES);
|
||||
$parentLoop = $this->betterNodeFinder->findParentTypes($if, self::LOOP_TYPES);
|
||||
|
||||
return $parentLoop !== null;
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ CODE_SAMPLE
|
|||
private function isFunctionLikeReturnsVoid(If_ $if): bool
|
||||
{
|
||||
/** @var FunctionLike|null $functionLike */
|
||||
$functionLike = $this->betterNodeFinder->findFirstParentInstanceOf($if, FunctionLike::class);
|
||||
$functionLike = $this->betterNodeFinder->findParentType($if, FunctionLike::class);
|
||||
if ($functionLike === null) {
|
||||
return true;
|
||||
}
|
||||
|
@ -298,10 +298,7 @@ CODE_SAMPLE
|
|||
if (! $this->isIfInLoop($if)) {
|
||||
return false;
|
||||
}
|
||||
return (bool) $this->betterNodeFinder->findFirstParentInstanceOf(
|
||||
$if,
|
||||
[If_::class, Else_::class, ElseIf_::class]
|
||||
);
|
||||
return (bool) $this->betterNodeFinder->findParentTypes($if, [If_::class, Else_::class, ElseIf_::class]);
|
||||
}
|
||||
|
||||
private function isLastIfOrBeforeLastReturn(If_ $if): bool
|
||||
|
|
|
@ -131,7 +131,7 @@ CODE_SAMPLE
|
|||
private function isFoundInParentNode(Variable $variable): bool
|
||||
{
|
||||
/** @var ClassMethod|Function_|null $classMethodOrFunction */
|
||||
$classMethodOrFunction = $this->betterNodeFinder->findFirstParentInstanceOf(
|
||||
$classMethodOrFunction = $this->betterNodeFinder->findParentTypes(
|
||||
$variable,
|
||||
[ClassMethod::class, Function_::class]
|
||||
);
|
||||
|
|
|
@ -42,7 +42,7 @@ final class ParamRenameFactory
|
|||
}
|
||||
|
||||
/** @var ClassMethod|Function_|Closure|ArrowFunction|null $functionLike */
|
||||
$functionLike = $this->betterNodeFinder->findFirstParentInstanceOf($param, FunctionLike::class);
|
||||
$functionLike = $this->betterNodeFinder->findParentType($param, FunctionLike::class);
|
||||
if ($functionLike === null) {
|
||||
throw new ShouldNotHappenException("There shouldn't be a param outside of FunctionLike");
|
||||
}
|
||||
|
|
|
@ -82,12 +82,11 @@ CODE_SAMPLE
|
|||
return null;
|
||||
}
|
||||
|
||||
if ($classLike->extends === null) {
|
||||
$this->makePrivate($node);
|
||||
return $node;
|
||||
if ($this->classMethodVisibilityGuard->isClassMethodVisibilityGuardedByParent($node, $classLike)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->classMethodVisibilityGuard->isClassMethodVisibilityGuardedByParent($node, $classLike)) {
|
||||
if ($this->classMethodVisibilityGuard->isClassMethodVisibilityGuardedByTrait($node, $classLike)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,16 +26,33 @@ final class ClassMethodVisibilityGuard
|
|||
return false;
|
||||
}
|
||||
|
||||
$methodName = $this->nodeNameResolver->getName($classMethod);
|
||||
$parentClasses = $this->getParentClasses($class);
|
||||
$propertyName = $this->nodeNameResolver->getName($classMethod);
|
||||
return $this->methodExistsInClasses($parentClasses, $methodName);
|
||||
}
|
||||
|
||||
foreach ($parentClasses as $parentClass) {
|
||||
if (method_exists($parentClass, $propertyName)) {
|
||||
return true;
|
||||
}
|
||||
public function isClassMethodVisibilityGuardedByTrait(ClassMethod $classMethod, Class_ $class): bool
|
||||
{
|
||||
$traits = $this->getParentTraits($class);
|
||||
$methodName = $this->nodeNameResolver->getName($classMethod);
|
||||
|
||||
return $this->methodExistsInClasses($traits, $methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getParentTraits(Class_ $class): array
|
||||
{
|
||||
/** @var string $className */
|
||||
$className = $this->nodeNameResolver->getName($class);
|
||||
|
||||
$traits = class_uses($className);
|
||||
if ($traits === false) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return false;
|
||||
return $traits;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,4 +70,18 @@ final class ClassMethodVisibilityGuard
|
|||
|
||||
return $classParents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $classes
|
||||
*/
|
||||
private function methodExistsInClasses(array $classes, string $method): bool
|
||||
{
|
||||
foreach ($classes as $class) {
|
||||
if (method_exists($class, $method)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Fixture;
|
||||
|
||||
use Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Source\MethodSomeTrait;
|
||||
|
||||
final class SkipTraitCalled
|
||||
{
|
||||
use MethodSomeTrait;
|
||||
|
||||
protected function configureRoutes()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Privatization\Tests\Rector\ClassMethod\PrivatizeFinalClassMethodRector\Source;
|
||||
|
||||
trait MethodSomeTrait
|
||||
{
|
||||
abstract protected function configureRoutes();
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->configureRoutes();
|
||||
}
|
||||
}
|
|
@ -91,12 +91,12 @@ final class BundleClassResolver
|
|||
|
||||
$this->addFullyQualifiedNamesToNodes($nodes);
|
||||
|
||||
$class = $this->betterNodeFinder->findFirstNonAnonymousClass($nodes);
|
||||
if ($class === null) {
|
||||
$classLike = $this->betterNodeFinder->findFirstNonAnonymousClass($nodes);
|
||||
if ($classLike === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->nodeNameResolver->getName($class);
|
||||
return $this->nodeNameResolver->getName($classLike);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\AddArrayReturnDocTypeRector\Fixture;
|
||||
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
use PhpParser\NodeFinder;
|
||||
|
||||
/**
|
||||
* @template T as Node
|
||||
*/
|
||||
final class SkipReturnTypeTemplate
|
||||
{
|
||||
/**
|
||||
* @var NodeFinder
|
||||
*/
|
||||
private $nodeFinder;
|
||||
|
||||
public function __construct(NodeFinder $nodeFinder)
|
||||
{
|
||||
$this->nodeFinder = $nodeFinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return T[]
|
||||
*/
|
||||
public function isValidDataProvider($nodes): array
|
||||
{
|
||||
return $this->nodeFinder->findInstanceOf($nodes, String_::class);
|
||||
}
|
||||
}
|
|
@ -42,7 +42,7 @@ final class ContextAnalyzer
|
|||
{
|
||||
$stopNodes = array_merge(self::LOOP_NODES, self::BREAK_NODES);
|
||||
|
||||
$firstParent = $this->betterNodeFinder->findFirstParentInstanceOf($node, $stopNodes);
|
||||
$firstParent = $this->betterNodeFinder->findParentTypes($node, $stopNodes);
|
||||
if ($firstParent === null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ final class ContextAnalyzer
|
|||
{
|
||||
$breakNodes = array_merge([If_::class], self::BREAK_NODES);
|
||||
|
||||
$previousNode = $this->betterNodeFinder->findFirstParentInstanceOf($node, $breakNodes);
|
||||
$previousNode = $this->betterNodeFinder->findParentTypes($node, $breakNodes);
|
||||
|
||||
if ($previousNode === null) {
|
||||
return false;
|
||||
|
|
|
@ -19,6 +19,7 @@ use Rector\NodeTypeResolver\Node\AttributeKey;
|
|||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
* @template T of Node
|
||||
* @see \Rector\Core\Tests\PhpParser\Node\BetterNodeFinder\BetterNodeFinderTest
|
||||
*/
|
||||
final class BetterNodeFinder
|
||||
|
@ -49,32 +50,63 @@ final class BetterNodeFinder
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string|string[] $type
|
||||
* @param class-string<T> $type
|
||||
* @return T|null
|
||||
*/
|
||||
public function findFirstParentInstanceOf(Node $node, $type): ?Node
|
||||
public function findParentType(Node $node, string $type): ?Node
|
||||
{
|
||||
$types = is_array($type) ? $type : [$type];
|
||||
Assert::allIsAOf($types, Node::class);
|
||||
Assert::isAOf($type, Node::class);
|
||||
|
||||
/** @var Node|null $parentNode */
|
||||
$parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parentNode === null) {
|
||||
/** @var Node|null $parent */
|
||||
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parent === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
do {
|
||||
if ($this->isTypes($parentNode, $types)) {
|
||||
return $parentNode;
|
||||
if (is_a($parent, $type, true)) {
|
||||
return $parent;
|
||||
}
|
||||
|
||||
if ($parentNode === null) {
|
||||
if ($parent === null) {
|
||||
return null;
|
||||
}
|
||||
} while ($parentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE));
|
||||
} while ($parent = $parent->getAttribute(AttributeKey::PARENT_NODE));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<T>[] $types
|
||||
* @return T|null
|
||||
*/
|
||||
public function findParentTypes(Node $node, array $types): ?Node
|
||||
{
|
||||
Assert::allIsAOf($types, Node::class);
|
||||
|
||||
/** @var Node|null $parent */
|
||||
$parent = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if ($parent === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
do {
|
||||
if ($this->isTypes($parent, $types)) {
|
||||
return $parent;
|
||||
}
|
||||
|
||||
if ($parent === null) {
|
||||
return null;
|
||||
}
|
||||
} while ($parent = $parent->getAttribute(AttributeKey::PARENT_NODE));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<T> $type
|
||||
* @return T|null
|
||||
*/
|
||||
public function findFirstAncestorInstanceOf(Node $node, string $type): ?Node
|
||||
{
|
||||
$currentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
|
||||
|
@ -90,7 +122,8 @@ final class BetterNodeFinder
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string[] $types
|
||||
* @param array<class-string<T>> $types
|
||||
* @return T|null
|
||||
*/
|
||||
public function findFirstAncestorInstancesOf(Node $node, array $types): ?Node
|
||||
{
|
||||
|
@ -109,8 +142,9 @@ final class BetterNodeFinder
|
|||
}
|
||||
|
||||
/**
|
||||
* @param class-string<T> $type
|
||||
* @param Node|Node[]|Stmt[] $nodes
|
||||
* @return Node[]
|
||||
* @return T[]
|
||||
*/
|
||||
public function findInstanceOf($nodes, string $type): array
|
||||
{
|
||||
|
@ -120,7 +154,9 @@ final class BetterNodeFinder
|
|||
}
|
||||
|
||||
/**
|
||||
* @param class-string<T> $type
|
||||
* @param Node|Node[] $nodes
|
||||
* @return T|null
|
||||
*/
|
||||
public function findFirstInstanceOf($nodes, string $type): ?Node
|
||||
{
|
||||
|
@ -130,6 +166,7 @@ final class BetterNodeFinder
|
|||
}
|
||||
|
||||
/**
|
||||
* @param class-string<T> $type
|
||||
* @param Node|Node[] $nodes
|
||||
*/
|
||||
public function hasInstanceOfName($nodes, string $type, string $name): bool
|
||||
|
@ -149,6 +186,7 @@ final class BetterNodeFinder
|
|||
|
||||
/**
|
||||
* @param Node|Node[] $nodes
|
||||
* @return Variable|null
|
||||
*/
|
||||
public function findVariableOfName($nodes, string $name): ?Node
|
||||
{
|
||||
|
@ -157,7 +195,7 @@ final class BetterNodeFinder
|
|||
|
||||
/**
|
||||
* @param Node|Node[] $nodes
|
||||
* @param class-string[] $types
|
||||
* @param class-string<T>[] $types
|
||||
*/
|
||||
public function hasInstancesOf($nodes, array $types): bool
|
||||
{
|
||||
|
@ -177,7 +215,9 @@ final class BetterNodeFinder
|
|||
}
|
||||
|
||||
/**
|
||||
* @param class-string<T> $type
|
||||
* @param Node|Node[] $nodes
|
||||
* @return T|null
|
||||
*/
|
||||
public function findLastInstanceOf($nodes, string $type): ?Node
|
||||
{
|
||||
|
@ -188,7 +228,8 @@ final class BetterNodeFinder
|
|||
return null;
|
||||
}
|
||||
|
||||
return array_pop($foundInstances);
|
||||
$lastItemKey = array_key_last($foundInstances);
|
||||
return $foundInstances[$lastItemKey];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -219,6 +260,7 @@ final class BetterNodeFinder
|
|||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
* @return ClassLike|null
|
||||
*/
|
||||
public function findFirstNonAnonymousClass(array $nodes): ?Node
|
||||
{
|
||||
|
@ -240,6 +282,9 @@ final class BetterNodeFinder
|
|||
return $this->nodeFinder->findFirst($nodes, $filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Assign|null
|
||||
*/
|
||||
public function findPreviousAssignToExpr(Expr $expr): ?Node
|
||||
{
|
||||
return $this->findFirstPrevious($expr, function (Node $node) use ($expr): bool {
|
||||
|
@ -279,7 +324,8 @@ final class BetterNodeFinder
|
|||
}
|
||||
|
||||
/**
|
||||
* @param class-string[] $types
|
||||
* @param class-string<T>[] $types
|
||||
* @return T|null
|
||||
*/
|
||||
public function findFirstPreviousOfTypes(Node $mainNode, array $types): ?Node
|
||||
{
|
||||
|
@ -314,17 +360,20 @@ final class BetterNodeFinder
|
|||
|
||||
/**
|
||||
* @param Node|Node[] $nodes
|
||||
* @param class-string<T> $type
|
||||
* @return T|null
|
||||
*/
|
||||
private function findInstanceOfName($nodes, string $type, string $name): ?Node
|
||||
{
|
||||
Assert::isAOf($type, Node::class);
|
||||
|
||||
$foundInstances = $this->nodeFinder->findInstanceOf($nodes, $type);
|
||||
|
||||
foreach ($foundInstances as $foundInstance) {
|
||||
if ($this->nodeNameResolver->isName($foundInstance, $name)) {
|
||||
return $foundInstance;
|
||||
if (! $this->nodeNameResolver->isName($foundInstance, $name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $foundInstance;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
Loading…
Reference in New Issue
Block a user