mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-17 13:28:18 +01:00
[TypeDeclaration] Add ReturnTypeFromStrictTypedCallRector (#5573)
This commit is contained in:
parent
a3f3b0e7d2
commit
651573a58f
@ -190,6 +190,7 @@
|
||||
"rules/symfony4/tests/Rector/MethodCall/ContainerGetToConstructorInjectionRector/Source"
|
||||
],
|
||||
"files": [
|
||||
"rules/type-declaration/tests/Rector/ClassMethod/ReturnTypeFromStrictTypedCallRector/Source/external_bool_function.php",
|
||||
"rules/restoration/tests/Rector/Use_/RestoreFullyQualifiedNameRector/Source/ShortClassOnly.php",
|
||||
"rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Source/AnotherClass.php",
|
||||
"rules/coding-style/tests/Rector/Namespace_/ImportFullyQualifiedNamesRector/Source/Foo.php",
|
||||
|
@ -2,12 +2,20 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return static function (
|
||||
\Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator $containerConfigurator
|
||||
): void {
|
||||
use Rector\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector;
|
||||
use Rector\TypeDeclaration\Rector\ClassMethod\ParamTypeFromStrictTypedPropertyRector;
|
||||
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector;
|
||||
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedPropertyRector;
|
||||
use Rector\TypeDeclaration\Rector\Closure\AddClosureReturnTypeRector;
|
||||
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(\Rector\TypeDeclaration\Rector\Closure\AddClosureReturnTypeRector::class);
|
||||
$services->set(\Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedPropertyRector::class);
|
||||
$services->set(\Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictConstructorRector::class);
|
||||
$services->set(\Rector\TypeDeclaration\Rector\ClassMethod\ParamTypeFromStrictTypedPropertyRector::class);
|
||||
$services->set(AddClosureReturnTypeRector::class);
|
||||
$services->set(ReturnTypeFromStrictTypedPropertyRector::class);
|
||||
$services->set(TypedPropertyFromStrictConstructorRector::class);
|
||||
$services->set(ParamTypeFromStrictTypedPropertyRector::class);
|
||||
$services->set(ReturnTypeFromStrictTypedCallRector::class);
|
||||
$services->set(AddVoidReturnTypeWhereNoReturnRector::class);
|
||||
};
|
||||
|
@ -2,14 +2,20 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return static function (
|
||||
\Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator $containerConfigurator
|
||||
): void {
|
||||
use Rector\TypeDeclaration\Rector\ClassMethod\AddArrayParamDocTypeRector;
|
||||
use Rector\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector;
|
||||
use Rector\TypeDeclaration\Rector\Closure\AddClosureReturnTypeRector;
|
||||
use Rector\TypeDeclaration\Rector\FunctionLike\ParamTypeDeclarationRector;
|
||||
use Rector\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector;
|
||||
use Rector\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(\Rector\TypeDeclaration\Rector\FunctionLike\ParamTypeDeclarationRector::class);
|
||||
$services->set(\Rector\TypeDeclaration\Rector\FunctionLike\ReturnTypeDeclarationRector::class);
|
||||
$services->set(\Rector\TypeDeclaration\Rector\Property\PropertyTypeDeclarationRector::class);
|
||||
$services->set(\Rector\TypeDeclaration\Rector\Closure\AddClosureReturnTypeRector::class);
|
||||
$services->set(\Rector\TypeDeclaration\Rector\ClassMethod\AddArrayParamDocTypeRector::class);
|
||||
$services->set(\Rector\TypeDeclaration\Rector\ClassMethod\AddArrayReturnDocTypeRector::class);
|
||||
$services->set(ParamTypeDeclarationRector::class);
|
||||
$services->set(ReturnTypeDeclarationRector::class);
|
||||
$services->set(PropertyTypeDeclarationRector::class);
|
||||
$services->set(AddClosureReturnTypeRector::class);
|
||||
$services->set(AddArrayParamDocTypeRector::class);
|
||||
$services->set(AddArrayReturnDocTypeRector::class);
|
||||
};
|
||||
|
@ -188,6 +188,16 @@ final class NodeRepository
|
||||
return $this->functionsByName[$name] ?? null;
|
||||
}
|
||||
|
||||
public function findFunctionByFuncCall(FuncCall $funcCall): ?Function_
|
||||
{
|
||||
$functionName = $this->nodeNameResolver->getName($funcCall);
|
||||
if ($functionName === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->findFunction($functionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MethodCall[][]|StaticCall[][]
|
||||
*/
|
||||
|
@ -544,3 +544,9 @@ parameters:
|
||||
- '#Property PhpParser\\Node\\Param\:\:\$type \(PhpParser\\Node\\Identifier\|PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|PhpParser\\Node\\UnionType\|null\) does not accept PhpParser\\Node#'
|
||||
- '#Binary operation "\." between array\|string\|false and (.*?) results in an error#'
|
||||
- '#Parameter \#3 \.\.\.\$rest of function array_uintersect expects array, Closure\(PhpParser\\Node\\Param, PhpParser\\Node\\Param\)\: int given#'
|
||||
- '#Method Rector\\TypeDeclaration\\Rector\\ClassMethod\\ReturnTypeFromStrictTypedCallRector\:\:collectStrictReturnTypes\(\) should return array<PhpParser\\Node\\Name\|PhpParser\\Node\\NullableType\|PhpParser\\Node\\UnionType\> but returns array<int, PhpParser\\Node\>#'
|
||||
|
||||
# stmts vs getStmts() issue
|
||||
- '#Access to an undefined property PhpParser\\Node\\Expr\\ArrowFunction\|PhpParser\\Node\\Expr\\Closure\|PhpParser\\Node\\Stmt\\ClassMethod\|PhpParser\\Node\\Stmt\\Function_\:\:\$stmts#'
|
||||
- '#Parameter \#1 \$functionLike of method Rector\\TypeDeclaration\\TypeInferer\\SilentVoidResolver\:\:hasExlusiveVoid\(\) expects PhpParser\\Node\\Expr\\Closure\|PhpParser\\Node\\Stmt\\ClassMethod\|PhpParser\\Node\\Stmt\\Function_, PhpParser\\Node\\Expr\\ArrowFunction\|PhpParser\\Node\\Expr\\Closure\|PhpParser\\Node\\Stmt\\ClassMethod\|PhpParser\\Node\\Stmt\\Function_ given#'
|
||||
|
||||
|
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\NodeAnalyzer;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\NullableType;
|
||||
use PhpParser\Node\UnionType;
|
||||
use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
|
||||
|
||||
final class TypeNodeUnwrapper
|
||||
{
|
||||
/**
|
||||
* @var BetterStandardPrinter
|
||||
*/
|
||||
private $betterStandardPrinter;
|
||||
|
||||
public function __construct(BetterStandardPrinter $betterStandardPrinter)
|
||||
{
|
||||
$this->betterStandardPrinter = $betterStandardPrinter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<UnionType|NullableType|Name|Identifier> $typeNodes
|
||||
* @return array<Name|Identifier>
|
||||
*/
|
||||
public function unwrapNullableUnionTypes(array $typeNodes): array
|
||||
{
|
||||
$unwrappedTypeNodes = [];
|
||||
|
||||
foreach ($typeNodes as $typeNode) {
|
||||
if ($typeNode instanceof UnionType) {
|
||||
$unwrappedTypeNodes = array_merge($unwrappedTypeNodes, $typeNode->types);
|
||||
} elseif ($typeNode instanceof NullableType) {
|
||||
$unwrappedTypeNodes[] = $typeNode->type;
|
||||
$unwrappedTypeNodes[] = new Identifier('null');
|
||||
} else {
|
||||
$unwrappedTypeNodes[] = $typeNode;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->uniquateNodes($unwrappedTypeNodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node[] $nodes
|
||||
* @return Node[]
|
||||
*/
|
||||
public function uniquateNodes(array $nodes): array
|
||||
{
|
||||
$uniqueNodes = [];
|
||||
foreach ($nodes as $node) {
|
||||
$uniqueHash = $this->betterStandardPrinter->printWithoutComments($node);
|
||||
$uniqueNodes[$uniqueHash] = $node;
|
||||
}
|
||||
|
||||
// reset keys from 0, for further compatibility
|
||||
return array_values($uniqueNodes);
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\ArrowFunction;
|
||||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use Rector\CodingStyle\ValueObject\ObjectMagicMethods;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\TypeDeclaration\TypeInferer\SilentVoidResolver;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* @see \Rector\TypeDeclaration\Tests\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector\AddVoidReturnTypeWhereNoReturnRectorTest
|
||||
*/
|
||||
final class AddVoidReturnTypeWhereNoReturnRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var SilentVoidResolver
|
||||
*/
|
||||
private $silentVoidResolver;
|
||||
|
||||
public function __construct(SilentVoidResolver $silentVoidResolver)
|
||||
{
|
||||
$this->silentVoidResolver = $silentVoidResolver;
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Add return type void to function like without any return', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
final class SomeClass
|
||||
{
|
||||
public function getValues()
|
||||
{
|
||||
$value = 1000;
|
||||
return;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
final class SomeClass
|
||||
{
|
||||
public function getValues(): void
|
||||
{
|
||||
$value = 1000;
|
||||
return;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [ClassMethod::class, Function_::class, Closure::class, ArrowFunction::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod|Function_|Closure|ArrowFunction $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::SCALAR_TYPES)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($node->returnType !== null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->isNames($node, ObjectMagicMethods::METHOD_NAMES)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! $this->silentVoidResolver->hasExlusiveVoid($node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->isAtLeastPhpVersion(PhpVersionFeature::VOID_TYPE)) {
|
||||
$node->returnType = new Identifier('void');
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\ArrowFunction;
|
||||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\FuncCall;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\NullableType;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\Node\UnionType;
|
||||
use PhpParser\Node\UnionType as PhpParserUnionType;
|
||||
use PHPStan\Type\Type;
|
||||
use Rector\CodingStyle\ValueObject\ObjectMagicMethods;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @see \Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\ReturnTypeFromStrictTypedCallRectorTest
|
||||
*/
|
||||
final class ReturnTypeFromStrictTypedCallRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var ReflectionTypeResolver
|
||||
*/
|
||||
private $reflectionTypeResolver;
|
||||
|
||||
/**
|
||||
* @var TypeNodeUnwrapper
|
||||
*/
|
||||
private $typeNodeUnwrapper;
|
||||
|
||||
public function __construct(ReflectionTypeResolver $reflectionTypeResolver, TypeNodeUnwrapper $typeNodeUnwrapper)
|
||||
{
|
||||
$this->reflectionTypeResolver = $reflectionTypeResolver;
|
||||
$this->typeNodeUnwrapper = $typeNodeUnwrapper;
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition('Add return type from strict return type of call', [
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
final class SomeClass
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
return $this->getNumber();
|
||||
}
|
||||
|
||||
private function getNumber(): int
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
,
|
||||
<<<'CODE_SAMPLE'
|
||||
final class SomeClass
|
||||
{
|
||||
public function getData(): int
|
||||
{
|
||||
return $this->getNumber();
|
||||
}
|
||||
|
||||
private function getNumber(): int
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
CODE_SAMPLE
|
||||
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [ClassMethod::class, Function_::class, Closure::class, ArrowFunction::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod|Function_|Closure|ArrowFunction $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
if (! $this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::SCALAR_TYPES)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($node->returnType !== null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->isNames($node, ObjectMagicMethods::METHOD_NAMES)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var Return_[] $returns */
|
||||
$returns = $this->betterNodeFinder->findInstanceOf((array) $node->stmts, Return_::class);
|
||||
|
||||
$returnedStrictTypes = $this->collectStrictReturnTypes($returns);
|
||||
if ($returnedStrictTypes === []) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (count($returnedStrictTypes) === 1) {
|
||||
$node->returnType = $returnedStrictTypes[0];
|
||||
return $node;
|
||||
}
|
||||
|
||||
if ($this->isAtLeastPhpVersion(PhpVersionFeature::UNION_TYPES)) {
|
||||
$unwrappedTypes = $this->typeNodeUnwrapper->unwrapNullableUnionTypes($returnedStrictTypes);
|
||||
$node->returnType = new UnionType($unwrappedTypes);
|
||||
return $node;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Return_[] $returns
|
||||
* @return array<Name|NullableType|UnionType>
|
||||
*/
|
||||
private function collectStrictReturnTypes(array $returns): array
|
||||
{
|
||||
$returnedStrictTypeNodes = [];
|
||||
|
||||
foreach ($returns as $return) {
|
||||
if ($return->expr === null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$returnedExpr = $return->expr;
|
||||
|
||||
if ($returnedExpr instanceof MethodCall) {
|
||||
$returnNode = $this->resolveMethodCallReturnNode($returnedExpr);
|
||||
} elseif ($returnedExpr instanceof StaticCall) {
|
||||
$returnNode = $this->resolveStaticCallReturnNode($returnedExpr);
|
||||
} elseif ($returnedExpr instanceof FuncCall) {
|
||||
$returnNode = $this->resolveFuncCallReturnNode($returnedExpr);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (! $returnNode instanceof Node) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$returnedStrictTypeNodes[] = $returnNode;
|
||||
}
|
||||
|
||||
return $this->typeNodeUnwrapper->uniquateNodes($returnedStrictTypeNodes);
|
||||
}
|
||||
|
||||
private function resolveMethodCallReturnNode(MethodCall $methodCall): ?Node
|
||||
{
|
||||
$classMethod = $this->nodeRepository->findClassMethodByMethodCall($methodCall);
|
||||
if ($classMethod instanceof ClassMethod) {
|
||||
return $classMethod->returnType;
|
||||
}
|
||||
|
||||
$returnType = $this->reflectionTypeResolver->resolveMethodCallReturnType($methodCall);
|
||||
if (! $returnType instanceof Type) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Identifier|Name|NullableType|PhpParserUnionType|null
|
||||
*/
|
||||
private function resolveFuncCallReturnNode(FuncCall $funcCall): ?Node
|
||||
{
|
||||
$function = $this->nodeRepository->findFunctionByFuncCall($funcCall);
|
||||
if ($function instanceof Function_) {
|
||||
return $function->returnType;
|
||||
}
|
||||
|
||||
$returnType = $this->reflectionTypeResolver->resolveFuncCallReturnType($funcCall);
|
||||
if (! $returnType instanceof Type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($returnType);
|
||||
}
|
||||
}
|
@ -4,7 +4,13 @@ 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\Reflection\Php\PhpFunctionReflection;
|
||||
use PHPStan\Reflection\Php\PhpMethodReflection;
|
||||
use PHPStan\Reflection\Php\PhpPropertyReflection;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
use PHPStan\Type\Type;
|
||||
@ -12,6 +18,7 @@ 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
|
||||
{
|
||||
@ -30,14 +37,51 @@ final class ReflectionTypeResolver
|
||||
*/
|
||||
private $nodeNameResolver;
|
||||
|
||||
/**
|
||||
* @var PrivatesCaller
|
||||
*/
|
||||
private $privatesCaller;
|
||||
|
||||
public function __construct(
|
||||
NodeTypeResolver $nodeTypeResolver,
|
||||
ReflectionProvider $reflectionProvider,
|
||||
NodeNameResolver $nodeNameResolver
|
||||
NodeNameResolver $nodeNameResolver,
|
||||
PrivatesCaller $privatesCaller
|
||||
) {
|
||||
$this->nodeTypeResolver = $nodeTypeResolver;
|
||||
$this->reflectionProvider = $reflectionProvider;
|
||||
$this->nodeNameResolver = $nodeNameResolver;
|
||||
$this->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
|
||||
@ -64,4 +108,46 @@ 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);
|
||||
|
||||
$methodReflection = $classReflection->getMethod($methodName, $callerScope);
|
||||
if (! $methodReflection instanceof PhpMethodReflection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->privatesCaller->callPrivateMethod($methodReflection, 'getNativeReturnType', []);
|
||||
}
|
||||
}
|
||||
|
@ -5,18 +5,57 @@ declare(strict_types=1);
|
||||
namespace Rector\TypeDeclaration\TypeInferer;
|
||||
|
||||
use PhpParser\Node\Expr\Closure;
|
||||
use PhpParser\Node\Expr\Yield_;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use PhpParser\Node\Stmt\Function_;
|
||||
use PhpParser\Node\Stmt\Interface_;
|
||||
use PhpParser\Node\Stmt\Return_;
|
||||
use PhpParser\Node\Stmt\Switch_;
|
||||
use PhpParser\Node\Stmt\Throw_;
|
||||
use PhpParser\Node\Stmt\TryCatch;
|
||||
use Rector\Core\PhpParser\Node\BetterNodeFinder;
|
||||
use Rector\NodeTypeResolver\Node\AttributeKey;
|
||||
|
||||
final class SilentVoidResolver
|
||||
{
|
||||
/**
|
||||
* @var BetterNodeFinder
|
||||
*/
|
||||
private $betterNodeFinder;
|
||||
|
||||
public function __construct(BetterNodeFinder $betterNodeFinder)
|
||||
{
|
||||
$this->betterNodeFinder = $betterNodeFinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod|Closure|Function_ $functionLike
|
||||
*/
|
||||
public function hasExlusiveVoid(FunctionLike $functionLike): bool
|
||||
{
|
||||
$classLike = $functionLike->getAttribute(AttributeKey::CLASS_NODE);
|
||||
if ($classLike instanceof Interface_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->betterNodeFinder->hasInstancesOf((array) $functionLike->stmts, [Yield_::class])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var Return_[] $returns */
|
||||
$returns = $this->betterNodeFinder->findInstanceOf((array) $functionLike->stmts, Return_::class);
|
||||
foreach ($returns as $return) {
|
||||
if ($return->expr !== null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod|Closure|Function_ $functionLike
|
||||
*/
|
||||
@ -69,10 +108,12 @@ final class SilentVoidResolver
|
||||
$casesWithReturn = 0;
|
||||
foreach ($switch->cases as $case) {
|
||||
foreach ($case->stmts as $caseStmt) {
|
||||
if ($caseStmt instanceof Return_) {
|
||||
++$casesWithReturn;
|
||||
break;
|
||||
if (! $caseStmt instanceof Return_) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++$casesWithReturn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class AddVoidReturnTypeWhereNoReturnRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$this->doTestFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return AddVoidReturnTypeWhereNoReturnRector::class;
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector\Fixture;
|
||||
|
||||
use Iterator;
|
||||
|
||||
final class SkipExistingType
|
||||
{
|
||||
public function getValues(): Iterator
|
||||
{
|
||||
yield [100];
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector\Fixture;
|
||||
|
||||
final class SkipReturnOfSomething
|
||||
{
|
||||
public function getValues()
|
||||
{
|
||||
$value = 1000;
|
||||
if ($value) {
|
||||
return;
|
||||
}
|
||||
|
||||
return 10;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector\Fixture;
|
||||
|
||||
final class SkipYield
|
||||
{
|
||||
public function getValues()
|
||||
{
|
||||
yield [1000];
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector\Fixture;
|
||||
|
||||
final class SomeClass
|
||||
{
|
||||
public function getValues()
|
||||
{
|
||||
$value = 1000;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector\Fixture;
|
||||
|
||||
final class SomeClass
|
||||
{
|
||||
public function getValues(): void
|
||||
{
|
||||
$value = 1000;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
final class AlsoStaticCall
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
return ValuableData::getNumber();
|
||||
}
|
||||
}
|
||||
|
||||
final class ValuableData
|
||||
{
|
||||
public static function getNumber(): int
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
final class AlsoStaticCall
|
||||
{
|
||||
public function getData(): int
|
||||
{
|
||||
return ValuableData::getNumber();
|
||||
}
|
||||
}
|
||||
|
||||
final class ValuableData
|
||||
{
|
||||
public static function getNumber(): int
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
use Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source\SomeExternalCaller;
|
||||
|
||||
final class ExternalCaller
|
||||
{
|
||||
public function getData(SomeExternalCaller $someExternalCaller)
|
||||
{
|
||||
return $someExternalCaller->getName();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
use Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source\SomeExternalCaller;
|
||||
|
||||
final class ExternalCaller
|
||||
{
|
||||
public function getData(SomeExternalCaller $someExternalCaller): string
|
||||
{
|
||||
return $someExternalCaller->getName();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
use function Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source\getExternalBool;
|
||||
|
||||
final class ExternalFunctionCaller
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
return getExternalBool();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
use function Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source\getExternalBool;
|
||||
|
||||
final class ExternalFunctionCaller
|
||||
{
|
||||
public function getData(): bool
|
||||
{
|
||||
return getExternalBool();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
use Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source\SomeExternalStaticCaller;
|
||||
|
||||
final class ExternalStaticCaller
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
return SomeExternalStaticCaller::getNumbers();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
use Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source\SomeExternalStaticCaller;
|
||||
|
||||
final class ExternalStaticCaller
|
||||
{
|
||||
public function getData(): int
|
||||
{
|
||||
return SomeExternalStaticCaller::getNumbers();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
final class ReturnFunction
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
return getMeBool();
|
||||
}
|
||||
}
|
||||
|
||||
function getMeBool(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
final class ReturnFunction
|
||||
{
|
||||
public function getData(): bool
|
||||
{
|
||||
return getMeBool();
|
||||
}
|
||||
}
|
||||
|
||||
function getMeBool(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
final class SkipConstructorForVoid
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$value = 1000;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
interface SkipInterfaceForVoid
|
||||
{
|
||||
public function someMethod();
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
final class SkipOnceTypeAndOnceNot
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
if (mt_rand(0, 100)) {
|
||||
return $this->getNumber();
|
||||
}
|
||||
|
||||
return $this->getRandom();
|
||||
}
|
||||
|
||||
private function getNumber(): int
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
private function getRandom()
|
||||
{
|
||||
if (mt_rand(0, 1)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return '...';
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
final class SkipTwiceDifferentType
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
if (mt_rand(0, 100)) {
|
||||
return $this->getNumber();
|
||||
}
|
||||
|
||||
return $this->getString();
|
||||
}
|
||||
|
||||
private function getNumber(): int
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
private function getString(): string
|
||||
{
|
||||
return 'hey';
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
final class SomeClass
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
return $this->getNumber();
|
||||
}
|
||||
|
||||
private function getNumber(): int
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
final class SomeClass
|
||||
{
|
||||
public function getData(): int
|
||||
{
|
||||
return $this->getNumber();
|
||||
}
|
||||
|
||||
private function getNumber(): int
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
final class TwiceSameType
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
if (mt_rand(0, 100)) {
|
||||
return $this->getNumber(100);
|
||||
}
|
||||
|
||||
return $this->getNumber(10);
|
||||
}
|
||||
|
||||
private function getNumber(int $value): int
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Fixture;
|
||||
|
||||
final class TwiceSameType
|
||||
{
|
||||
public function getData(): int
|
||||
{
|
||||
if (mt_rand(0, 100)) {
|
||||
return $this->getNumber(100);
|
||||
}
|
||||
|
||||
return $this->getNumber(10);
|
||||
}
|
||||
|
||||
private function getNumber(int $value): int
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\FixturePhp80;
|
||||
|
||||
final class MixOfNullableTypes
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
if (mt_rand(0, 100)) {
|
||||
return $this->getFirstMix();
|
||||
}
|
||||
|
||||
return $this->getSecondMixed();
|
||||
}
|
||||
|
||||
private function getFirstMix(): ?int
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
private function getSecondMixed(): ?string
|
||||
{
|
||||
return 'hey';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\FixturePhp80;
|
||||
|
||||
final class MixOfNullableTypes
|
||||
{
|
||||
public function getData(): int|null|string
|
||||
{
|
||||
if (mt_rand(0, 100)) {
|
||||
return $this->getFirstMix();
|
||||
}
|
||||
|
||||
return $this->getSecondMixed();
|
||||
}
|
||||
|
||||
private function getFirstMix(): ?int
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
private function getSecondMixed(): ?string
|
||||
{
|
||||
return 'hey';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\FixturePhp80;
|
||||
|
||||
final class MixOfUnionTypes
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
if (mt_rand(0, 100)) {
|
||||
return $this->getFirstMix();
|
||||
}
|
||||
|
||||
return $this->getSecondMixed();
|
||||
}
|
||||
|
||||
private function getFirstMix(): int|string
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
private function getSecondMixed(): string|bool
|
||||
{
|
||||
return 'hey';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\FixturePhp80;
|
||||
|
||||
final class MixOfUnionTypes
|
||||
{
|
||||
public function getData(): int|string|bool
|
||||
{
|
||||
if (mt_rand(0, 100)) {
|
||||
return $this->getFirstMix();
|
||||
}
|
||||
|
||||
return $this->getSecondMixed();
|
||||
}
|
||||
|
||||
private function getFirstMix(): int|string
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
private function getSecondMixed(): string|bool
|
||||
{
|
||||
return 'hey';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\FixturePhp80;
|
||||
|
||||
final class TwiceDifferentType
|
||||
{
|
||||
public function getData()
|
||||
{
|
||||
if (mt_rand(0, 100)) {
|
||||
return $this->getNumber();
|
||||
}
|
||||
|
||||
return $this->getString();
|
||||
}
|
||||
|
||||
private function getNumber(): int
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
private function getString(): string
|
||||
{
|
||||
return 'hey';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\FixturePhp80;
|
||||
|
||||
final class TwiceDifferentType
|
||||
{
|
||||
public function getData(): int|string
|
||||
{
|
||||
if (mt_rand(0, 100)) {
|
||||
return $this->getNumber();
|
||||
}
|
||||
|
||||
return $this->getString();
|
||||
}
|
||||
|
||||
private function getNumber(): int
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
private function getString(): string
|
||||
{
|
||||
return 'hey';
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class Php80Test extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @requires PHP 8.0
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$this->doTestFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/FixturePhp80');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return ReturnTypeFromStrictTypedCallRector::class;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class ReturnTypeFromStrictTypedCallRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$this->doTestFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function provideConfigFilePath(): string
|
||||
{
|
||||
return __DIR__ . '/config/configured_rule.php';
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source;
|
||||
|
||||
final class SomeExternalCaller
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Yesman';
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source;
|
||||
|
||||
final class SomeExternalStaticCaller
|
||||
{
|
||||
public static function getNumbers(): int
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\TypeDeclaration\Tests\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\Source;
|
||||
|
||||
function getExternalBool(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\ValueObject\PhpVersionFeature;
|
||||
use Rector\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
|
||||
return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
$parameters = $containerConfigurator->parameters();
|
||||
$parameters->set(Option::PHP_VERSION_FEATURES, PhpVersionFeature::UNION_TYPES - 1);
|
||||
|
||||
$services = $containerConfigurator->services();
|
||||
$services->set(ReturnTypeFromStrictTypedCallRector::class);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user