Cleaning up NodeRepository dependency (#280)

Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
Tomas Votruba 2021-06-24 10:11:14 +02:00 committed by GitHub
parent 5daf16907a
commit 29e9bf5610
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 237 additions and 194 deletions

View File

@ -7,6 +7,8 @@ namespace Rector\StaticTypeMapper;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\UnionType as PhpParserUnionType;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
@ -19,6 +21,7 @@ use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;
use Rector\StaticTypeMapper\Mapper\PhpParserNodeMapper;
use Rector\StaticTypeMapper\Naming\NameScopeFactory;
@ -36,7 +39,6 @@ final class StaticTypeMapper
private PhpDocTypeMapper $phpDocTypeMapper,
private PhpParserNodeMapper $phpParserNodeMapper
) {
// $this->nameScopeFactory->setStaticTypeMapper($this);
}
public function mapPHPStanTypeToPHPStanPhpDocTypeNode(Type $phpStanType): TypeNode
@ -78,7 +80,16 @@ final class StaticTypeMapper
public function mapPHPStanPhpDocTypeNodeToPHPStanType(TypeNode $typeNode, Node $node): Type
{
if ($node instanceof Param) {
$classMethod = $node->getAttribute(AttributeKey::PARENT_NODE);
if ($classMethod instanceof ClassMethod) {
// param does not hany any clue about template map, but class method has
$node = $classMethod;
}
}
$nameScope = $this->nameScopeFactory->createNameScopeFromNode($node);
return $this->phpDocTypeMapper->mapToPHPStanType($typeNode, $node, $nameScope);
}

View File

@ -497,3 +497,6 @@ parameters:
-
message: '#Assign in loop is not allowed#'
path: rules/RemovingStatic/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php
# generics single place
- '#Method Rector\\Php80\\NodeResolver\\ArgumentSorter\:\:sortArgsByExpectedParamOrder\(\) should return array<T of PhpParser\\Node\\Arg\|PhpParser\\Node\\Param\> but returns array<PhpParser\\Node\\Arg\|PhpParser\\Node\\Param\>#'

View File

@ -0,0 +1,20 @@
<?php
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayParamDocTypeRector\Fixture;
use PhpParser\Node\Arg;
use PhpParser\Node\Param;
final class SkipTemplate
{
/**
* @template TItem as Arg|Param
* @param array<TItem> $args
* @param array<int, string> $expectedOrderedParams
* @return array<TItem>
*/
public function run(array $args): array
{
return $args;
}
}

View File

