Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -465,11 +465,7 @@ parameters:
- '#Class "Rector\\CodingStyle\\Rector\\Enum_\\EnumCaseToPascalCaseRector" is missing @see annotation with test case class reference#'
- '#Class "Rector\\CodeQuality\\Rector\\Concat\\JoinStringConcatRector" is missing @see annotation with test case class reference#'
- '#Class "Rector\\CodeQuality\\Rector\\Switch_\\SwitchTrueToIfRector" is missing @see annotation with test case class reference#'

# false positive
-
identifier: phpstanApi.varTagAssumption
path: rules/TypeDeclarationDocblocks/Rector/ClassMethod/AddReturnDocblockForDimFetchArrayFromAssignsRector.php
- '#Class "Rector\\TypeDeclarationDocblocks\\Rector\\ClassMethod\\AddReturnDocblockForDimFetchArrayFromAssignsRector" is missing @see annotation with test case class reference#'

# @todo fix in phpstan-rules
-
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,18 @@
namespace Rector\TypeDeclarationDocblocks\Rector\ClassMethod;

use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Return_;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
use Rector\Configuration\Deprecation\Contract\DeprecatedInterface;
use Rector\Exception\ShouldNotHappenException;
use Rector\Rector\AbstractRector;
use Rector\TypeDeclarationDocblocks\NodeFinder\ReturnNodeFinder;
use Rector\TypeDeclarationDocblocks\TagNodeAnalyzer\UsefulArrayTagNodeAnalyzer;
use Rector\TypeDeclarationDocblocks\TypeResolver\ConstantArrayTypeGeneralizer;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;

/**
* @see \Rector\Tests\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForDimFetchArrayFromAssignsRector\AddReturnDocblockForDimFetchArrayFromAssignsRectorTest
* @deprecated This rule is deprecated, as the array shape is guessed from conditional assigns. The result is vague and unreliable, as any later assign can widen the type. Add the @return docblock manually instead.
*/
final class AddReturnDocblockForDimFetchArrayFromAssignsRector extends AbstractRector
final class AddReturnDocblockForDimFetchArrayFromAssignsRector extends AbstractRector implements DeprecatedInterface
{
public function __construct(
private readonly PhpDocInfoFactory $phpDocInfoFactory,
private readonly UsefulArrayTagNodeAnalyzer $usefulArrayTagNodeAnalyzer,
private readonly ReturnNodeFinder $returnNodeFinder,
private readonly ConstantArrayTypeGeneralizer $constantArrayTypeGeneralizer,
private readonly PhpDocTypeChanger $phpDocTypeChanger,
) {
}

public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
Expand Down Expand Up @@ -101,117 +81,9 @@ public function getNodeTypes(): array
*/
public function refactor(Node $node): ?ClassMethod
{
if ($node->stmts === null) {
return null;
}

$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);

if ($this->usefulArrayTagNodeAnalyzer->isUsefulArrayTag($phpDocInfo->getReturnTagValue())) {
return null;
}

$soleReturn = $this->returnNodeFinder->findOnlyReturnWithExpr($node);
if (! $soleReturn instanceof Return_) {
return null;
}

// only variable
if (! $soleReturn->expr instanceof Variable) {
return null;
}

// @todo check type here
$returnedExprType = $this->getType($soleReturn->expr);

if (! $this->isConstantArrayType($returnedExprType)) {
return null;
}

// find stmts with $item = [];
$returnedVariableName = $this->getName($soleReturn->expr);
if (! is_string($returnedVariableName)) {
return null;
}

if (! $this->isVariableInstantiated($node, $returnedVariableName)) {
return null;
}

if ($returnedExprType->getReferencedClasses() !== []) {
// better handled by shared-interface/class rule, to avoid turning objects to mixed
return null;
}

// conditional assign
$genericUnionedTypeNodes = [];

if ($returnedExprType instanceof UnionType) {
foreach ($returnedExprType->getTypes() as $unionedType) {
if ($unionedType instanceof ConstantArrayType) {
// skip empty array
if ($unionedType->getKeyTypes() === [] && $unionedType->getValueTypes() === []) {
continue;
}

$genericUnionedTypeNode = $this->constantArrayTypeGeneralizer->generalize($unionedType);
$genericUnionedTypeNodes[] = $genericUnionedTypeNode;
}
}
} else {
/** @var ConstantArrayType $returnedExprType */
$genericTypeNode = $this->constantArrayTypeGeneralizer->generalize($returnedExprType);
$this->phpDocTypeChanger->changeReturnTypeNode($node, $phpDocInfo, $genericTypeNode);

return $node;
}

// @todo handle multiple type nodes
$this->phpDocTypeChanger->changeReturnTypeNode($node, $phpDocInfo, $genericUnionedTypeNodes[0]);

return $node;
}

private function isVariableInstantiated(ClassMethod $classMethod, string $returnedVariableName): bool
{
foreach ((array) $classMethod->stmts as $stmt) {
if (! $stmt instanceof Expression) {
continue;
}

if (! $stmt->expr instanceof Assign) {
continue;
}

$assign = $stmt->expr;
if (! $assign->var instanceof Variable) {
continue;
}

if (! $this->isName($assign->var, $returnedVariableName)) {
continue;
}

// must be array assignment
if (! $assign->expr instanceof Array_) {
continue;
}

return true;
}

return false;
}

private function isConstantArrayType(Type $returnedExprType): bool
{
if ($returnedExprType instanceof UnionType) {
return array_all(
$returnedExprType->getTypes(),
fn (Type $unionedType): bool => $unionedType instanceof ConstantArrayType
);
}

return $returnedExprType instanceof ConstantArrayType;
throw new ShouldNotHappenException(sprintf(
'"%s" rule is deprecated, as the array shape guessed from conditional assigns is vague and unreliable. Add the @return docblock manually instead',
self::class
));
}
}
4 changes: 0 additions & 4 deletions src/Config/Level/TypeDeclarationDocblocksLevel.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddParamArrayDocblockFromDimFetchAccessRector;
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForArrayDimAssignedObjectRector;
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForCommonObjectDenominatorRector;
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForDimFetchArrayFromAssignsRector;
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\AddReturnDocblockForJsonArrayRector;
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockGetterReturnArrayFromPropertyDocblockVarRector;
use Rector\TypeDeclarationDocblocks\Rector\ClassMethod\DocblockReturnArrayFromDirectArrayInstanceRector;
Expand Down Expand Up @@ -58,8 +57,5 @@ final class TypeDeclarationDocblocksLevel
// return
DocblockGetterReturnArrayFromPropertyDocblockVarRector::class,
NarrowArrayCollectionUnionReturnDocblockRector::class,

// run latter after other rules, as more generic
AddReturnDocblockForDimFetchArrayFromAssignsRector::class,
];
}
Loading