diff --git a/composer.json b/composer.json
index 31000e09672..d782a02fb58 100644
--- a/composer.json
+++ b/composer.json
@@ -140,7 +140,8 @@
"Rector\\NetteKdyby\\": "rules/nette-kdyby/src",
"Rector\\NetteUtilsCodeQuality\\": "rules/nette-utils-code-quality/src",
"Rector\\NetteCodeQuality\\": "rules/nette-code-quality/src",
- "Rector\\Decomplex\\": "rules/decomplex/src"
+ "Rector\\Decomplex\\": "rules/decomplex/src",
+ "Rector\\Downgrade\\": "rules/downgrade/src"
}
},
"autoload-dev": {
@@ -218,7 +219,8 @@
"Rector\\NetteKdyby\\Tests\\": "rules/nette-kdyby/tests",
"Rector\\NetteUtilsCodeQuality\\Tests\\": "rules/nette-utils-code-quality/tests",
"Rector\\NetteCodeQuality\\Tests\\": "rules/nette-code-quality/tests",
- "Rector\\Decomplex\\Tests\\": "rules/decomplex/tests"
+ "Rector\\Decomplex\\Tests\\": "rules/decomplex/tests",
+ "Rector\\Downgrade\\Tests\\": "rules/downgrade/tests"
},
"classmap": [
"rules/cakephp/tests/Rector/Name/ImplicitShortClassNameUseStatementRector/Source",
diff --git a/config/set/downgrade/downgrade.yaml b/config/set/downgrade/downgrade.yaml
new file mode 100644
index 00000000000..dca5879a0c3
--- /dev/null
+++ b/config/set/downgrade/downgrade.yaml
@@ -0,0 +1,2 @@
+services:
+ Rector\Downgrade\Rector\Property\TypedPropertyRector: null
diff --git a/docs/rector_rules_overview.md b/docs/rector_rules_overview.md
index 6109b040fd5..d5890996ec9 100644
--- a/docs/rector_rules_overview.md
+++ b/docs/rector_rules_overview.md
@@ -1,4 +1,4 @@
-# All 519 Rectors Overview
+# All 520 Rectors Overview
- [Projects](#projects)
- [General](#general)
@@ -18,6 +18,7 @@
- [Doctrine](#doctrine) (16)
- [DoctrineCodeQuality](#doctrinecodequality) (2)
- [DoctrineGedmoToKnplabs](#doctrinegedmotoknplabs) (7)
+- [Downgrade](#downgrade) (1)
- [DynamicTypeAnalysis](#dynamictypeanalysis) (3)
- [FileSystemRector](#filesystemrector) (1)
- [Guzzle](#guzzle) (1)
@@ -4213,6 +4214,27 @@ Change Tree from gedmo/doctrine-extensions to knplabs/doctrine-behaviors
+## Downgrade
+
+### `TypedPropertyRector`
+
+- class: [`Rector\Downgrade\Rector\Property\TypedPropertyRector`](/../master/rules/downgrade/src/Rector/Property/TypedPropertyRector.php)
+- [test fixtures](/../master/rules/php74/tests/Rector/Property/TypedPropertyRector/Fixture)
+
+Changes property type definition from type definitions to `@var` annotations.
+
+```diff
+ class SomeClass {
+- private string $property;
++ /**
++ * @var string
++ */
++ private $property;
+ }
+```
+
+
+
## DynamicTypeAnalysis
### `AddArgumentTypeWithProbeDataRector`
diff --git a/rules/downgrade/src/Rector/Property/TypedPropertyRector.php b/rules/downgrade/src/Rector/Property/TypedPropertyRector.php
new file mode 100644
index 00000000000..0f77b47c0f7
--- /dev/null
+++ b/rules/downgrade/src/Rector/Property/TypedPropertyRector.php
@@ -0,0 +1,72 @@
+type === null) {
+ return null;
+ }
+
+ /** @var PhpDocInfo|null $phpDocInfo */
+ $phpDocInfo = $node->getAttribute(AttributeKey::PHP_DOC_INFO);
+ if ($phpDocInfo === null) {
+ $phpDocInfo = $this->phpDocInfoFactory->createEmpty($node);
+ }
+
+ $newType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($node->type);
+ $phpDocInfo->changeVarType($newType);
+ $node->type = null;
+
+ return $node;
+ }
+}
diff --git a/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/classname_nullable_type.php.inc b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/classname_nullable_type.php.inc
new file mode 100644
index 00000000000..75ab74b6ea8
--- /dev/null
+++ b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/classname_nullable_type.php.inc
@@ -0,0 +1,22 @@
+
+-----
+
diff --git a/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/classname_type.php.inc b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/classname_type.php.inc
new file mode 100644
index 00000000000..a73c538e7b9
--- /dev/null
+++ b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/classname_type.php.inc
@@ -0,0 +1,22 @@
+
+-----
+
diff --git a/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/docblock_exists.php.inc b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/docblock_exists.php.inc
new file mode 100644
index 00000000000..d284704b9c0
--- /dev/null
+++ b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/docblock_exists.php.inc
@@ -0,0 +1,26 @@
+
+-----
+
diff --git a/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/fixture.php.inc b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/fixture.php.inc
new file mode 100644
index 00000000000..a3642426686
--- /dev/null
+++ b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/fixture.php.inc
@@ -0,0 +1,22 @@
+
+-----
+
diff --git a/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/nullable_type.php.inc b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/nullable_type.php.inc
new file mode 100644
index 00000000000..df4c27911b6
--- /dev/null
+++ b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Fixture/nullable_type.php.inc
@@ -0,0 +1,22 @@
+
+-----
+
diff --git a/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Source/AnotherClass.php b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Source/AnotherClass.php
new file mode 100644
index 00000000000..804e9c252f7
--- /dev/null
+++ b/rules/downgrade/tests/Rector/Property/TypedPropertyRector/Source/AnotherClass.php
@@ -0,0 +1,10 @@
+= 7.4
+ * @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 TypedPropertyRector::class;
+ }
+}
diff --git a/sonar-project.properties b/sonar-project.properties
index d77e0125be6..d8911404fff 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -4,9 +4,9 @@ sonar.projectKey=rectorphp_rector
# relative paths to source
# wildcards don't work :(
-sonar.sources=compiler/src,src,rules/autodiscovery/src,rules/architecture/src,packages/attribute-aware-php-doc/src,packages/better-php-doc-parser/src,rules/cakephp/src,rules/celebrity/src,rules/code-quality/src,rules/coding-style/src,packages/console-differ/src,rules/dead-code/src,rules/doctrine/src,rules/doctrine-code-quality/src,rules/framework-migration/src,packages/file-system-rector/src,rules/guzzle/src,rules/laravel/src,rules/legacy/src,rules/mysql-to-mysqli/src,rules/nette-tester-to-phpunit/src,rules/nette-to-symfony/src,rules/nette/src,packages/node-collector/src,packages/node-type-resolver/src,packages/node-name-resolver/src,rules/phpstan/src,packages/phpstan-static-type-mapper/src,rules/phpunit-symfony/src,rules/phpunit/src,rules/psr4/src,rules/php-spec-to-phpunit/src,rules/php52/src,rules/php53/src,rules/php54/src,rules/php55/src,rules/php56/src,rules/php70/src,rules/php71/src,rules/php72/src,rules/php73/src,rules/php74/src,rules/php80/src,rules/removing-static/src,rules/renaming/src,rules/restoration/src,rules/solid/src,rules/sensio/src,packages/static-type-mapper/src,rules/symfony-code-quality/src,rules/symfony-phpunit/src,rules/symfony/src,rules/twig/src,rules/type-declaration/src,packages/vendor-locker/src,packages/rector-generator/src,rules/strict-code-quality/src,packages/dynamic-type-analysis/src,rules/php-deglobalize/src,rules/phalcon/src,rules/doctrine-gedmo-to-knplabs/src,packages/polyfill/src
+sonar.sources=compiler/src,src,rules/autodiscovery/src,rules/architecture/src,packages/attribute-aware-php-doc/src,packages/better-php-doc-parser/src,rules/cakephp/src,rules/celebrity/src,rules/code-quality/src,rules/coding-style/src,packages/console-differ/src,rules/dead-code/src,rules/doctrine/src,rules/doctrine-code-quality/src,rules/framework-migration/src,packages/file-system-rector/src,rules/guzzle/src,rules/laravel/src,rules/legacy/src,rules/mysql-to-mysqli/src,rules/nette-tester-to-phpunit/src,rules/nette-to-symfony/src,rules/nette/src,packages/node-collector/src,packages/node-type-resolver/src,packages/node-name-resolver/src,rules/phpstan/src,packages/phpstan-static-type-mapper/src,rules/phpunit-symfony/src,rules/phpunit/src,rules/psr4/src,rules/php-spec-to-phpunit/src,rules/php52/src,rules/php53/src,rules/php54/src,rules/php55/src,rules/php56/src,rules/php70/src,rules/php71/src,rules/php72/src,rules/php73/src,rules/php74/src,rules/php80/src,rules/removing-static/src,rules/renaming/src,rules/restoration/src,rules/solid/src,rules/sensio/src,packages/static-type-mapper/src,rules/symfony-code-quality/src,rules/symfony-phpunit/src,rules/symfony/src,rules/twig/src,rules/type-declaration/src,packages/vendor-locker/src,packages/rector-generator/src,rules/strict-code-quality/src,packages/dynamic-type-analysis/src,rules/php-deglobalize/src,rules/phalcon/src,rules/doctrine-gedmo-to-knplabs/src,packages/polyfill/src,rules/downgrade/src
-sonar.tests=tests,rules/autodiscovery/tests,rules/architecture/tests,packages/better-php-doc-parser/tests,rules/cakephp/tests,rules/celebrity/tests,rules/code-quality/tests,rules/coding-style/tests,rules/dead-code/tests,rules/doctrine/tests,rules/doctrine-code-quality/tests,rules/guzzle/tests,rules/laravel/tests,rules/legacy/tests,rules/mysql-to-mysqli/tests,rules/nette-tester-to-phpunit/tests,rules/nette-to-symfony/tests,rules/nette/tests,packages/node-type-resolver/tests,utils/phpstan-extensions/src,rules/phpstan/tests,rules/phpunit-symfony/tests,rules/phpunit/tests,rules/psr4/tests,rules/php-spec-to-phpunit/tests,rules/php52/tests,rules/php53/tests,rules/php54/tests,rules/php55/tests,rules/php56/tests,rules/php70/tests,rules/php71/tests,rules/php72/tests,rules/php73/tests,rules/php74/tests,rules/php80/tests,rules/removing-static/tests,rules/renaming/tests,rules/restoration/tests,rules/solid/tests,rules/sensio/tests,rules/symfony-code-quality/tests,rules/symfony-phpunit/tests,rules/symfony/tests,rules/twig/tests,rules/type-declaration/tests,rules/strict-code-quality/tests,packages/dynamic-type-analysis/tests,rules/php-deglobalize/tests,rules/phalcon/tests,utils/documentation-generator/src,utils/phpstan-attribute-type-syncer/src,utils/phpstan-static-type-mapper-checker/src,rules/doctrine-gedmo-to-knplabs/tests,packages/polyfill/tests
+sonar.tests=tests,rules/autodiscovery/tests,rules/architecture/tests,packages/better-php-doc-parser/tests,rules/cakephp/tests,rules/celebrity/tests,rules/code-quality/tests,rules/coding-style/tests,rules/dead-code/tests,rules/doctrine/tests,rules/doctrine-code-quality/tests,rules/guzzle/tests,rules/laravel/tests,rules/legacy/tests,rules/mysql-to-mysqli/tests,rules/nette-tester-to-phpunit/tests,rules/nette-to-symfony/tests,rules/nette/tests,packages/node-type-resolver/tests,utils/phpstan-extensions/src,rules/phpstan/tests,rules/phpunit-symfony/tests,rules/phpunit/tests,rules/psr4/tests,rules/php-spec-to-phpunit/tests,rules/php52/tests,rules/php53/tests,rules/php54/tests,rules/php55/tests,rules/php56/tests,rules/php70/tests,rules/php71/tests,rules/php72/tests,rules/php73/tests,rules/php74/tests,rules/php80/tests,rules/removing-static/tests,rules/renaming/tests,rules/restoration/tests,rules/solid/tests,rules/sensio/tests,rules/symfony-code-quality/tests,rules/symfony-phpunit/tests,rules/symfony/tests,rules/twig/tests,rules/type-declaration/tests,rules/strict-code-quality/tests,packages/dynamic-type-analysis/tests,rules/php-deglobalize/tests,rules/phalcon/tests,utils/documentation-generator/src,utils/phpstan-attribute-type-syncer/src,utils/phpstan-static-type-mapper-checker/src,rules/doctrine-gedmo-to-knplabs/tests,packages/polyfill/tests,rules/downgrade/tests
# see https://docs.sonarqube.org/latest/project-administration/narrowing-the-focus/#NarrowingtheFocus-patterns
sonar.exclusions=src/**/*.php.inc,rules/**/*.php.inc,packages/**/*.php.inc,packages/**/Fixture/**/*,rules/**/Fixture/**/*,tests/**/Source/**/*