@ -2,54 +2,33 @@
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Fixture;
use Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Source\NestedGetData;
final class AddFromChild
{
public function getData(Nested $nested)
public function getData(NestedGetData $nested)
{
return $nested->getData();
}
}
final class Nested
{
public function getData()
{
return [
'key',
'value'
];
}
}
?>
-----
<?php
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Fixture;
use Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Source\NestedGetData;
final class AddFromChild
{
/**
* @return string[]
*/
public function getData(Nested $nested)
public function getData(NestedGetData $nested)
{
return $nested->getData();
}
}
final class Nested
{
/**
* @return string[]
*/
public function getData()
{
return [
'key',
'value'
];
}
}
?>

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector\Source;
final class NestedGetData
{
public function getData()
{
return [
'key',
'value'
];
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace Rector\Tests\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector\Fixture;
use Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator;
final class PrivatePropertyReflection
{
public function getTokens(BetterTokenIterator $betterTokenIterator): array
{
return $betterTokenIterator->getTokens();
}
}

View File

@ -6,13 +6,15 @@ namespace Rector\Php80\NodeResolver;
use PhpParser\Node\Arg;
use PhpParser\Node\Param;
use PHPStan\Reflection\ParameterReflection;
final class ArgumentSorter
{
/**
* @param array<int, Param> $expectedOrderedParams
* @param Arg[] $args
* @return Arg[]
* @template T as Arg|Param
* @param array<int, ParameterReflection> $expectedOrderedParams
* @param T[] $args
* @return T[]
*/
public function sortArgsByExpectedParamOrder(array $args, array $expectedOrderedParams): array
{

View File

@ -4,25 +4,27 @@ declare(strict_types=1);
namespace Rector\Php80\NodeResolver;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParameterReflection;
final class RequireOptionalParamResolver
{
/**
* @param ClassMethod $functionLike
* @return Param[]
* @return ParameterReflection[]
*/
public function resolve(FunctionLike $functionLike): array
public function resolveFromReflection(MethodReflection | FunctionReflection $functionLikeReflection): array
{
$parametersAcceptor = $functionLikeReflection->getVariants()[0];
$optionalParams = [];
$requireParams = [];
foreach ($functionLike->getParams() as $position => $param) {
if ($param->default === null && ! $param->variadic) {
$requireParams[$position] = $param;
foreach ($parametersAcceptor->getParameters() as $position => $parameterReflection) {
if ($parameterReflection->getDefaultValue() === null && ! $parameterReflection->isVariadic()) {
$requireParams[$position] = $parameterReflection;
} else {
$optionalParams[$position] = $param;
$optionalParams[$position] = $parameterReflection;
}
}

View File

@ -8,10 +8,12 @@ use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\TypeWithClassName;
use Rector\Core\PHPStan\Reflection\CallReflectionResolver;
use Rector\Core\PHPStan\Reflection\ClassMethodReflectionResolver;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\MethodName;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\Php80\NodeResolver\ArgumentSorter;
use Rector\Php80\NodeResolver\RequireOptionalParamResolver;
use Rector\Php80\Reflection\MethodReflectionClassMethodResolver;
@ -28,7 +30,9 @@ final class OptionalParametersAfterRequiredRector extends AbstractRector
public function __construct(
private RequireOptionalParamResolver $requireOptionalParamResolver,
private ArgumentSorter $argumentSorter,
private MethodReflectionClassMethodResolver $methodReflectionClassMethodResolver
private MethodReflectionClassMethodResolver $methodReflectionClassMethodResolver,
private CallReflectionResolver $callReflectionResolver,
private ClassMethodReflectionResolver $classMethodReflectionResolver
) {
}
@ -88,12 +92,25 @@ CODE_SAMPLE
return null;
}
$expectedOrderParams = $this->requireOptionalParamResolver->resolve($classMethod);
if ($classMethod->params === $expectedOrderParams) {
$classMethodReflection = $this->classMethodReflectionResolver->resolve($classMethod);
if (! $classMethodReflection instanceof MethodReflection) {
return null;
}
$classMethod->params = $expectedOrderParams;
$parametersAcceptor = $classMethodReflection->getVariants()[0];
$expectedOrderParameterReflections = $this->requireOptionalParamResolver->resolveFromReflection(
$classMethodReflection
);
if ($parametersAcceptor->getParameters() === $expectedOrderParameterReflections) {
return null;
}
$newParams = $this->argumentSorter->sortArgsByExpectedParamOrder(
$classMethod->params,
$expectedOrderParameterReflections
);
$classMethod->params = $newParams;
return $classMethod;
}
@ -117,8 +134,17 @@ CODE_SAMPLE
return null;
}
$expectedOrderedParams = $this->requireOptionalParamResolver->resolve($classMethod);
if ($expectedOrderedParams === $classMethod->getParams()) {
$classMethodReflection = $this->classMethodReflectionResolver->resolve($classMethod);
if (! $classMethodReflection instanceof MethodReflection) {
return null;
}
$parametersAcceptor = $classMethodReflection->getVariants()[0];
$expectedOrderedParameterReflections = $this->requireOptionalParamResolver->resolveFromReflection(
$classMethodReflection
);
if ($expectedOrderedParameterReflections === $parametersAcceptor->getParameters()) {
return null;
}
@ -126,7 +152,10 @@ CODE_SAMPLE
return null;
}
$newArgs = $this->argumentSorter->sortArgsByExpectedParamOrder($new->args, $expectedOrderedParams);
$newArgs = $this->argumentSorter->sortArgsByExpectedParamOrder(
$new->args,
$expectedOrderedParameterReflections
);
if ($new->args === $newArgs) {
return null;
}
@ -138,32 +167,35 @@ CODE_SAMPLE
private function refactorMethodCall(MethodCall $methodCall): ?MethodCall
{
$classMethod = $this->nodeRepository->findClassMethodByMethodCall($methodCall);
if (! $classMethod instanceof ClassMethod) {
$callReflection = $this->callReflectionResolver->resolveCall($methodCall);
if ($callReflection === null) {
return null;
}
// because parameters can be already changed
$originalClassMethod = $classMethod->getAttribute(AttributeKey::ORIGINAL_NODE);
if (! $originalClassMethod instanceof ClassMethod) {
$parametersAcceptor = $callReflection->getVariants()[0];
$expectedOrderedParameterReflections = $this->requireOptionalParamResolver->resolveFromReflection(
$callReflection
);
if ($expectedOrderedParameterReflections === $parametersAcceptor->getParameters()) {
return null;
}
$expectedOrderedParams = $this->requireOptionalParamResolver->resolve($originalClassMethod);
if ($expectedOrderedParams === $classMethod->getParams()) {
if (count($methodCall->args) !== count($parametersAcceptor->getParameters())) {
return null;
}
if (count($methodCall->args) !== count($classMethod->getParams())) {
return null;
}
$newArgs = $this->argumentSorter->sortArgsByExpectedParamOrder(
$methodCall->args,
$expectedOrderedParameterReflections
);
$newArgs = $this->argumentSorter->sortArgsByExpectedParamOrder($methodCall->args, $expectedOrderedParams);
if ($methodCall->args === $newArgs) {
return null;
}
$methodCall->args = $newArgs;
return $methodCall;
}
}

View File

@ -17,15 +17,15 @@ use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\UnionType as PhpParserUnionType;
use PHPStan\Type\MixedType;
use PHPStan\Type\NullType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PHPStan\Reflection\CallReflectionResolver;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\TypeDeclaration\NodeAnalyzer\TypeNodeUnwrapper;
use Rector\TypeDeclaration\Reflection\ReflectionTypeResolver;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@ -35,8 +35,8 @@ use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
final class ReturnTypeFromStrictTypedCallRector extends AbstractRector
{
public function __construct(
private ReflectionTypeResolver $reflectionTypeResolver,
private TypeNodeUnwrapper $typeNodeUnwrapper
private TypeNodeUnwrapper $typeNodeUnwrapper,
private CallReflectionResolver $callReflectionResolver
) {
}
@ -162,12 +162,8 @@ CODE_SAMPLE
$returnedExpr = $return->expr;
if ($returnedExpr instanceof MethodCall) {
if ($returnedExpr instanceof MethodCall || $returnedExpr instanceof StaticCall || $returnedExpr instanceof FuncCall) {
$returnNode = $this->resolveMethodCallReturnNode($returnedExpr);
} elseif ($returnedExpr instanceof StaticCall) {
$returnNode = $this->resolveStaticCallReturnNode($returnedExpr);
} elseif ($returnedExpr instanceof FuncCall) {
$returnNode = $this->resolveFuncCallReturnNode($returnedExpr);
} else {
return [];
}
@ -182,40 +178,16 @@ CODE_SAMPLE
return $this->typeNodeUnwrapper->uniquateNodes($returnedStrictTypeNodes);
}
private function resolveMethodCallReturnNode(MethodCall $methodCall): ?Node
private function resolveMethodCallReturnNode(MethodCall | StaticCall | FuncCall $call): ?Node
{
$classMethod = $this->nodeRepository->findClassMethodByMethodCall($methodCall);
if ($classMethod instanceof ClassMethod) {
return $classMethod->returnType;
}
$returnType = $this->reflectionTypeResolver->resolveMethodCallReturnType($methodCall);
if (! $returnType instanceof Type) {
$methodReflection = $this->callReflectionResolver->resolveCall($call);
if ($methodReflection === null) {
return null;
}
return $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType);
}
private function resolveStaticCallReturnNode(StaticCall $staticCall): ?Node
{
$classMethod = $this->nodeRepository->findClassMethodByStaticCall($staticCall);
if ($classMethod instanceof ClassMethod) {
return $classMethod->returnType;
}
$returnType = $this->reflectionTypeResolver->resolveStaticCallReturnType($staticCall);
if (! $returnType instanceof Type) {
return null;
}
return $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType);
}
private function resolveFuncCallReturnNode(FuncCall $funcCall): Name | NullableType | PhpParserUnionType | null
{
$returnType = $this->reflectionTypeResolver->resolveFuncCallReturnType($funcCall);
if (! $returnType instanceof Type) {
$parametersAcceptor = $methodReflection->getVariants()[0];
$returnType = $parametersAcceptor->getReturnType();
if ($returnType instanceof MixedType) {
return null;
}

View File

@ -246,6 +246,7 @@ CODE_SAMPLE
$hasExternalClassOrInterfaceOrTrait = $this->externalFullyQualifiedAnalyzer->hasExternalFullyQualifieds(
$classLike
);
return $functionLike->returnType === null && $hasExternalClassOrInterfaceOrTrait && $this->isName(
$inferredReturnNode,
'void'

View File

@ -4,14 +4,7 @@ declare(strict_types=1);
namespace Rector\TypeDeclaration\Reflection;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\Php\PhpFunctionReflection;
use PHPStan\Reflection\Php\PhpMethodReflection;
use PHPStan\Reflection\Php\PhpPropertyReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\Type;
@ -19,7 +12,6 @@ use PHPStan\Type\TypeWithClassName;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Symplify\PackageBuilder\Reflection\PrivatesCaller;
final class ReflectionTypeResolver
{
@ -27,40 +19,9 @@ final class ReflectionTypeResolver
private NodeTypeResolver $nodeTypeResolver,
private ReflectionProvider $reflectionProvider,
private NodeNameResolver $nodeNameResolver,
private PrivatesCaller $privatesCaller
) {
}
public function resolveMethodCallReturnType(MethodCall $methodCall): ?Type
{
$objectType = $this->nodeTypeResolver->resolve($methodCall->var);
if (! $objectType instanceof TypeWithClassName) {
return null;
}
$methodName = $this->nodeNameResolver->getName($methodCall->name);
if ($methodName === null) {
return null;
}
return $this->resolveNativeReturnTypeFromClassAndMethod($objectType->getClassName(), $methodName, $methodCall);
}
public function resolveStaticCallReturnType(StaticCall $staticCall): ?Type
{
$className = $this->nodeNameResolver->getName($staticCall->class);
if ($className === null) {
return null;
}
$methodName = $this->nodeNameResolver->getName($staticCall->name);
if ($methodName === null) {
return null;
}
return $this->resolveNativeReturnTypeFromClassAndMethod($className, $methodName, $staticCall);
}
public function resolvePropertyFetchType(PropertyFetch $propertyFetch): ?Type
{
$objectType = $this->nodeTypeResolver->resolve($propertyFetch->var);
@ -85,51 +46,4 @@ final class ReflectionTypeResolver
return null;
}
public function resolveFuncCallReturnType(FuncCall $funcCall): ?Type
{
$funcCallScope = $funcCall->getAttribute(AttributeKey::SCOPE);
$funcCallName = $funcCall->name;
if ($funcCallName instanceof Expr) {
return null;
}
if (! $this->reflectionProvider->hasFunction($funcCallName, $funcCallScope)) {
return null;
}
$functionReflection = $this->reflectionProvider->getFunction($funcCallName, $funcCallScope);
if (! $functionReflection instanceof PhpFunctionReflection) {
return null;
}
return $this->privatesCaller->callPrivateMethod($functionReflection, 'getNativeReturnType', []);
}
private function resolveNativeReturnTypeFromClassAndMethod(string $className, string $methodName, Expr $expr): ?Type
{
if (! $this->reflectionProvider->hasClass($className)) {
return null;
}
$classReflection = $this->reflectionProvider->getClass($className);
if (! $classReflection->hasMethod($methodName)) {
return null;
}
$callerScope = $expr->getAttribute(AttributeKey::SCOPE);
// probably trait
if (! $callerScope instanceof Scope) {
return null;
}
$methodReflection = $classReflection->getMethod($methodName, $callerScope);
if (! $methodReflection instanceof PhpMethodReflection) {
return null;
}
return $this->privatesCaller->callPrivateMethod($methodReflection, 'getNativeReturnType', []);
}
}

View File

@ -16,11 +16,15 @@ use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\NodeTraverser;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\Php\PhpFunctionReflection;
use PHPStan\Type\ArrayType;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use PHPStan\Type\VoidType;
use Rector\NodeCollector\NodeCollector\NodeRepository;
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\PHPStan\Reflection\CallReflectionResolver;
use Rector\Core\Reflection\FunctionLikeReflectionParser;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
@ -37,7 +41,9 @@ final class ReturnedNodesReturnTypeInferer implements ReturnTypeInfererInterface
private SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
private TypeFactory $typeFactory,
private SplArrayFixedTypeNarrower $splArrayFixedTypeNarrower,
private NodeRepository $nodeRepository
private CallReflectionResolver $callReflectionResolver,
private FunctionLikeReflectionParser $functionLikeReflectionParser,
private BetterStandardPrinter $betterStandardPrinter
) {
}
@ -137,17 +143,20 @@ final class ReturnedNodesReturnTypeInferer implements ReturnTypeInfererInterface
return new MixedType();
}
$classMethod = $this->nodeRepository->findClassMethodByMethodCall($return->expr);
if (! $classMethod instanceof ClassMethod) {
$callReflection = $this->callReflectionResolver->resolveCall($return->expr);
if ($callReflection === null) {
return new MixedType();
}
// avoid infinite looping over self call
if ($classMethod === $originalFunctionLike) {
return new MixedType();
if ($callReflection instanceof MethodReflection) {
return $this->resolveClassMethod($callReflection, $originalFunctionLike);
}
return $this->inferFunctionLike($classMethod);
if ($callReflection instanceof PhpFunctionReflection) {
return $this->resolveFunction($callReflection, $originalFunctionLike);
}
return new MixedType();
}
private function isArrayTypeMixed(Type $type): bool
@ -167,12 +176,47 @@ final class ReturnedNodesReturnTypeInferer implements ReturnTypeInfererInterface
{
if ($resolvedType instanceof MixedType || $this->isArrayTypeMixed($resolvedType)) {
$correctedType = $this->inferFromReturnedMethodCall($return, $functionLike);
// override only if has some extra value
if (! $correctedType instanceof MixedType) {
if (! $correctedType instanceof MixedType && ! $correctedType instanceof VoidType) {
return $correctedType;
}
}
return $resolvedType;
}
private function resolveClassMethod(MethodReflection $methodReflection, FunctionLike $originalFunctionLike): Type
{
$classMethod = $this->functionLikeReflectionParser->parseMethodReflection($methodReflection);
if (! $classMethod instanceof ClassMethod) {
return new MixedType();
}
$classMethodCacheKey = $this->betterStandardPrinter->print($classMethod);
$functionLikeCacheKey = $this->betterStandardPrinter->print($originalFunctionLike);
if ($classMethodCacheKey === $functionLikeCacheKey) {
return new MixedType();
}
return $this->inferFunctionLike($classMethod);
}
private function resolveFunction(PhpFunctionReflection $phpFunctionReflection, FunctionLike $functionLike): Type
{
$function = $this->functionLikeReflectionParser->parseFunctionReflection($phpFunctionReflection);
if (! $function instanceof Function_) {
return new MixedType();
}
$classMethodCacheKey = $this->betterStandardPrinter->print($function);
$functionLikeCacheKey = $this->betterStandardPrinter->print($functionLike);
if ($classMethodCacheKey === $functionLikeCacheKey) {
return new MixedType();
}
return $this->inferFunctionLike($function);
}
}

View File

@ -10,11 +10,13 @@ use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\NodeFinder;
use PhpParser\Parser;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\Php\PhpFunctionReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ObjectType;
use PHPStan\Type\ThisType;
@ -67,6 +69,38 @@ final class FunctionLikeReflectionParser
return $class->getMethod($methodReflection->getName());
}
public function parseFunctionReflection(PhpFunctionReflection $phpFunctionReflection): ?Function_
{
$fileName = $phpFunctionReflection->getFileName();
if ($fileName === false) {
return null;
}
$fileContent = $this->smartFileSystem->readFile($fileName);
if (! is_string($fileContent)) {
return null;
}
$nodes = (array) $this->parser->parse($fileContent);
$smartFileInfo = new SmartFileInfo($fileName);
$file = new File($smartFileInfo, $smartFileInfo->getContents());
$nodes = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($file, $nodes);
/** @var Function_[] $functions */
$functions = $this->nodeFinder->findInstanceOf($nodes, Function_::class);
foreach ($functions as $function) {
if (! $this->nodeNameResolver->isName($function, $phpFunctionReflection->getName())) {
continue;
}
return $function;
}
return null;
}
/**
* @param MethodCall|StaticCall|Node $node
*/