mirror of
https://github.com/rectorphp/rector.git
synced 2025-02-24 11:44:14 +01:00
Merge pull request #2768 from rectorphp/node-type-resolver
NodeTypeResolver improvements
This commit is contained in:
commit
967e7768cb
@ -9,6 +9,7 @@
|
||||
"symfony/process": "^4.4|^5.0",
|
||||
"symfony/filesystem": "^4.4|^5.0",
|
||||
"symfony/finder": "^4.4|^5.0",
|
||||
"symplify/package-builder": "^7.2",
|
||||
"nette/utils": "^3.0"
|
||||
},
|
||||
"autoload": {
|
||||
|
@ -6,11 +6,15 @@ namespace Rector\Compiler\Console;
|
||||
|
||||
use Nette\Utils\FileSystem as NetteFileSystem;
|
||||
use Nette\Utils\Json;
|
||||
use Rector\Console\Style\SymfonyStyleFactory;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symplify\PackageBuilder\Console\ShellCode;
|
||||
use Symplify\PackageBuilder\Reflection\PrivatesCaller;
|
||||
|
||||
/**
|
||||
* Inspired by @see https://github.com/phpstan/phpstan-src/blob/f939d23155627b5c2ec6eef36d976dddea22c0c5/compiler/src/Console/CompileCommand.php
|
||||
@ -37,12 +41,20 @@ final class CompileCommand extends Command
|
||||
*/
|
||||
private $originalComposerJsonFileContent;
|
||||
|
||||
/**
|
||||
* @var SymfonyStyle
|
||||
*/
|
||||
private $symfonyStyle;
|
||||
|
||||
public function __construct(string $dataDir, string $buildDir)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->filesystem = new Filesystem();
|
||||
$this->dataDir = $dataDir;
|
||||
$this->buildDir = $buildDir;
|
||||
|
||||
$symfonyStyleFactory = new SymfonyStyleFactory(new PrivatesCaller());
|
||||
$this->symfonyStyle = $symfonyStyleFactory->create();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
@ -55,6 +67,8 @@ final class CompileCommand extends Command
|
||||
{
|
||||
$composerJsonFile = $this->buildDir . '/composer.json';
|
||||
|
||||
$this->symfonyStyle->note('Loading ' . $composerJsonFile);
|
||||
|
||||
$this->fixComposerJson($composerJsonFile);
|
||||
|
||||
// @see https://github.com/dotherightthing/wpdtrt-plugin-boilerplate/issues/52
|
||||
@ -79,7 +93,7 @@ final class CompileCommand extends Command
|
||||
|
||||
$this->restoreComposerJson($composerJsonFile);
|
||||
|
||||
return 0;
|
||||
return ShellCode::SUCCESS;
|
||||
}
|
||||
|
||||
private function fixComposerJson(string $composerJsonFile): void
|
||||
|
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTypeResolver\Contract\Metadata;
|
||||
|
||||
use PhpParser\Node;
|
||||
|
||||
interface NodeDecoratorInterface
|
||||
{
|
||||
public function reset(): void;
|
||||
|
||||
public function decorateNode(Node $node): void;
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\NodeTypeResolver\NodeTypeCorrector;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PHPStan\Type\ArrayType;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
use Rector\PhpParser\Printer\BetterStandardPrinter;
|
||||
|
||||
final class PregMatchTypeCorrector
|
||||
{
|
||||
/**
|
||||
* @var BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
|
||||
/**
|
||||
* @var NameResolver
|
||||
*/
|
||||
private $nameResolver;
|
||||
|
||||
/**
|
||||
* @var BetterStandardPrinter
|
||||
*/
|
||||
private $betterStandardPrinter;
|
||||
|
||||
public function __construct(
|
||||
BetterNodeFinder $betterNodeFinder,
|
||||
NameResolver $nameResolver,
|
||||
BetterStandardPrinter $betterStandardPrinter
|
||||
) {
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
$this->nameResolver = $nameResolver;
|
||||
$this->betterStandardPrinter = $betterStandardPrinter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Special case for "preg_match(), preg_match_all()" - with 3rd argument
|
||||
* @covers https://github.com/rectorphp/rector/issues/786
|
||||
*/
|
||||
public function correct(Node $node, Type $originalType): Type
|
||||
{
|
||||
if (! $node instanceof Variable) {
|
||||
return $originalType;
|
||||
}
|
||||
|
||||
if ($originalType instanceof ArrayType) {
|
||||
return $originalType;
|
||||
}
|
||||
|
||||
foreach ($this->getVariableUsages($node) as $usage) {
|
||||
$possiblyArg = $usage->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if (! $possiblyArg instanceof Arg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$funcCallNode = $possiblyArg->getAttribute(AttributeKey::PARENT_NODE);
|
||||
|
||||
if (! $funcCallNode instanceof FuncCall) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->nameResolver->isNames($funcCallNode, ['preg_match', 'preg_match_all'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! isset($funcCallNode->args[2])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// are the same variables
|
||||
if (! $this->betterStandardPrinter->areNodesEqual($funcCallNode->args[2]->value, $node)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return new ArrayType(new MixedType(), new MixedType());
|
||||
}
|
||||
|
||||
return $originalType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Node[]
|
||||
*/
|
||||
private function getVariableUsages(Variable $variable): array
|
||||
{
|
||||
$scope = $this->getScopeNode($variable);
|
||||
|
||||
if ($scope === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->betterNodeFinder->find((array) $scope->stmts, function (Node $node) use ($variable): bool {
|
||||
return $node instanceof Variable && $node->name === $variable->name;
|
||||
});
|
||||
}
|
||||
|
||||
private function getScopeNode(Node $node): ?Node
|
||||
{
|
||||
return $node->getAttribute(AttributeKey::METHOD_NODE)
|
||||
?? $node->getAttribute(AttributeKey::FUNCTION_NODE)
|
||||
?? $node->getAttribute(AttributeKey::NAMESPACE_NODE);
|
||||
}
|
||||
}
|
@ -10,7 +10,6 @@ use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\New_;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
@ -27,7 +26,6 @@ use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Nop;
|
||||
use PhpParser\Node\Stmt\PropertyProperty;
|
||||
use PhpParser\Node\Stmt\Trait_;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
@ -56,12 +54,10 @@ use Rector\Exception\ShouldNotHappenException;
|
||||
use Rector\NodeContainer\ParsedNodesByType;
|
||||
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\NodeTypeCorrector\PregMatchTypeCorrector;
|
||||
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
|
||||
use Rector\NodeTypeResolver\Reflection\ClassReflectionTypesResolver;
|
||||
use Rector\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
use Rector\PhpParser\NodeTraverser\CallableNodeTraverser;
|
||||
use Rector\PhpParser\Printer\BetterStandardPrinter;
|
||||
use Rector\TypeDeclaration\PHPStan\Type\ObjectTypeSpecifier;
|
||||
use ReflectionProperty;
|
||||
use Symfony\Component\Finder\SplFileInfo;
|
||||
@ -78,16 +74,6 @@ final class NodeTypeResolver
|
||||
*/
|
||||
private $nameResolver;
|
||||
|
||||
/**
|
||||
* @var BetterStandardPrinter
|
||||
*/
|
||||
private $betterStandardPrinter;
|
||||
|
||||
/**
|
||||
* @var CallableNodeTraverser
|
||||
*/
|
||||
private $callableNodeTraverser;
|
||||
|
||||
/**
|
||||
* @var ClassReflectionTypesResolver
|
||||
*/
|
||||
@ -108,11 +94,6 @@ final class NodeTypeResolver
|
||||
*/
|
||||
private $objectTypeSpecifier;
|
||||
|
||||
/**
|
||||
* @var BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
|
||||
/**
|
||||
* @var ParsedNodesByType
|
||||
*/
|
||||
@ -128,39 +109,40 @@ final class NodeTypeResolver
|
||||
*/
|
||||
private $staticTypeMapper;
|
||||
|
||||
/**
|
||||
* @var PregMatchTypeCorrector
|
||||
*/
|
||||
private $pregMatchTypeCorrector;
|
||||
|
||||
/**
|
||||
* @param PerNodeTypeResolverInterface[] $perNodeTypeResolvers
|
||||
*/
|
||||
public function __construct(
|
||||
BetterStandardPrinter $betterStandardPrinter,
|
||||
BetterPhpDocParser $betterPhpDocParser,
|
||||
NameResolver $nameResolver,
|
||||
ParsedNodesByType $parsedNodesByType,
|
||||
CallableNodeTraverser $callableNodeTraverser,
|
||||
ClassReflectionTypesResolver $classReflectionTypesResolver,
|
||||
ReflectionProvider $reflectionProvider,
|
||||
TypeFactory $typeFactory,
|
||||
StaticTypeMapper $staticTypeMapper,
|
||||
ObjectTypeSpecifier $objectTypeSpecifier,
|
||||
BetterNodeFinder $betterNodeFinder,
|
||||
PregMatchTypeCorrector $pregMatchTypeCorrector,
|
||||
array $perNodeTypeResolvers
|
||||
) {
|
||||
$this->betterStandardPrinter = $betterStandardPrinter;
|
||||
$this->nameResolver = $nameResolver;
|
||||
|
||||
foreach ($perNodeTypeResolvers as $perNodeTypeResolver) {
|
||||
$this->addPerNodeTypeResolver($perNodeTypeResolver);
|
||||
}
|
||||
|
||||
$this->callableNodeTraverser = $callableNodeTraverser;
|
||||
$this->classReflectionTypesResolver = $classReflectionTypesResolver;
|
||||
$this->reflectionProvider = $reflectionProvider;
|
||||
$this->typeFactory = $typeFactory;
|
||||
$this->objectTypeSpecifier = $objectTypeSpecifier;
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
$this->parsedNodesByType = $parsedNodesByType;
|
||||
$this->betterPhpDocParser = $betterPhpDocParser;
|
||||
$this->staticTypeMapper = $staticTypeMapper;
|
||||
$this->pregMatchTypeCorrector = $pregMatchTypeCorrector;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -260,7 +242,7 @@ final class NodeTypeResolver
|
||||
{
|
||||
$nodeType = $this->getStaticType($node);
|
||||
|
||||
$nodeType = $this->correctPregMatchType($node, $nodeType);
|
||||
$nodeType = $this->pregMatchTypeCorrector->correct($node, $nodeType);
|
||||
if ($nodeType instanceof ObjectType) {
|
||||
if (is_a($nodeType->getClassName(), Countable::class, true)) {
|
||||
return true;
|
||||
@ -270,6 +252,7 @@ final class NodeTypeResolver
|
||||
if (is_a($nodeType->getClassName(), 'SimpleXMLElement', true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return is_a($nodeType->getClassName(), 'ResourceBundle', true);
|
||||
}
|
||||
|
||||
@ -280,7 +263,7 @@ final class NodeTypeResolver
|
||||
{
|
||||
$nodeStaticType = $this->getStaticType($node);
|
||||
|
||||
$nodeStaticType = $this->correctPregMatchType($node, $nodeStaticType);
|
||||
$nodeStaticType = $this->pregMatchTypeCorrector->correct($node, $nodeStaticType);
|
||||
if ($this->isIntersectionArrayType($nodeStaticType)) {
|
||||
return true;
|
||||
}
|
||||
@ -312,10 +295,7 @@ final class NodeTypeResolver
|
||||
}
|
||||
|
||||
if ($node instanceof Param) {
|
||||
$paramStaticType = $this->resolveParamStaticType($node);
|
||||
if ($paramStaticType !== null) {
|
||||
return $paramStaticType;
|
||||
}
|
||||
return $this->resolve($node);
|
||||
}
|
||||
|
||||
/** @var Scope|null $nodeScope */
|
||||
@ -553,71 +533,6 @@ final class NodeTypeResolver
|
||||
return $this->typeFactory->createObjectTypeOrUnionType($allTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Special case for "preg_match(), preg_match_all()" - with 3rd argument
|
||||
* @covers https://github.com/rectorphp/rector/issues/786
|
||||
*/
|
||||
private function correctPregMatchType(Node $node, Type $originalType): Type
|
||||
{
|
||||
if (! $node instanceof Variable) {
|
||||
return $originalType;
|
||||
}
|
||||
|
||||
if ($originalType instanceof ArrayType) {
|
||||
return $originalType;
|
||||
}
|
||||
|
||||
foreach ($this->getVariableUsages($node) as $usage) {
|
||||
$possiblyArg = $usage->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if (! $possiblyArg instanceof Arg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$funcCallNode = $possiblyArg->getAttribute(AttributeKey::PARENT_NODE);
|
||||
if (! $funcCallNode instanceof FuncCall) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $this->nameResolver->isNames($funcCallNode, ['preg_match', 'preg_match_all'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! isset($funcCallNode->args[2])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// are the same variables
|
||||
if (! $this->betterStandardPrinter->areNodesEqual($funcCallNode->args[2]->value, $node)) {
|
||||
continue;
|
||||
}
|
||||
return new ArrayType(new MixedType(), new MixedType());
|
||||
}
|
||||
return $originalType;
|
||||
}
|
||||
|
||||
private function getScopeNode(Node $node): ?Node
|
||||
{
|
||||
return $node->getAttribute(AttributeKey::METHOD_NODE)
|
||||
?? $node->getAttribute(AttributeKey::FUNCTION_NODE)
|
||||
?? $node->getAttribute(AttributeKey::NAMESPACE_NODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Node[]
|
||||
*/
|
||||
private function getVariableUsages(Variable $variable): array
|
||||
{
|
||||
$scope = $this->getScopeNode($variable);
|
||||
|
||||
if ($scope === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->betterNodeFinder->find((array) $scope->stmts, function (Node $node) use ($variable): bool {
|
||||
return $node instanceof Variable && $node->name === $variable->name;
|
||||
});
|
||||
}
|
||||
|
||||
private function isIntersectionArrayType(Type $nodeType): bool
|
||||
{
|
||||
if (! $nodeType instanceof IntersectionType) {
|
||||
@ -670,37 +585,6 @@ final class NodeTypeResolver
|
||||
return $propertyPropertyNode->default instanceof Array_;
|
||||
}
|
||||
|
||||
private function resolveParamStaticType(Param $param): Type
|
||||
{
|
||||
$classMethod = $param->getAttribute(AttributeKey::METHOD_NODE);
|
||||
if ($classMethod === null) {
|
||||
return new MixedType();
|
||||
}
|
||||
|
||||
/** @var string $paramName */
|
||||
$paramName = $this->nameResolver->getName($param);
|
||||
$paramStaticType = new MixedType();
|
||||
|
||||
// special case for param inside method/function
|
||||
$this->callableNodeTraverser->traverseNodesWithCallable(
|
||||
(array) $classMethod->stmts,
|
||||
function (Node $node) use ($paramName, &$paramStaticType): ?int {
|
||||
if (! $node instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->nameResolver->isName($node, $paramName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$paramStaticType = $this->getStaticType($node);
|
||||
return NodeTraverser::STOP_TRAVERSAL;
|
||||
}
|
||||
);
|
||||
|
||||
return $paramStaticType;
|
||||
}
|
||||
|
||||
private function isAnonymousClass(Node $node): bool
|
||||
{
|
||||
if (! $node instanceof Class_) {
|
||||
|
@ -5,14 +5,20 @@ declare(strict_types=1);
|
||||
namespace Rector\NodeTypeResolver\PerNodeTypeResolver;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Param;
|
||||
use PhpParser\NodeTraverser;
|
||||
use PHPStan\Type\MixedType;
|
||||
use PHPStan\Type\ObjectType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\NodeTypeResolver\Contract\PerNodeTypeResolver\PerNodeTypeResolverInterface;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
use Rector\NodeTypeResolver\NodeTypeResolver;
|
||||
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator;
|
||||
use Rector\PhpParser\Node\Resolver\NameResolver;
|
||||
use Rector\PhpParser\NodeTraverser\CallableNodeTraverser;
|
||||
|
||||
/**
|
||||
* @see \Rector\NodeTypeResolver\Tests\PerNodeTypeResolver\ParamTypeResolver\ParamTypeResolverTest
|
||||
@ -29,10 +35,32 @@ final class ParamTypeResolver implements PerNodeTypeResolverInterface
|
||||
*/
|
||||
private $docBlockManipulator;
|
||||
|
||||
public function __construct(NameResolver $nameResolver, DocBlockManipulator $docBlockManipulator)
|
||||
{
|
||||
/**
|
||||
* @var CallableNodeTraverser
|
||||
*/
|
||||
private $callableNodeTraverser;
|
||||
|
||||
/**
|
||||
* @var NodeTypeResolver
|
||||
*/
|
||||
private $nodeTypeResolver;
|
||||
|
||||
public function __construct(
|
||||
NameResolver $nameResolver,
|
||||
DocBlockManipulator $docBlockManipulator,
|
||||
CallableNodeTraverser $callableNodeTraverser
|
||||
) {
|
||||
$this->nameResolver = $nameResolver;
|
||||
$this->docBlockManipulator = $docBlockManipulator;
|
||||
$this->callableNodeTraverser = $callableNodeTraverser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @required
|
||||
*/
|
||||
public function autowirePropertyTypeResolver(NodeTypeResolver $nodeTypeResolver): void
|
||||
{
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,29 +72,76 @@ final class ParamTypeResolver implements PerNodeTypeResolverInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Param $paramNode
|
||||
* @param Param $node
|
||||
*/
|
||||
public function resolve(Node $paramNode): Type
|
||||
public function resolve(Node $node): Type
|
||||
{
|
||||
if ($paramNode->type !== null) {
|
||||
$resolveTypeName = $this->nameResolver->getName($paramNode->type);
|
||||
$paramType = $this->resolveFromType($node);
|
||||
if (! $paramType instanceof MixedType) {
|
||||
return $paramType;
|
||||
}
|
||||
|
||||
$firstVariableUseType = $this->resolveFromFirstVariableUse($node);
|
||||
if (! $firstVariableUseType instanceof MixedType) {
|
||||
return $firstVariableUseType;
|
||||
}
|
||||
|
||||
return $this->resolveFromFunctionDocBlock($node);
|
||||
}
|
||||
|
||||
private function resolveFromFirstVariableUse(Param $param): Type
|
||||
{
|
||||
$classMethod = $param->getAttribute(AttributeKey::METHOD_NODE);
|
||||
if ($classMethod === null) {
|
||||
return new MixedType();
|
||||
}
|
||||
|
||||
/** @var string $paramName */
|
||||
$paramName = $this->nameResolver->getName($param);
|
||||
$paramStaticType = new MixedType();
|
||||
|
||||
// special case for param inside method/function
|
||||
$this->callableNodeTraverser->traverseNodesWithCallable(
|
||||
(array) $classMethod->stmts,
|
||||
function (Node $node) use ($paramName, &$paramStaticType): ?int {
|
||||
if (! $node instanceof Variable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->nameResolver->isName($node, $paramName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$paramStaticType = $this->nodeTypeResolver->resolve($node);
|
||||
|
||||
return NodeTraverser::STOP_TRAVERSAL;
|
||||
}
|
||||
);
|
||||
|
||||
return $paramStaticType;
|
||||
}
|
||||
|
||||
private function resolveFromFunctionDocBlock(Param $param): Type
|
||||
{
|
||||
/** @var FunctionLike $parentNode */
|
||||
$parentNode = $param->getAttribute(AttributeKey::PARENT_NODE);
|
||||
|
||||
/** @var string $paramName */
|
||||
$paramName = $this->nameResolver->getName($param);
|
||||
|
||||
return $this->docBlockManipulator->getParamTypeByName($parentNode, '$' . $paramName);
|
||||
}
|
||||
|
||||
private function resolveFromType(Node $node)
|
||||
{
|
||||
if ($node->type !== null && ! $node->type instanceof Identifier) {
|
||||
$resolveTypeName = $this->nameResolver->getName($node->type);
|
||||
if ($resolveTypeName) {
|
||||
// @todo map the other way every type :)
|
||||
return new ObjectType($resolveTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
/** @var FunctionLike $parentNode */
|
||||
$parentNode = $paramNode->getAttribute(AttributeKey::PARENT_NODE);
|
||||
|
||||
return $this->resolveTypesFromFunctionDocBlock($paramNode, $parentNode);
|
||||
}
|
||||
|
||||
private function resolveTypesFromFunctionDocBlock(Param $param, FunctionLike $functionLike): Type
|
||||
{
|
||||
/** @var string $paramName */
|
||||
$paramName = $this->nameResolver->getName($param);
|
||||
|
||||
return $this->docBlockManipulator->getParamTypeByName($functionLike, '$' . $paramName);
|
||||
return new MixedType();
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,11 @@ final class RectorsFinder
|
||||
|
||||
$rector = $reflectionClass->newInstanceWithoutConstructor();
|
||||
if (! $rector instanceof RectorInterface) {
|
||||
// lowercase letter bug in RototLoader
|
||||
if (Strings::endsWith($class, 'rector')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new ShouldNotHappenException(sprintf(
|
||||
'"%s" found something that looks like Rector but does not implements "%s" interface.',
|
||||
__METHOD__,
|
||||
|
Loading…
x
Reference in New Issue
Block a user