diff --git a/composer.json b/composer.json index 864c5f2cba4..4dc882acaee 100644 --- a/composer.json +++ b/composer.json @@ -53,7 +53,9 @@ "extra": { "patches": { "roave/better-reflection": { - "parser type miss-match with dev version": "patches/better-reflection-php-parser.patch" + "parser type miss-match with dev-version 1": "patches/better-reflection-php-parser-memoizing-parser.patch", + "parser type miss-match with dev-version 2": "patches/better-reflection-php-parser-reflection-function-abstract.patch", + "parser type miss-match with dev-version 3": "patches/better-reflection-php-parser-reflection-parameter.patch" } } } diff --git a/packages/BetterReflection/src/Reflector/MethodReflector.php b/packages/BetterReflection/src/Reflector/MethodReflector.php new file mode 100644 index 00000000000..5cdd190c8af --- /dev/null +++ b/packages/BetterReflection/src/Reflector/MethodReflector.php @@ -0,0 +1,33 @@ +classReflector = $classReflector; + } + + public function reflectClassMethod(string $class, string $method): ?ReflectionMethod + { + try { + $classReflection = $this->classReflector->reflect($class); + } catch (IdentifierNotFound $identifierNotFoundException) { + // class doesn't exist + return null; + } + + return $classReflection->getImmediateMethods()[$method] ?? null; + } +} diff --git a/packages/NodeTypeResolver/src/TypeContext.php b/packages/NodeTypeResolver/src/TypeContext.php index 6810c219b3c..d5665305110 100644 --- a/packages/NodeTypeResolver/src/TypeContext.php +++ b/packages/NodeTypeResolver/src/TypeContext.php @@ -6,9 +6,12 @@ use PhpParser\Node\Expr\Closure; use PhpParser\Node\FunctionLike; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassLike; +use Rector\BetterReflection\Reflector\MethodReflector; use Rector\NodeTypeResolver\TypesExtractor\ConstructorPropertyTypesExtractor; use ReflectionFunction; -use ReflectionMethod; +use Roave\BetterReflection\Reflection\ReflectionMethod; +use Roave\BetterReflection\Reflector\ClassReflector; +use Roave\BetterReflection\Reflector\Exception\IdentifierNotFound; /** * Inspired by https://github.com/nikic/PHP-Parser/blob/9373a8e9f551516bc8e42aedeacd1b4f635d27fc/lib/PhpParser/NameContext.php. @@ -35,9 +38,23 @@ final class TypeContext */ private $constructorPropertyTypesExtractor; - public function __construct(ConstructorPropertyTypesExtractor $constructorPropertyTypesExtractor) - { + /** + * @var ClassReflector + */ + private $classReflector; + /** + * @var MethodReflector + */ + private $methodReflector; + + public function __construct( + ConstructorPropertyTypesExtractor $constructorPropertyTypesExtractor, + ClassReflector $classReflector, + MethodReflector $methodReflector + ) { $this->constructorPropertyTypesExtractor = $constructorPropertyTypesExtractor; + $this->classReflector = $classReflector; + $this->methodReflector = $methodReflector; } public function startFile(): void @@ -91,25 +108,22 @@ final class TypeContext } /** - * @return ReflectionFunction|ReflectionMethod|null + * @return \Roave\BetterReflection\Reflection\ReflectionFunction|ReflectionMethod|null */ private function getFunctionReflection(FunctionLike $functionLikeNode) { if ($this->classLikeNode) { - $className = $this->classLikeNode->namespacedName->toString(); - if (! class_exists($className)) { - return null; - } - if ($functionLikeNode instanceof Closure) { return null; } + $className = $this->classLikeNode->namespacedName->toString(); $methodName = (string) $functionLikeNode->name; - return new ReflectionMethod($className, $methodName); + return $this->methodReflector->reflectClassMethod($className, $methodName); } + // todo: use BetterReflection\FunctionReflector? return new ReflectionFunction((string) $functionLikeNode->name); } } diff --git a/packages/NodeTypeResolver/src/TypesExtractor/ConstructorPropertyTypesExtractor.php b/packages/NodeTypeResolver/src/TypesExtractor/ConstructorPropertyTypesExtractor.php index a0c1cef0793..6eae10a6d9e 100644 --- a/packages/NodeTypeResolver/src/TypesExtractor/ConstructorPropertyTypesExtractor.php +++ b/packages/NodeTypeResolver/src/TypesExtractor/ConstructorPropertyTypesExtractor.php @@ -9,8 +9,9 @@ use PhpParser\Node\Expr\StaticCall; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Expression; -use ReflectionClass; -use Roave\BetterReflection\BetterReflection; +use PHPStan\Reflection\MethodsClassReflectionExtension; +use Rector\BetterReflection\Reflector\MethodReflector; +use Roave\BetterReflection\Reflection\ReflectionMethod; use Roave\BetterReflection\Reflector\ClassReflector; use Roave\BetterReflection\Reflector\Exception\IdentifierNotFound; @@ -20,10 +21,15 @@ final class ConstructorPropertyTypesExtractor * @var ClassReflector */ private $classReflector; + /** + * @var MethodReflector + */ + private $methodReflector; - public function __construct(ClassReflector $classReflector) + public function __construct(ClassReflector $classReflector, MethodReflector $methodReflector) { $this->classReflector = $classReflector; + $this->methodReflector = $methodReflector; } /** @@ -54,31 +60,15 @@ final class ConstructorPropertyTypesExtractor { $className = $classNode->namespacedName->toString(); - try { - $classReflection = $this->classReflector->reflect($className); - - } catch (IdentifierNotFound $identifierNotFoundException) { - // class doesn't exist + $constructorMethodReflection = $this->methodReflector->reflectClassMethod($className, '__construct'); + if ($constructorMethodReflection === null) { return []; } - // use DI - dump($classReflection); - die; - - // todo: add check for nonexisting classes when it comes - if (! class_exists($className)) { - return []; - } - - dump($classReflection); - die; - - $constructorMethod = (new ReflectionClass($className))->getConstructor(); $parametersWithTypes = []; - if ($constructorMethod) { - foreach ($constructorMethod->getParameters() as $parameterReflection) { + if ($constructorMethodReflection) { + foreach ($constructorMethodReflection->getParameters() as $parameterReflection) { $parameterName = $parameterReflection->getName(); $parameterType = (string) $parameterReflection->getType(); diff --git a/patches/better-reflection-php-parser.patch b/patches/better-reflection-php-parser-memoizing-parser.patch similarity index 100% rename from patches/better-reflection-php-parser.patch rename to patches/better-reflection-php-parser-memoizing-parser.patch diff --git a/patches/better-reflection-php-parser-reflection-function-abstract.patch b/patches/better-reflection-php-parser-reflection-function-abstract.patch new file mode 100644 index 00000000000..318cbcd22c7 --- /dev/null +++ b/patches/better-reflection-php-parser-reflection-function-abstract.patch @@ -0,0 +1,11 @@ +--- /dev/null ++++ roave/better-reflection/src/Reflection/ReflectionFunctionAbstract.php +@@ -149,7 +149,7 @@ + return self::CLOSURE_NAME; + } + +- return $this->node->name; ++ return (string) $this->node->name; + } + + /** diff --git a/patches/better-reflection-php-parser-reflection-parameter.patch b/patches/better-reflection-php-parser-reflection-parameter.patch new file mode 100644 index 00000000000..d784e6599a5 --- /dev/null +++ b/patches/better-reflection-php-parser-reflection-parameter.patch @@ -0,0 +1,11 @@ +--- /dev/null ++++ roave/better-reflection/src/Reflection/ReflectionParameter.php +@@ -262,7 +262,7 @@ + */ + public function getName() : string + { +- return $this->node->name; ++ return (string) $this->node->type; + } + + /**