Skip to content

Commit

Permalink
[CodeQuality] Add DynamicDocBlockPropertyToNativePropertyRector (#5691)
Browse files Browse the repository at this point in the history
* [CodeQuality] Kick off DynamicDocBlockPropertyToNativePropertyRector

* add nullable type with default

* skip __get() and __set()

* [ci-review] Rector Rectify

---------

Co-authored-by: GitHub Action <[email protected]>
  • Loading branch information
TomasVotruba and actions-user authored Oct 12, 2024
1 parent 6f863d1 commit d7bfc24
Show file tree
Hide file tree
Showing 13 changed files with 594 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector;

use Iterator;
use PHPUnit\Framework\Attributes\DataProvider;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;

final class DynamicDocBlockPropertyToNativePropertyRectorTest extends AbstractRectorTestCase
{
#[DataProvider('provideData')]
public function test(string $filePath): void
{
$this->doTestFile($filePath);
}

public static function provideData(): Iterator
{
return self::yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

/**
* @property SomeDependency $someDependency
*/
#[\AllowDynamicProperties]
final class BareClass
{
public function run(): void
{
$this->someDependency = new SomeDependency();
}
}

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

final class BareClass
{
private ?\Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency $someDependency;
public function run(): void
{
$this->someDependency = new SomeDependency();
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use PHPUnit\Framework\TestCase;
use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

/**
* @property SomeDependency $someDependency
*/
#[\AllowDynamicProperties]
final class ExistingProperty extends TestCase
{
private SomeDependency $someDependency;

protected function setUp(): void
{
parent::setUp();
$this->someDependency = new SomeDependency();
}
}

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use PHPUnit\Framework\TestCase;
use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

final class ExistingProperty extends TestCase
{
private SomeDependency $someDependency;
protected function setUp(): void
{
parent::setUp();
$this->someDependency = new SomeDependency();
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use PHPUnit\Framework\TestCase;
use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

/**
* @property SomeDependency $someDependency
*/
#[\AllowDynamicProperties]
final class ImproveExistingPropertyType extends TestCase
{
private $someDependency;

protected function setUp(): void
{
parent::setUp();
$this->someDependency = new SomeDependency();
}
}

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use PHPUnit\Framework\TestCase;
use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

final class ImproveExistingPropertyType extends TestCase
{
private \Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency $someDependency;
protected function setUp(): void
{
parent::setUp();
$this->someDependency = new SomeDependency();
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

/**
* @property SomeDependency $someDependency
*/
#[\AllowDynamicProperties]
final class IncludeNull
{
protected $someDependency = null;
}

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

final class IncludeNull
{
protected ?\Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency $someDependency = null;
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

/**
* @property SomeDependency $someDependency
*/
#[\AllowDynamicProperties]
final class PromotedPropertyPriority
{
public function __construct(
protected SomeDependency $someDependency
) {
}
}

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

final class PromotedPropertyPriority
{
public function __construct(
protected SomeDependency $someDependency
) {
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

/**
* @property SomeDependency $someDependency
*/
#[\AllowDynamicProperties]
final class SkipGetMagic
{
public function run(): void
{
$this->someDependency = new SomeDependency();
}

public function __get($name)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

/**
* @property SomeDependency $someDependency
*/
#[\AllowDynamicProperties]
final class SkipSetMagic
{
public function run(): void
{
$this->someDependency = new SomeDependency();
}

public function __set($name, $value)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use PHPUnit\Framework\TestCase;
use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

/**
* @property SomeDependency $someDependency
*/
#[\AllowDynamicProperties]
final class SomeTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
$this->someDependency = new SomeDependency();
}
}

?>
-----
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Fixture;

use PHPUnit\Framework\TestCase;
use Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency;

final class SomeTest extends TestCase
{
private ?\Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source\SomeDependency $someDependency;
protected function setUp(): void
{
parent::setUp();
$this->someDependency = new SomeDependency();
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Rector\Tests\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector\Source;

class SomeDependency
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

use Rector\CodeQuality\Rector\Class_\DynamicDocBlockPropertyToNativePropertyRector;
use Rector\Config\RectorConfig;
use Rector\ValueObject\PhpVersionFeature;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->phpVersion(PhpVersionFeature::DEPRECATE_DYNAMIC_PROPERTIES);

$rectorConfig->rule(DynamicDocBlockPropertyToNativePropertyRector::class);
};
55 changes: 55 additions & 0 deletions rules/CodeQuality/NodeFactory/TypedPropertyFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Rector\CodeQuality\NodeFactory;

use PhpParser\Node;
use PhpParser\Node\ComplexType;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\PropertyProperty;
use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\StaticTypeMapper\StaticTypeMapper;

final readonly class TypedPropertyFactory
{
public function __construct(
private StaticTypeMapper $staticTypeMapper,
) {
}

public function createFromPropertyTagValueNode(
PropertyTagValueNode $propertyTagValueNode,
Class_ $class,
string $propertyName
): Property {
$propertyProperty = new PropertyProperty($propertyName);
$propertyTypeNode = $this->createPropertyTypeNode($propertyTagValueNode, $class);

return new Property(Class_::MODIFIER_PRIVATE, [$propertyProperty], [], $propertyTypeNode);
}

public function createPropertyTypeNode(
PropertyTagValueNode $propertyTagValueNode,
Class_ $class,
bool $isNullable = true
): Name|ComplexType|Identifier|null {
$propertyType = $this->staticTypeMapper->mapPHPStanPhpDocTypeNodeToPHPStanType(
$propertyTagValueNode->type,
$class
);

$typeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($propertyType, TypeKind::PROPERTY);

if ($isNullable && ! $typeNode instanceof NullableType && ! $typeNode instanceof ComplexType && $typeNode instanceof Node) {
return new NullableType($typeNode);
}

return $typeNode;
}
}
Loading

0 comments on commit d7bfc24

Please sign in to comment.