diff --git a/.github/workflows/along_other_packages.yaml b/.github/workflows/along_other_packages.yaml
index b807c2d2b657..d08576d09d64 100644
--- a/.github/workflows/along_other_packages.yaml
+++ b/.github/workflows/along_other_packages.yaml
@@ -31,7 +31,7 @@ jobs:
name: "PHP ${{ matrix.php_version }}"
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
diff --git a/.github/workflows/bare_run.yaml b/.github/workflows/bare_run.yaml
index 69155eb2dc84..d802a98b3070 100644
--- a/.github/workflows/bare_run.yaml
+++ b/.github/workflows/bare_run.yaml
@@ -16,7 +16,7 @@ jobs:
php_version: ['7.2', '7.3', '7.4', '8.0', '8.1']
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
-
uses: shivammathur/setup-php@v2
diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index 2f1bb0b14109..d05dac882fc0 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -19,14 +19,13 @@ jobs:
directory:
- 'e2e/define-constant'
- 'e2e/dont-execute-code'
- - 'e2e/finalize'
- 'e2e/parse-php7-code'
- 'e2e/parse-php8-code'
name: End to end test - ${{ matrix.directory }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
diff --git a/.github/workflows/e2e_diff.yaml b/.github/workflows/e2e_diff.yaml
index e3e797366261..bd65c0cc1292 100644
--- a/.github/workflows/e2e_diff.yaml
+++ b/.github/workflows/e2e_diff.yaml
@@ -22,7 +22,7 @@ jobs:
name: End to end test with diff - ${{ matrix.directory }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
diff --git a/.github/workflows/e2e_global.yaml b/.github/workflows/e2e_global.yaml
index a5fa2bd731eb..16bf3a9b4251 100644
--- a/.github/workflows/e2e_global.yaml
+++ b/.github/workflows/e2e_global.yaml
@@ -19,7 +19,7 @@ jobs:
name: End to end test - ${{ matrix.directory }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
diff --git a/.github/workflows/e2e_php72.yaml b/.github/workflows/e2e_php72.yaml
index ce425e9c0860..1246812919ae 100644
--- a/.github/workflows/e2e_php72.yaml
+++ b/.github/workflows/e2e_php72.yaml
@@ -13,7 +13,7 @@ jobs:
name: End to end test - PHP 7.2 with load ReflectionUnionType stub
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
diff --git a/.github/workflows/e2e_php74.yaml b/.github/workflows/e2e_php74.yaml
index 627b65e6143b..fd30e3b40763 100644
--- a/.github/workflows/e2e_php74.yaml
+++ b/.github/workflows/e2e_php74.yaml
@@ -16,7 +16,7 @@ jobs:
name: End to end test - PHP 7.4 and Match class name
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
diff --git a/.github/workflows/standalone_rule_test.yaml b/.github/workflows/standalone_rule_test.yaml
index 046fa69f7807..6dbcd92edd98 100644
--- a/.github/workflows/standalone_rule_test.yaml
+++ b/.github/workflows/standalone_rule_test.yaml
@@ -19,7 +19,7 @@ jobs:
name: End to end test - ${{ matrix.directory }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- uses: shivammathur/setup-php@v2
with:
diff --git a/README.md b/README.md
index 5f2ea29e745a..ce4cce349a4d 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ There are 2 main ways to use Rector:
To use them, create a `rector.php` in your root directory:
```bash
-vendor/bin/rector init
+vendor/bin/rector
```
And modify it:
diff --git a/composer.json b/composer.json
index e3b48bf3e675..b3da2e4b7c64 100644
--- a/composer.json
+++ b/composer.json
@@ -8,7 +8,7 @@
],
"require": {
"php": "^7.2|^8.0",
- "phpstan/phpstan": "^1.10.15"
+ "phpstan/phpstan": "^1.10.20"
},
"autoload": {
"files": [
diff --git a/config/config.php b/config/config.php
index acc97294359a..43f44f9ace2b 100644
--- a/config/config.php
+++ b/config/config.php
@@ -23,32 +23,65 @@
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TypeParser;
use PHPStan\Reflection\ReflectionProvider;
+use Rector\BetterPhpDocParser\Contract\BasePhpDocNodeVisitorInterface;
+use Rector\BetterPhpDocParser\Contract\PhpDocParser\PhpDocNodeDecoratorInterface;
+use Rector\BetterPhpDocParser\PhpDocNodeMapper;
use Rector\BetterPhpDocParser\PhpDocParser\BetterPhpDocParser;
use Rector\BetterPhpDocParser\PhpDocParser\BetterTypeParser;
use Rector\Caching\Cache;
use Rector\Caching\CacheFactory;
use Rector\Caching\ValueObject\Storage\MemoryCacheStorage;
+use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface;
+use Rector\CodingStyle\ClassNameImport\ClassNameImportSkipper;
+use Rector\CodingStyle\Contract\ClassNameImport\ClassNameImportSkipVoterInterface;
use Rector\Config\RectorConfig;
+use Rector\Core\Application\ApplicationFileProcessor;
use Rector\Core\Bootstrap\ExtensionConfigResolver;
+use Rector\Core\Configuration\ConfigInitializer;
use Rector\Core\Configuration\Parameter\ParameterProvider;
+use Rector\Core\Console\Command\ListRulesCommand;
use Rector\Core\Console\ConsoleApplication;
+use Rector\Core\Console\Output\OutputFormatterCollector;
use Rector\Core\Console\Style\RectorConsoleOutputStyle;
use Rector\Core\Console\Style\RectorConsoleOutputStyleFactory;
use Rector\Core\Console\Style\SymfonyStyleFactory;
+use Rector\Core\Contract\Processor\FileProcessorInterface;
+use Rector\Core\Contract\Rector\NonPhpRectorInterface;
+use Rector\Core\Contract\Rector\PhpRectorInterface;
+use Rector\Core\Contract\Rector\RectorInterface;
+use Rector\Core\NonPhpFile\NonPhpFileProcessor;
+use Rector\Core\PhpParser\NodeTraverser\RectorNodeTraverser;
use Rector\Core\Validation\Collector\EmptyConfigurableRectorCollector;
+use Rector\Core\ValueObjectFactory\Application\FileFactory;
+use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
+use Rector\NodeNameResolver\NodeNameResolver;
+use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
use Rector\NodeTypeResolver\DependencyInjection\PHPStanServicesFactory;
+use Rector\NodeTypeResolver\NodeTypeResolver;
+use Rector\NodeTypeResolver\PHPStan\Scope\Contract\NodeVisitor\ScopeResolverNodeVisitorInterface;
+use Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver;
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocator\IntermediateSourceLocator;
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider;
+use Rector\Parallel\WorkerRunner;
+use Rector\PhpAttribute\AnnotationToAttributeMapper;
+use Rector\PhpAttribute\Contract\AnnotationToAttributeMapperInterface;
use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser;
use Rector\PhpDocParser\PhpParser\SmartPhpParser;
use Rector\PhpDocParser\PhpParser\SmartPhpParserFactory;
-use Rector\PSR4\Composer\PSR4NamespaceMatcher;
-use Rector\PSR4\Contract\PSR4AutoloadNamespaceMatcherInterface;
+use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;
+use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;
+use Rector\RectorGenerator\Command\GenerateCommand;
+use Rector\RectorGenerator\Command\InitRecipeCommand;
+use Rector\StaticTypeMapper\Contract\PhpDocParser\PhpDocTypeMapperInterface;
+use Rector\StaticTypeMapper\Contract\PhpParser\PhpParserNodeMapperInterface;
+use Rector\StaticTypeMapper\Mapper\PhpParserNodeMapper;
+use Rector\StaticTypeMapper\PhpDoc\PhpDocTypeMapper;
use Rector\Utils\Command\MissingInSetCommand;
use Rector\Utils\Command\OutsideAnySetCommand;
use RectorPrefix202306\Symfony\Component\Console\Application;
use RectorPrefix202306\Symfony\Component\Console\Style\SymfonyStyle;
use function RectorPrefix202306\Symfony\Component\DependencyInjection\Loader\Configurator\service;
+use function RectorPrefix202306\Symfony\Component\DependencyInjection\Loader\Configurator\tagged_iterator;
use RectorPrefix202306\Symfony\Component\Filesystem\Filesystem;
use RectorPrefix202306\Symplify\EasyParallel\ValueObject\EasyParallelConfig;
return static function (RectorConfig $rectorConfig) : void {
@@ -83,12 +116,11 @@
__DIR__ . '/../packages/PHPStanStaticTypeMapper/Enum',
__DIR__ . '/../packages/Caching/Cache.php',
__DIR__ . '/../packages/NodeTypeResolver/PhpDocNodeVisitor/UnderscoreRenamePhpDocNodeVisitor.php',
+ __DIR__ . '/../packages/NodeTypeResolver/PHPStan/ObjectWithoutClassTypeWithParentTypes.php',
// used in PHPStan
__DIR__ . '/../packages/NodeTypeResolver/Reflection/BetterReflection/RectorBetterReflectionSourceLocatorFactory.php',
__DIR__ . '/../packages/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php',
]);
- // psr-4
- $services->alias(PSR4AutoloadNamespaceMatcherInterface::class, PSR4NamespaceMatcher::class);
$services->load('Rector\\', __DIR__ . '/../rules')->exclude([__DIR__ . '/../rules/*/ValueObject/*', __DIR__ . '/../rules/*/Rector/*', __DIR__ . '/../rules/*/Contract/*', __DIR__ . '/../rules/*/Exception/*', __DIR__ . '/../rules/*/Enum/*']);
$services->set(Filesystem::class);
// use faster in-memory cache in CI.
@@ -133,8 +165,17 @@
$services->set(ScopeFactory::class)->factory([service(PHPStanServicesFactory::class), 'createScopeFactory']);
$services->set(TypeNodeResolver::class)->factory([service(PHPStanServicesFactory::class), 'createTypeNodeResolver']);
$services->set(DynamicSourceLocatorProvider::class)->factory([service(PHPStanServicesFactory::class), 'createDynamicSourceLocatorProvider']);
- $services->set(MissingInSetCommand::class);
- $services->set(OutsideAnySetCommand::class);
+ // add commands optinally
+ if (\class_exists(MissingInSetCommand::class)) {
+ $services->set(MissingInSetCommand::class);
+ $services->set(OutsideAnySetCommand::class);
+ $services->get(ConsoleApplication::class)->call('add', [service(MissingInSetCommand::class)])->call('add', [service(OutsideAnySetCommand::class)]);
+ }
+ if (\class_exists(InitRecipeCommand::class)) {
+ $services->set(InitRecipeCommand::class);
+ $services->set(GenerateCommand::class);
+ $services->get(ConsoleApplication::class)->call('add', [service(InitRecipeCommand::class)])->call('add', [service(GenerateCommand::class)]);
+ }
// phpdoc parser
$services->set(SmartPhpParser::class)->factory([service(SmartPhpParserFactory::class), 'create']);
$services->set(ConstExprEvaluator::class);
@@ -145,4 +186,23 @@
$services->set(\PHPStan\PhpDocParser\Lexer\Lexer::class);
$services->set(TypeParser::class);
$services->set(ConstExprParser::class);
+ // tagged services
+ $services->set(PhpDocNodeMapper::class)->arg('$phpDocNodeVisitors', tagged_iterator(BasePhpDocNodeVisitorInterface::class));
+ $services->set(BetterPhpDocParser::class)->arg('$phpDocNodeDecorators', tagged_iterator(PhpDocNodeDecoratorInterface::class));
+ $services->set(NodeTypeResolver::class)->arg('$nodeTypeResolvers', tagged_iterator(NodeTypeResolverInterface::class));
+ $services->set(PHPStanNodeScopeResolver::class)->arg('$nodeVisitors', tagged_iterator(ScopeResolverNodeVisitorInterface::class));
+ $services->set(PHPStanStaticTypeMapper::class)->arg('$typeMappers', tagged_iterator(TypeMapperInterface::class));
+ $services->set(PhpParserNodeMapper::class)->arg('$phpParserNodeMappers', tagged_iterator(PhpParserNodeMapperInterface::class));
+ $services->set(PhpDocTypeMapper::class)->arg('$phpDocTypeMappers', tagged_iterator(PhpDocTypeMapperInterface::class));
+ $services->set(ClassNameImportSkipper::class)->arg('$classNameImportSkipVoters', tagged_iterator(ClassNameImportSkipVoterInterface::class));
+ $services->set(ConfigInitializer::class)->arg('$rectors', tagged_iterator(RectorInterface::class));
+ $services->set(ListRulesCommand::class)->arg('$rectors', tagged_iterator(RectorInterface::class));
+ $services->set(OutputFormatterCollector::class)->arg('$outputFormatters', tagged_iterator(OutputFormatterInterface::class));
+ $services->set(NonPhpFileProcessor::class)->arg('$nonPhpRectors', tagged_iterator(NonPhpRectorInterface::class));
+ $services->set(RectorNodeTraverser::class)->arg('$phpRectors', tagged_iterator(PhpRectorInterface::class));
+ $services->set(NodeNameResolver::class)->arg('$nodeNameResolvers', tagged_iterator(NodeNameResolverInterface::class));
+ $services->set(ApplicationFileProcessor::class)->arg('$fileProcessors', tagged_iterator(FileProcessorInterface::class));
+ $services->set(FileFactory::class)->arg('$fileProcessors', tagged_iterator(FileProcessorInterface::class));
+ $services->set(WorkerRunner::class)->arg('$fileProcessors', tagged_iterator(FileProcessorInterface::class));
+ $services->set(AnnotationToAttributeMapper::class)->arg('$annotationToAttributeMappers', tagged_iterator(AnnotationToAttributeMapperInterface::class));
};
diff --git a/config/set/action-injection-to-constructor-injection.php b/config/set/action-injection-to-constructor-injection.php
deleted file mode 100644
index f0ea7c0e5501..000000000000
--- a/config/set/action-injection-to-constructor-injection.php
+++ /dev/null
@@ -1,10 +0,0 @@
-rule(ActionInjectionToConstructorInjectionRector::class);
-};
diff --git a/config/set/code-quality.php b/config/set/code-quality.php
index 868e5b711982..f85dc5af8de4 100644
--- a/config/set/code-quality.php
+++ b/config/set/code-quality.php
@@ -11,7 +11,9 @@
use Rector\CodeQuality\Rector\Catch_\ThrowWithPreviousExceptionRector;
use Rector\CodeQuality\Rector\Class_\CompleteDynamicPropertiesRector;
use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
+use Rector\CodeQuality\Rector\ClassConstFetch\ConvertStaticPrivateConstantToSelfRector;
use Rector\CodeQuality\Rector\ClassMethod\InlineArrayReturnAssignRector;
+use Rector\CodeQuality\Rector\ClassMethod\LocallyCalledStaticMethodToNonStaticRector;
use Rector\CodeQuality\Rector\ClassMethod\OptionalParametersAfterRequiredRector;
use Rector\CodeQuality\Rector\ClassMethod\ReturnTypeFromStrictScalarReturnExprRector;
use Rector\CodeQuality\Rector\Concat\JoinStringConcatRector;
@@ -25,7 +27,6 @@
use Rector\CodeQuality\Rector\Foreach_\SimplifyForeachToArrayFilterRector;
use Rector\CodeQuality\Rector\Foreach_\SimplifyForeachToCoalescingRector;
use Rector\CodeQuality\Rector\Foreach_\UnusedForeachValueToArrayKeysRector;
-use Rector\CodeQuality\Rector\FuncCall\ArrayKeysAndInArrayToArrayKeyExistsRector;
use Rector\CodeQuality\Rector\FuncCall\ArrayMergeOfNonArraysToSimpleArrayRector;
use Rector\CodeQuality\Rector\FuncCall\BoolvalToTypeCastRector;
use Rector\CodeQuality\Rector\FuncCall\CallUserFuncWithArrowFunctionToInlineRector;
@@ -44,7 +45,6 @@
use Rector\CodeQuality\Rector\FuncCall\SingleInArrayToCompareRector;
use Rector\CodeQuality\Rector\FuncCall\StrvalToTypeCastRector;
use Rector\CodeQuality\Rector\FuncCall\UnwrapSprintfOneArgumentRector;
-use Rector\CodeQuality\Rector\FunctionLike\RemoveAlwaysTrueConditionSetInConstructorRector;
use Rector\CodeQuality\Rector\FunctionLike\SimplifyUselessVariableRector;
use Rector\CodeQuality\Rector\Identical\BooleanNotIdenticalToNotIdenticalRector;
use Rector\CodeQuality\Rector\Identical\FlipTypeControlToUseExclusiveTypeRector;
@@ -109,5 +109,5 @@
'mbstrrpos' => 'mb_strrpos',
'mbsubstr' => 'mb_substr',
]);
- $rectorConfig->rules([CombinedAssignRector::class, SimplifyEmptyArrayCheckRector::class, ReplaceMultipleBooleanNotRector::class, ForeachToInArrayRector::class, SimplifyForeachToCoalescingRector::class, SimplifyFuncGetArgsCountRector::class, SimplifyInArrayValuesRector::class, SimplifyStrposLowerRector::class, GetClassToInstanceOfRector::class, SimplifyArraySearchRector::class, SimplifyConditionsRector::class, SimplifyIfNotNullReturnRector::class, SimplifyIfReturnBoolRector::class, SimplifyUselessVariableRector::class, UnnecessaryTernaryExpressionRector::class, RemoveExtraParametersRector::class, SimplifyDeMorganBinaryRector::class, SimplifyTautologyTernaryRector::class, SimplifyForeachToArrayFilterRector::class, SingleInArrayToCompareRector::class, SimplifyIfElseToTernaryRector::class, JoinStringConcatRector::class, ConsecutiveNullCompareReturnsToNullCoalesceQueueRector::class, ExplicitBoolCompareRector::class, CombineIfRector::class, UseIdenticalOverEqualWithSameTypeRector::class, SimplifyBoolIdenticalTrueRector::class, SimplifyRegexPatternRector::class, BooleanNotIdenticalToNotIdenticalRector::class, StrvalToTypeCastRector::class, FloatvalToTypeCastRector::class, CallableThisArrayToAnonymousFunctionRector::class, AndAssignsToSeparateLinesRector::class, CompactToVariablesRector::class, CompleteDynamicPropertiesRector::class, IsAWithStringWithThirdArgumentRector::class, StrlenZeroToIdenticalEmptyStringRector::class, RemoveAlwaysTrueConditionSetInConstructorRector::class, ThrowWithPreviousExceptionRector::class, RemoveSoleValueSprintfRector::class, ShortenElseIfRector::class, ArrayMergeOfNonArraysToSimpleArrayRector::class, IntvalToTypeCastRector::class, BoolvalToTypeCastRector::class, ArrayKeyExistsTernaryThenValueToCoalescingRector::class, AbsolutizeRequireAndIncludePathRector::class, ChangeArrayPushToArrayAssignRector::class, ForRepeatedCountToOwnVariableRector::class, ForeachItemsAssignToEmptyArrayToAssignRector::class, InlineIfToExplicitIfRector::class, ArrayKeysAndInArrayToArrayKeyExistsRector::class, UnusedForeachValueToArrayKeysRector::class, CommonNotEqualRector::class, SetTypeToCastRector::class, LogicalToBooleanRector::class, VarToPublicPropertyRector::class, IssetOnPropertyObjectToPropertyExistsRector::class, NewStaticToNewSelfRector::class, UnwrapSprintfOneArgumentRector::class, SwitchNegatedTernaryRector::class, SingularSwitchToIfRector::class, SimplifyIfNullableReturnRector::class, FuncGetArgsToVariadicParamRector::class, CallUserFuncToMethodCallRector::class, CallUserFuncWithArrowFunctionToInlineRector::class, CountArrayToEmptyArrayComparisonRector::class, FlipTypeControlToUseExclusiveTypeRector::class, InlineArrayReturnAssignRector::class, InlineIsAInstanceOfRector::class, TernaryFalseExpressionToIfRector::class, InlineConstructorDefaultToPropertyRector::class, ReturnTypeFromStrictScalarReturnExprRector::class, TernaryEmptyArrayArrayDimFetchToCoalesceRector::class, OptionalParametersAfterRequiredRector::class, SimplifyEmptyCheckOnEmptyArrayRector::class, SwitchTrueToIfRector::class, CleanupUnneededNullsafeOperatorRector::class, DisallowedEmptyRuleFixerRector::class]);
+ $rectorConfig->rules([CombinedAssignRector::class, SimplifyEmptyArrayCheckRector::class, ReplaceMultipleBooleanNotRector::class, ForeachToInArrayRector::class, SimplifyForeachToCoalescingRector::class, SimplifyFuncGetArgsCountRector::class, SimplifyInArrayValuesRector::class, SimplifyStrposLowerRector::class, GetClassToInstanceOfRector::class, SimplifyArraySearchRector::class, SimplifyConditionsRector::class, SimplifyIfNotNullReturnRector::class, SimplifyIfReturnBoolRector::class, SimplifyUselessVariableRector::class, UnnecessaryTernaryExpressionRector::class, RemoveExtraParametersRector::class, SimplifyDeMorganBinaryRector::class, SimplifyTautologyTernaryRector::class, SimplifyForeachToArrayFilterRector::class, SingleInArrayToCompareRector::class, SimplifyIfElseToTernaryRector::class, JoinStringConcatRector::class, ConsecutiveNullCompareReturnsToNullCoalesceQueueRector::class, ExplicitBoolCompareRector::class, CombineIfRector::class, UseIdenticalOverEqualWithSameTypeRector::class, SimplifyBoolIdenticalTrueRector::class, SimplifyRegexPatternRector::class, BooleanNotIdenticalToNotIdenticalRector::class, StrvalToTypeCastRector::class, FloatvalToTypeCastRector::class, CallableThisArrayToAnonymousFunctionRector::class, AndAssignsToSeparateLinesRector::class, CompactToVariablesRector::class, CompleteDynamicPropertiesRector::class, IsAWithStringWithThirdArgumentRector::class, StrlenZeroToIdenticalEmptyStringRector::class, ThrowWithPreviousExceptionRector::class, RemoveSoleValueSprintfRector::class, ShortenElseIfRector::class, ArrayMergeOfNonArraysToSimpleArrayRector::class, IntvalToTypeCastRector::class, BoolvalToTypeCastRector::class, ArrayKeyExistsTernaryThenValueToCoalescingRector::class, AbsolutizeRequireAndIncludePathRector::class, ChangeArrayPushToArrayAssignRector::class, ForRepeatedCountToOwnVariableRector::class, ForeachItemsAssignToEmptyArrayToAssignRector::class, InlineIfToExplicitIfRector::class, UnusedForeachValueToArrayKeysRector::class, CommonNotEqualRector::class, SetTypeToCastRector::class, LogicalToBooleanRector::class, VarToPublicPropertyRector::class, IssetOnPropertyObjectToPropertyExistsRector::class, NewStaticToNewSelfRector::class, UnwrapSprintfOneArgumentRector::class, SwitchNegatedTernaryRector::class, SingularSwitchToIfRector::class, SimplifyIfNullableReturnRector::class, FuncGetArgsToVariadicParamRector::class, CallUserFuncToMethodCallRector::class, CallUserFuncWithArrowFunctionToInlineRector::class, CountArrayToEmptyArrayComparisonRector::class, FlipTypeControlToUseExclusiveTypeRector::class, InlineArrayReturnAssignRector::class, InlineIsAInstanceOfRector::class, TernaryFalseExpressionToIfRector::class, InlineConstructorDefaultToPropertyRector::class, ReturnTypeFromStrictScalarReturnExprRector::class, TernaryEmptyArrayArrayDimFetchToCoalesceRector::class, OptionalParametersAfterRequiredRector::class, SimplifyEmptyCheckOnEmptyArrayRector::class, SwitchTrueToIfRector::class, CleanupUnneededNullsafeOperatorRector::class, DisallowedEmptyRuleFixerRector::class, ConvertStaticPrivateConstantToSelfRector::class, LocallyCalledStaticMethodToNonStaticRector::class]);
};
diff --git a/config/set/coding-style.php b/config/set/coding-style.php
index bcc99a22c687..0246f8bafbc8 100644
--- a/config/set/coding-style.php
+++ b/config/set/coding-style.php
@@ -9,7 +9,6 @@
use Rector\CodingStyle\Rector\Class_\AddArrayDefaultToArrayPropertyRector;
use Rector\CodingStyle\Rector\ClassConst\RemoveFinalFromConstRector;
use Rector\CodingStyle\Rector\ClassConst\SplitGroupedClassConstantsRector;
-use Rector\CodingStyle\Rector\ClassConst\VarConstantCommentRector;
use Rector\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector;
use Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector;
use Rector\CodingStyle\Rector\ClassMethod\NewlineBeforeNewAssignSetRector;
@@ -39,5 +38,5 @@
use Rector\Visibility\Rector\ClassMethod\ExplicitPublicClassMethodRector;
return static function (RectorConfig $rectorConfig) : void {
$rectorConfig->ruleWithConfiguration(FuncCallToConstFetchRector::class, ['php_sapi_name' => 'PHP_SAPI', 'pi' => 'M_PI']);
- $rectorConfig->rules([SeparateMultiUseImportsRector::class, PostIncDecToPreIncDecRector::class, UnSpreadOperatorRector::class, NewlineAfterStatementRector::class, RemoveFinalFromConstRector::class, NullableCompareToNullRector::class, BinarySwitchToIfElseRector::class, ConsistentImplodeRector::class, TernaryConditionVariableAssignmentRector::class, SymplifyQuoteEscapeRector::class, StringClassNameToClassConstantRector::class, CatchExceptionNameMatchingTypeRector::class, UseIncrementAssignRector::class, SplitDoubleAssignRector::class, VarConstantCommentRector::class, EncapsedStringsToSprintfRector::class, WrapEncapsedVariableInCurlyBracesRector::class, NewlineBeforeNewAssignSetRector::class, AddArrayDefaultToArrayPropertyRector::class, MakeInheritedMethodVisibilitySameAsParentRector::class, CallUserFuncArrayToVariadicRector::class, VersionCompareFuncCallToConstantRector::class, StaticArrowFunctionRector::class, StaticClosureRector::class, CountArrayToEmptyArrayComparisonRector::class, CallUserFuncToMethodCallRector::class, FuncGetArgsToVariadicParamRector::class, StrictArraySearchRector::class, UseClassKeywordForClassNameResolutionRector::class, SplitGroupedPropertiesRector::class, SplitGroupedClassConstantsRector::class, ExplicitPublicClassMethodRector::class]);
+ $rectorConfig->rules([SeparateMultiUseImportsRector::class, PostIncDecToPreIncDecRector::class, UnSpreadOperatorRector::class, NewlineAfterStatementRector::class, RemoveFinalFromConstRector::class, NullableCompareToNullRector::class, BinarySwitchToIfElseRector::class, ConsistentImplodeRector::class, TernaryConditionVariableAssignmentRector::class, SymplifyQuoteEscapeRector::class, StringClassNameToClassConstantRector::class, CatchExceptionNameMatchingTypeRector::class, UseIncrementAssignRector::class, SplitDoubleAssignRector::class, EncapsedStringsToSprintfRector::class, WrapEncapsedVariableInCurlyBracesRector::class, NewlineBeforeNewAssignSetRector::class, AddArrayDefaultToArrayPropertyRector::class, MakeInheritedMethodVisibilitySameAsParentRector::class, CallUserFuncArrayToVariadicRector::class, VersionCompareFuncCallToConstantRector::class, StaticArrowFunctionRector::class, StaticClosureRector::class, CountArrayToEmptyArrayComparisonRector::class, CallUserFuncToMethodCallRector::class, FuncGetArgsToVariadicParamRector::class, StrictArraySearchRector::class, UseClassKeywordForClassNameResolutionRector::class, SplitGroupedPropertiesRector::class, SplitGroupedClassConstantsRector::class, ExplicitPublicClassMethodRector::class]);
};
diff --git a/config/set/dead-code.php b/config/set/dead-code.php
index 9f1f9f11fef4..d49a43fae38c 100644
--- a/config/set/dead-code.php
+++ b/config/set/dead-code.php
@@ -11,9 +11,7 @@
use Rector\DeadCode\Rector\BooleanAnd\RemoveAndTrueRector;
use Rector\DeadCode\Rector\Cast\RecastingRemovalRector;
use Rector\DeadCode\Rector\ClassConst\RemoveUnusedPrivateClassConstantRector;
-use Rector\DeadCode\Rector\ClassMethod\RemoveDelegatingParentCallRector;
use Rector\DeadCode\Rector\ClassMethod\RemoveEmptyClassMethodRector;
-use Rector\DeadCode\Rector\ClassMethod\RemoveLastReturnRector;
use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedConstructorParamRector;
use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodParameterRector;
use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector;
@@ -21,6 +19,7 @@
use Rector\DeadCode\Rector\ClassMethod\RemoveUselessParamTagRector;
use Rector\DeadCode\Rector\ClassMethod\RemoveUselessReturnTagRector;
use Rector\DeadCode\Rector\Concat\RemoveConcatAutocastRector;
+use Rector\DeadCode\Rector\ConstFetch\RemovePhpVersionIdCheckRector;
use Rector\DeadCode\Rector\Expression\RemoveDeadStmtRector;
use Rector\DeadCode\Rector\Expression\SimplifyMirrorAssignRector;
use Rector\DeadCode\Rector\For_\RemoveDeadContinueRector;
@@ -30,10 +29,10 @@
use Rector\DeadCode\Rector\FunctionLike\RemoveDeadReturnRector;
use Rector\DeadCode\Rector\If_\RemoveAlwaysTrueIfConditionRector;
use Rector\DeadCode\Rector\If_\RemoveDeadInstanceOfRector;
+use Rector\DeadCode\Rector\If_\RemoveTypedPropertyDeadInstanceOfRector;
use Rector\DeadCode\Rector\If_\RemoveUnusedNonEmptyArrayBeforeForeachRector;
use Rector\DeadCode\Rector\If_\SimplifyIfElseWithSameContentRector;
use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector;
-use Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector;
use Rector\DeadCode\Rector\Node\RemoveNonExistingVarAnnotationRector;
use Rector\DeadCode\Rector\Plus\RemoveDeadZeroAndOneOperationRector;
use Rector\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector;
@@ -68,7 +67,6 @@
RemoveAndTrueRector::class,
RemoveConcatAutocastRector::class,
SimplifyUselessVariableRector::class,
- RemoveDelegatingParentCallRector::class,
RemoveDuplicatedCaseInSwitchRector::class,
RemoveNullPropertyInitializationRector::class,
RemoveUnreachableStatementRector::class,
@@ -78,10 +76,10 @@
RemoveDeadTryCatchRector::class,
RemoveUnusedVariableAssignRector::class,
RemoveUnusedNonEmptyArrayBeforeForeachRector::class,
- RemoveEmptyMethodCallRector::class,
RemoveDeadConditionAboveReturnRector::class,
RemoveUnusedConstructorParamRector::class,
RemoveDeadInstanceOfRector::class,
+ RemoveTypedPropertyDeadInstanceOfRector::class,
RemoveDeadLoopRector::class,
RemoveUnusedPrivateMethodParameterRector::class,
// docblock
@@ -90,10 +88,10 @@
RemoveNonExistingVarAnnotationRector::class,
RemoveUselessVarTagRector::class,
RemoveUnusedPromotedPropertyRector::class,
- RemoveLastReturnRector::class,
RemoveJustPropertyFetchForAssignRector::class,
RemoveJustVariableAssignRector::class,
RemoveAlwaysTrueIfConditionRector::class,
RemoveDeadZeroAndOneOperationRector::class,
+ RemovePhpVersionIdCheckRector::class,
]);
};
diff --git a/config/set/privatization.php b/config/set/privatization.php
index 898d1cd49e54..f4e6463e4473 100644
--- a/config/set/privatization.php
+++ b/config/set/privatization.php
@@ -4,11 +4,10 @@
namespace RectorPrefix202306;
use Rector\Config\RectorConfig;
-use Rector\Privatization\Rector\Class_\ChangeGlobalVariablesToPropertiesRector;
use Rector\Privatization\Rector\Class_\FinalizeClassesWithoutChildrenRector;
use Rector\Privatization\Rector\ClassMethod\PrivatizeFinalClassMethodRector;
use Rector\Privatization\Rector\MethodCall\PrivatizeLocalGetterToPropertyRector;
use Rector\Privatization\Rector\Property\PrivatizeFinalClassPropertyRector;
return static function (RectorConfig $rectorConfig) : void {
- $rectorConfig->rules([FinalizeClassesWithoutChildrenRector::class, ChangeGlobalVariablesToPropertiesRector::class, PrivatizeLocalGetterToPropertyRector::class, PrivatizeFinalClassPropertyRector::class, PrivatizeFinalClassMethodRector::class]);
+ $rectorConfig->rules([FinalizeClassesWithoutChildrenRector::class, PrivatizeLocalGetterToPropertyRector::class, PrivatizeFinalClassPropertyRector::class, PrivatizeFinalClassMethodRector::class]);
};
diff --git a/config/set/psr-4.php b/config/set/psr-4.php
deleted file mode 100644
index 416c33fdfafd..000000000000
--- a/config/set/psr-4.php
+++ /dev/null
@@ -1,12 +0,0 @@
-rule(NormalizeNamespaceByPSR4ComposerAutoloadRector::class);
- $rectorConfig->rule(MultipleClassFileToPsr4ClassesRector::class);
-};
diff --git a/config/set/strict-booleans.php b/config/set/strict-booleans.php
new file mode 100644
index 000000000000..86f731a5cdc4
--- /dev/null
+++ b/config/set/strict-booleans.php
@@ -0,0 +1,14 @@
+rules([BooleanInBooleanNotRuleFixerRector::class, DisallowedEmptyRuleFixerRector::class, BooleanInIfConditionRuleFixerRector::class, BooleanInTernaryOperatorRuleFixerRector::class, DisallowedShortTernaryRuleFixerRector::class]);
+};
diff --git a/config/set/type-declaration.php b/config/set/type-declaration.php
index 9d74eefa67ab..32ef99279f76 100644
--- a/config/set/type-declaration.php
+++ b/config/set/type-declaration.php
@@ -15,6 +15,7 @@
use Rector\TypeDeclaration\Rector\ClassMethod\AddVoidReturnTypeWhereNoReturnRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ArrayShapeFromConstantArrayReturnRector;
use Rector\TypeDeclaration\Rector\ClassMethod\BoolReturnTypeFromStrictScalarReturnsRector;
+use Rector\TypeDeclaration\Rector\ClassMethod\NumericReturnTypeFromStrictScalarReturnsRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ParamAnnotationIncorrectNullableRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ParamTypeByMethodCallTypeRector;
use Rector\TypeDeclaration\Rector\ClassMethod\ParamTypeByParentCallTypeRector;
@@ -39,5 +40,5 @@
use Rector\TypeDeclaration\Rector\Property\TypedPropertyFromStrictSetUpRector;
use Rector\TypeDeclaration\Rector\Property\VarAnnotationIncorrectNullableRector;
return static function (RectorConfig $rectorConfig) : void {
- $rectorConfig->rules([AddClosureReturnTypeRector::class, AddArrowFunctionReturnTypeRector::class, ParamTypeByMethodCallTypeRector::class, TypedPropertyFromAssignsRector::class, ReturnAnnotationIncorrectNullableRector::class, VarAnnotationIncorrectNullableRector::class, ParamAnnotationIncorrectNullableRector::class, AddReturnTypeDeclarationBasedOnParentClassMethodRector::class, ReturnTypeFromStrictTypedPropertyRector::class, TypedPropertyFromStrictConstructorRector::class, ParamTypeFromStrictTypedPropertyRector::class, AddVoidReturnTypeWhereNoReturnRector::class, ReturnTypeFromReturnNewRector::class, TypedPropertyFromStrictGetterMethodReturnTypeRector::class, AddMethodCallBasedStrictParamTypeRector::class, ArrayShapeFromConstantArrayReturnRector::class, ReturnTypeFromStrictBoolReturnExprRector::class, ReturnTypeFromStrictNativeCallRector::class, ReturnTypeFromStrictNewArrayRector::class, ReturnTypeFromStrictScalarReturnExprRector::class, TypedPropertyFromStrictSetUpRector::class, ParamTypeByParentCallTypeRector::class, AddParamTypeSplFixedArrayRector::class, AddParamTypeBasedOnPHPUnitDataProviderRector::class, AddParamTypeFromPropertyTypeRector::class, AddReturnTypeDeclarationFromYieldsRector::class, ReturnTypeFromReturnDirectArrayRector::class, ReturnTypeFromStrictConstantReturnRector::class, ReturnTypeFromStrictTypedCallRector::class, ReturnNeverTypeRector::class, EmptyOnNullableObjectToInstanceOfRector::class, PropertyTypeFromStrictSetterGetterRector::class, ReturnTypeFromStrictTernaryRector::class, BoolReturnTypeFromStrictScalarReturnsRector::class]);
+ $rectorConfig->rules([AddClosureReturnTypeRector::class, AddArrowFunctionReturnTypeRector::class, ParamTypeByMethodCallTypeRector::class, TypedPropertyFromAssignsRector::class, ReturnAnnotationIncorrectNullableRector::class, VarAnnotationIncorrectNullableRector::class, ParamAnnotationIncorrectNullableRector::class, AddReturnTypeDeclarationBasedOnParentClassMethodRector::class, ReturnTypeFromStrictTypedPropertyRector::class, TypedPropertyFromStrictConstructorRector::class, ParamTypeFromStrictTypedPropertyRector::class, AddVoidReturnTypeWhereNoReturnRector::class, ReturnTypeFromReturnNewRector::class, TypedPropertyFromStrictGetterMethodReturnTypeRector::class, AddMethodCallBasedStrictParamTypeRector::class, ArrayShapeFromConstantArrayReturnRector::class, ReturnTypeFromStrictBoolReturnExprRector::class, ReturnTypeFromStrictNativeCallRector::class, ReturnTypeFromStrictNewArrayRector::class, ReturnTypeFromStrictScalarReturnExprRector::class, TypedPropertyFromStrictSetUpRector::class, ParamTypeByParentCallTypeRector::class, AddParamTypeSplFixedArrayRector::class, AddParamTypeBasedOnPHPUnitDataProviderRector::class, AddParamTypeFromPropertyTypeRector::class, AddReturnTypeDeclarationFromYieldsRector::class, ReturnTypeFromReturnDirectArrayRector::class, ReturnTypeFromStrictConstantReturnRector::class, ReturnTypeFromStrictTypedCallRector::class, ReturnNeverTypeRector::class, EmptyOnNullableObjectToInstanceOfRector::class, PropertyTypeFromStrictSetterGetterRector::class, ReturnTypeFromStrictTernaryRector::class, BoolReturnTypeFromStrictScalarReturnsRector::class, NumericReturnTypeFromStrictScalarReturnsRector::class]);
};
diff --git a/docs/rector_rules_overview.md b/docs/rector_rules_overview.md
index 0c57e5f16f4c..23adbca74ae8 100644
--- a/docs/rector_rules_overview.md
+++ b/docs/rector_rules_overview.md
@@ -1,4 +1,4 @@
-# 391 Rules Overview
+# 369 Rules Overview
@@ -6,15 +6,11 @@
- [Arguments](#arguments) (6)
-- [CodeQuality](#codequality) (74)
+- [CodeQuality](#codequality) (72)
-- [CodingStyle](#codingstyle) (34)
+- [CodingStyle](#codingstyle) (31)
-- [Compatibility](#compatibility) (1)
-
-- [DeadCode](#deadcode) (46)
-
-- [DependencyInjection](#dependencyinjection) (2)
+- [DeadCode](#deadcode) (43)
- [EarlyReturn](#earlyreturn) (10)
@@ -22,8 +18,6 @@
- [Naming](#naming) (6)
-- [PSR4](#psr4) (2)
-
- [Php52](#php52) (2)
- [Php53](#php53) (3)
@@ -44,25 +38,23 @@
- [Php74](#php74) (13)
-- [Php80](#php80) (19)
+- [Php80](#php80) (17)
-- [Php81](#php81) (12)
+- [Php81](#php81) (11)
-- [Php82](#php82) (3)
+- [Php82](#php82) (4)
-- [Privatization](#privatization) (5)
+- [Privatization](#privatization) (4)
- [Removing](#removing) (6)
-- [RemovingStatic](#removingstatic) (1)
-
- [Renaming](#renaming) (10)
-- [Strict](#strict) (6)
+- [Strict](#strict) (5)
-- [Transform](#transform) (27)
+- [Transform](#transform) (22)
-- [TypeDeclaration](#typedeclaration) (40)
+- [TypeDeclaration](#typedeclaration) (41)
- [Visibility](#visibility) (3)
@@ -368,23 +360,6 @@ Change `array_key_exists()` ternary to coalescing
-### ArrayKeysAndInArrayToArrayKeyExistsRector
-
-Replace `array_keys()` and `in_array()` to `array_key_exists()`
-
-- class: [`Rector\CodeQuality\Rector\FuncCall\ArrayKeysAndInArrayToArrayKeyExistsRector`](../rules/CodeQuality/Rector/FuncCall/ArrayKeysAndInArrayToArrayKeyExistsRector.php)
-
-```diff
- function run($packageName, $values)
- {
-- $keys = array_keys($values);
-- return in_array($packageName, $keys, true);
-+ return array_key_exists($packageName, $values);
- }
-```
-
-
-
### ArrayMergeOfNonArraysToSimpleArrayRector
Change array_merge of non arrays to array directly
@@ -670,30 +645,13 @@ Change multiple null compares to ?? queue
Replaces static::* access to private constants with self::*
-:wrench: **configure it!**
-
- class: [`Rector\CodeQuality\Rector\ClassConstFetch\ConvertStaticPrivateConstantToSelfRector`](../rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php)
-```php
-ruleWithConfiguration(ConvertStaticPrivateConstantToSelfRector::class, [
- ConvertStaticPrivateConstantToSelfRector::ENABLE_FOR_NON_FINAL_CLASSES => false,
- ]);
-};
-```
-
-↓
-
```diff
- final class Foo {
+ final class Foo
+ {
private const BAR = 'bar';
+
public function run()
{
- $bar = static::BAR;
@@ -1005,36 +963,40 @@ Joins concat of 2 strings, unless the length is too long
-### LogicalToBooleanRector
+### LocallyCalledStaticMethodToNonStaticRector
-Change OR, AND to ||, && with more common understanding
+Change static method and local-only calls to non-static
-- class: [`Rector\CodeQuality\Rector\LogicalAnd\LogicalToBooleanRector`](../rules/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector.php)
+- class: [`Rector\CodeQuality\Rector\ClassMethod\LocallyCalledStaticMethodToNonStaticRector`](../rules/CodeQuality/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php)
```diff
--if ($f = false or true) {
-+if (($f = false) || true) {
- return $f;
+ class SomeClass
+ {
+ public function run()
+ {
+- self::someStatic();
++ $this->someStatic();
+ }
+
+- private static function someStatic()
++ private function someStatic()
+ {
+ }
}
```
-### NarrowUnionTypeDocRector
+### LogicalToBooleanRector
-Changes docblock by narrowing type
+Change OR, AND to ||, && with more common understanding
-- class: [`Rector\CodeQuality\Rector\ClassMethod\NarrowUnionTypeDocRector`](../rules/CodeQuality/Rector/ClassMethod/NarrowUnionTypeDocRector.php)
+- class: [`Rector\CodeQuality\Rector\LogicalAnd\LogicalToBooleanRector`](../rules/CodeQuality/Rector/LogicalAnd/LogicalToBooleanRector.php)
```diff
- class SomeClass {
- /**
-- * @param object|DateTime $message
-+ * @param DateTime $message
- */
- public function getMessage(object $message)
- {
- }
+-if ($f = false or true) {
++if (($f = false) || true) {
+ return $f;
}
```
@@ -1047,7 +1009,7 @@ Change unsafe new `static()` to new `self()`
- class: [`Rector\CodeQuality\Rector\New_\NewStaticToNewSelfRector`](../rules/CodeQuality/Rector/New_/NewStaticToNewSelfRector.php)
```diff
- class SomeClass
+ final class SomeClass
{
public function build()
{
@@ -1077,34 +1039,6 @@ Move required parameters after optional ones
-### RemoveAlwaysTrueConditionSetInConstructorRector
-
-If conditions is always true, perform the content right away
-
-- class: [`Rector\CodeQuality\Rector\FunctionLike\RemoveAlwaysTrueConditionSetInConstructorRector`](../rules/CodeQuality/Rector/FunctionLike/RemoveAlwaysTrueConditionSetInConstructorRector.php)
-
-```diff
- final class SomeClass
- {
- private $value;
-
- public function __construct(stdClass $value)
- {
- $this->value = $value;
- }
-
- public function go()
- {
-- if ($this->value) {
-- return 'yes';
-- }
-+ return 'yes';
- }
- }
-```
-
-
-
### RemoveSoleValueSprintfRector
Remove `sprintf()` wrapper if not needed
@@ -2129,47 +2063,6 @@ Use ++$value or --$value instead of `$value++` or `$value--`
-### PreferThisOrSelfMethodCallRector
-
-Changes `$this->...` and static:: to self:: or vise versa for given types
-
-:wrench: **configure it!**
-
-- class: [`Rector\CodingStyle\Rector\MethodCall\PreferThisOrSelfMethodCallRector`](../rules/CodingStyle/Rector/MethodCall/PreferThisOrSelfMethodCallRector.php)
-
-```php
-ruleWithConfiguration(PreferThisOrSelfMethodCallRector::class, [
- TestCase::class => 'prefer_self',
- ]);
-};
-```
-
-↓
-
-```diff
- use PHPUnit\Framework\TestCase;
-
- final class SomeClass extends TestCase
- {
- public function run()
- {
-- $this->assertEquals('a', 'a');
-+ self::assertEquals('a', 'a');
- }
- }
-```
-
-
-
### RemoveFinalFromConstRector
Remove final from constants in classes defined as final
@@ -2186,49 +2079,6 @@ Remove final from constants in classes defined as final
-### ReturnArrayClassMethodToYieldRector
-
-Turns array return to yield return in specific type and method
-
-:wrench: **configure it!**
-
-- class: [`Rector\CodingStyle\Rector\ClassMethod\ReturnArrayClassMethodToYieldRector`](../rules/CodingStyle/Rector/ClassMethod/ReturnArrayClassMethodToYieldRector.php)
-
-```php
-ruleWithConfiguration(ReturnArrayClassMethodToYieldRector::class, [
- new ReturnArrayClassMethodToYield('PHPUnit\Framework\TestCase', '*provide*'),
- ]);
-};
-```
-
-↓
-
-```diff
- use PHPUnit\Framework\TestCase;
-
- final class SomeTest implements TestCase
- {
- public static function provideData()
- {
-- return [
-- ['some text']
-- ];
-+ yield ['some text'];
- }
- }
-```
-
-
-
### SeparateMultiUseImportsRector
Split multi use imports and trait statements to standalone lines
@@ -2449,24 +2299,6 @@ Use ++ increment instead of `$var += 1`
-### VarConstantCommentRector
-
-Constant should have a `@var` comment with type
-
-- class: [`Rector\CodingStyle\Rector\ClassConst\VarConstantCommentRector`](../rules/CodingStyle/Rector/ClassConst/VarConstantCommentRector.php)
-
-```diff
- class SomeClass
- {
-+ /**
-+ * @var string
-+ */
- const HI = 'hi';
- }
-```
-
-
-
### VersionCompareFuncCallToConstantRector
Changes use of call to version compare function to use of PHP version constant
@@ -2502,39 +2334,6 @@ Wrap encapsed variables in curly braces
-## Compatibility
-
-### AttributeCompatibleAnnotationRector
-
-Change annotation to attribute compatible form, see https://tomasvotruba.com/blog/doctrine-annotations-and-attributes-living-together-in-peace/
-
-- class: [`Rector\Compatibility\Rector\Class_\AttributeCompatibleAnnotationRector`](../rules/Compatibility/Rector/Class_/AttributeCompatibleAnnotationRector.php)
-
-```diff
--use Doctrine\Common\Annotations\Annotation\Required;
-+use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
-
- /**
- * @annotation
-+ * @NamedArgumentConstructor
- */
- class SomeAnnotation
- {
- /**
-- * @var string[]
-- * @Required()
-+ * @param string[] $enum
- */
-- public array $enum;
-+ public function __construct(
-+ public array $enum
-+ ) {
-+ }
- }
-```
-
-
-
## DeadCode
### RecastingRemovalRector
@@ -2698,18 +2497,14 @@ Remove if, foreach and for that does not do anything
```diff
class SomeClass
{
- public function run($someObject)
+ public function run($value)
{
- $value = 5;
- if ($value) {
- }
-
- if ($someObject->run()) {
+- foreach ($values as $value) {
- }
-
-- foreach ($values as $value) {
- }
-
return $value;
}
}
@@ -2724,16 +2519,13 @@ Remove dead instanceof check on type hinted variable
- class: [`Rector\DeadCode\Rector\If_\RemoveDeadInstanceOfRector`](../rules/DeadCode/Rector/If_/RemoveDeadInstanceOfRector.php)
```diff
- final class SomeClass
+ function run(stdClass $stdClass)
{
- public function go(stdClass $stdClass)
- {
-- if (! $stdClass instanceof stdClass) {
-- return false;
-- }
+- if (! $stdClass instanceof stdClass) {
+- return false;
+- }
-
- return true;
- }
+ return true;
}
```
@@ -2840,24 +2632,6 @@ Remove operation with 1 and 0, that have no effect on the value
-### RemoveDelegatingParentCallRector
-
-Removed dead parent call, that does not change anything
-
-- class: [`Rector\DeadCode\Rector\ClassMethod\RemoveDelegatingParentCallRector`](../rules/DeadCode/Rector/ClassMethod/RemoveDelegatingParentCallRector.php)
-
-```diff
- class SomeClass
- {
-- public function prettyPrint(array $stmts): string
-- {
-- return parent::prettyPrint($stmts);
-- }
- }
-```
-
-
-
### RemoveDoubleAssignRector
Simplify useless double assigns
@@ -2930,27 +2704,6 @@ Remove empty class methods not required by parents
-### RemoveEmptyMethodCallRector
-
-Remove empty method call
-
-- class: [`Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector`](../rules/DeadCode/Rector/MethodCall/RemoveEmptyMethodCallRector.php)
-
-```diff
- class SomeClass
- {
- public function callThis()
- {
- }
- }
-
--$some = new SomeClass();
--$some->callThis();
-+$some = new SomeClass();
-```
-
-
-
### RemoveJustPropertyFetchForAssignRector
Remove assign of property, just for value assign
@@ -3018,27 +2771,6 @@ Remove variable just to assign value or return value
-### RemoveLastReturnRector
-
-Remove very last `return` that has no meaning
-
-- class: [`Rector\DeadCode\Rector\ClassMethod\RemoveLastReturnRector`](../rules/DeadCode/Rector/ClassMethod/RemoveLastReturnRector.php)
-
-```diff
- function some_function($value)
- {
- if ($value === 1000) {
- return;
- }
-
- if ($value) {
-- return;
- }
- }
-```
-
-
-
### RemoveNonExistingVarAnnotationRector
Removes non-existing `@var` annotations above the code
@@ -3096,27 +2828,8 @@ Remove unused parent call with no parent class
Remove unneeded PHP_VERSION_ID conditional checks
-:wrench: **configure it!**
-
- class: [`Rector\DeadCode\Rector\ConstFetch\RemovePhpVersionIdCheckRector`](../rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php)
-```php
-ruleWithConfiguration(RemovePhpVersionIdCheckRector::class, [
- 80000,
- ]);
-};
-```
-
-↓
-
```diff
class SomeClass
{
@@ -3133,18 +2846,48 @@ return static function (RectorConfig $rectorConfig): void {
-### RemoveUnreachableStatementRector
+### RemoveTypedPropertyDeadInstanceOfRector
-Remove unreachable statements
+Remove dead instanceof check on type hinted property
-- class: [`Rector\DeadCode\Rector\Stmt\RemoveUnreachableStatementRector`](../rules/DeadCode/Rector/Stmt/RemoveUnreachableStatementRector.php)
+- class: [`Rector\DeadCode\Rector\If_\RemoveTypedPropertyDeadInstanceOfRector`](../rules/DeadCode/Rector/If_/RemoveTypedPropertyDeadInstanceOfRector.php)
```diff
- class SomeClass
+ final class SomeClass
{
- public function run()
+ private $someObject;
+
+ public function __construct(SomeObject $someObject)
{
- return 5;
+ $this->someObject = $someObject;
+ }
+
+ public function run()
+ {
+- if ($this->someObject instanceof SomeObject) {
+- return true;
+- }
+-
+- return false;
++ return true;
+ }
+ }
+```
+
+
+
+### RemoveUnreachableStatementRector
+
+Remove unreachable statements
+
+- class: [`Rector\DeadCode\Rector\Stmt\RemoveUnreachableStatementRector`](../rules/DeadCode/Rector/Stmt/RemoveUnreachableStatementRector.php)
+
+```diff
+ class SomeClass
+ {
+ public function run()
+ {
+ return 5;
-
- $removeMe = 10;
}
@@ -3280,27 +3023,8 @@ Remove unused private method
Remove unused private properties
-:wrench: **configure it!**
-
- class: [`Rector\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector`](../rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php)
-```php
-ruleWithConfiguration(RemoveUnusedPrivatePropertyRector::class, [
- RemoveUnusedPrivatePropertyRector::REMOVE_ASSIGN_SIDE_EFFECT => true,
- ]);
-};
-```
-
-↓
-
```diff
class SomeClass
{
@@ -3450,43 +3174,6 @@ Removes unneeded `$value` = `$value` assigns
-### TargetRemoveClassMethodRector
-
-Remove defined class method
-
-:wrench: **configure it!**
-
-- class: [`Rector\DeadCode\Rector\Class_\TargetRemoveClassMethodRector`](../rules/DeadCode/Rector/Class_/TargetRemoveClassMethodRector.php)
-
-```php
-ruleWithConfiguration(TargetRemoveClassMethodRector::class, [
- new TargetRemoveClassMethod('SomeClass', 'run'),
- ]);
-};
-```
-
-↓
-
-```diff
- class SomeClass
- {
-- public function run()
-- {
-- }
- }
-```
-
-
-
### TernaryToBooleanOrFalseToBooleanAndRector
Change ternary of bool : false to && bool
@@ -3529,72 +3216,6 @@ Remove php version checks if they are passed
-## DependencyInjection
-
-### ActionInjectionToConstructorInjectionRector
-
-Turns action injection in Controllers to constructor injection
-
-- class: [`Rector\DependencyInjection\Rector\Class_\ActionInjectionToConstructorInjectionRector`](../rules/DependencyInjection/Rector/Class_/ActionInjectionToConstructorInjectionRector.php)
-
-```diff
- final class SomeController
- {
-- public function default(ProductRepository $productRepository)
-+ public function __construct(
-+ private ProductRepository $productRepository
-+ ) {
-+ }
-+
-+ public function default()
- {
-- $products = $productRepository->fetchAll();
-+ $products = $this->productRepository->fetchAll();
- }
- }
-```
-
-
-
-### AddMethodParentCallRector
-
-Add method parent call, in case new parent method is added
-
-:wrench: **configure it!**
-
-- class: [`Rector\DependencyInjection\Rector\ClassMethod\AddMethodParentCallRector`](../rules/DependencyInjection/Rector/ClassMethod/AddMethodParentCallRector.php)
-
-```php
-ruleWithConfiguration(AddMethodParentCallRector::class, [
- 'ParentClassWithNewConstructor' => '__construct',
- ]);
-};
-```
-
-↓
-
-```diff
- class SunshineCommand extends ParentClassWithNewConstructor
- {
- public function __construct()
- {
- $value = 5;
-+
-+ parent::__construct();
- }
- }
-```
-
-
-
## EarlyReturn
### ChangeAndIfToEarlyReturnRector
@@ -4080,68 +3701,6 @@ Rename variable to match new ClassType
-## PSR4
-
-### MultipleClassFileToPsr4ClassesRector
-
-Change multiple classes in one file to standalone PSR-4 classes.
-
-- class: [`Rector\PSR4\Rector\Namespace_\MultipleClassFileToPsr4ClassesRector`](../rules/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector.php)
-
-```diff
-+// new file: "app/Exceptions/FirstException.php"
- namespace App\Exceptions;
-
- use Exception;
-
- final class FirstException extends Exception
- {
- }
-+
-+// new file: "app/Exceptions/SecondException.php"
-+namespace App\Exceptions;
-+
-+use Exception;
-
- final class SecondException extends Exception
- {
- }
-```
-
-
-
-### NormalizeNamespaceByPSR4ComposerAutoloadRector
-
-Adds namespace to namespace-less files or correct namespace to match PSR-4 in `composer.json` autoload section. Run with combination with "Rector\PSR4\Rector\Namespace_\MultipleClassFileToPsr4ClassesRector"
-
-- class: [`Rector\PSR4\Rector\FileWithoutNamespace\NormalizeNamespaceByPSR4ComposerAutoloadRector`](../rules/PSR4/Rector/FileWithoutNamespace/NormalizeNamespaceByPSR4ComposerAutoloadRector.php)
-
-- with `composer.json`:
-
-```json
-{
- "autoload": {
- "psr-4": {
- "App\\CustomNamespace\\": "src"
- }
- }
-}
-```
-
-↓
-
-```diff
- // src/SomeClass.php
-
-+namespace App\CustomNamespace;
-+
- class SomeClass
- {
- }
-```
-
-
-
## Php52
### ContinueToBreakInSwitchRector
@@ -5680,47 +5239,6 @@ return static function (RectorConfig $rectorConfig): void {
-### DoctrineAnnotationClassToAttributeRector
-
-Refactor Doctrine `@annotation` annotated class to a PHP 8.0 attribute class
-
-:wrench: **configure it!**
-
-- class: [`Rector\Php80\Rector\Class_\DoctrineAnnotationClassToAttributeRector`](../rules/Php80/Rector/Class_/DoctrineAnnotationClassToAttributeRector.php)
-
-```php
-ruleWithConfiguration(DoctrineAnnotationClassToAttributeRector::class, [
- DoctrineAnnotationClassToAttributeRector::REMOVE_ANNOTATIONS => true,
- ]);
-};
-```
-
-↓
-
-```diff
--use Doctrine\Common\Annotations\Annotation\Target;
-+use Attribute;
-
--/**
-- * @Annotation
-- * @Target({"METHOD"})
-- */
-+#[Attribute(Attribute::TARGET_METHOD)]
- class SomeAnnotation
- {
- }
-```
-
-
-
### FinalPrivateToPrivateVisibilityRector
Changes method visibility from final private to only private
@@ -5989,50 +5507,8 @@ Add `Stringable` interface to classes with `__toString()` method
-### UnionTypesRector
-
-Change docs types to union types, where possible (properties are covered by TypedPropertiesRector)
-
-- class: [`Rector\Php80\Rector\FunctionLike\UnionTypesRector`](../rules/Php80/Rector/FunctionLike/UnionTypesRector.php)
-
-```diff
- class SomeClass
- {
-- /**
-- * @param array|int $number
-- * @return bool|float
-- */
-- public function go($number)
-+ public function go(array|int $number): bool|float
- {
- }
- }
-```
-
-
-
## Php81
-### ConstantListClassToEnumRector
-
-Upgrade constant list classes to full blown enum
-
-- class: [`Rector\Php81\Rector\Class_\ConstantListClassToEnumRector`](../rules/Php81/Rector/Class_/ConstantListClassToEnumRector.php)
-
-```diff
--class Direction
-+enum Direction
- {
-- public const LEFT = 'left';
-+ case LEFT;
-
-- public const RIGHT = 'right';
-+ case RIGHT;
- }
-```
-
-
-
### FinalizePublicClassConstantRector
Add final to constants that does not have children
@@ -6258,6 +5734,45 @@ Refactor Spatie enum method calls
## Php82
+### AddSensitiveParameterAttributeRector
+
+Add SensitiveParameter attribute to method and function configured parameters
+
+:wrench: **configure it!**
+
+- class: [`Rector\Php82\Rector\Param\AddSensitiveParameterAttributeRector`](../rules/Php82/Rector/Param/AddSensitiveParameterAttributeRector.php)
+
+```php
+ruleWithConfiguration(AddSensitiveParameterAttributeRector::class, [
+ AddSensitiveParameterAttributeRector::SENSITIVE_PARAMETERS => [
+ 'password',
+ ],
+ ]);
+};
+```
+
+↓
+
+```diff
+ class SomeClass
+ {
+- public function run(string $password)
++ public function run(#[\SensitiveParameter] string $password)
+ {
+ }
+ }
+```
+
+
+
### FilesystemIteratorSkipDotsRector
Prior PHP 8.2 FilesystemIterator::SKIP_DOTS was always set and could not be removed, therefore FilesystemIterator::SKIP_DOTS is added in order to keep this behaviour.
@@ -6308,34 +5823,6 @@ Change deprecated utf8_decode and utf8_encode to mb_convert_encoding
## Privatization
-### ChangeGlobalVariablesToPropertiesRector
-
-Change global `$variables` to private properties
-
-- class: [`Rector\Privatization\Rector\Class_\ChangeGlobalVariablesToPropertiesRector`](../rules/Privatization/Rector/Class_/ChangeGlobalVariablesToPropertiesRector.php)
-
-```diff
- class SomeClass
- {
-+ private $variable;
- public function go()
- {
-- global $variable;
-- $variable = 5;
-+ $this->variable = 5;
- }
-
- public function run()
- {
-- global $variable;
-- var_dump($variable);
-+ var_dump($this->variable);
- }
- }
-```
-
-
-
### FinalizeClassesWithoutChildrenRector
Finalize every class that has no children
@@ -6626,32 +6113,6 @@ return static function (RectorConfig $rectorConfig): void {
-## RemovingStatic
-
-### LocallyCalledStaticMethodToNonStaticRector
-
-Change static method and local-only calls to non-static
-
-- class: [`Rector\RemovingStatic\Rector\ClassMethod\LocallyCalledStaticMethodToNonStaticRector`](../rules/RemovingStatic/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php)
-
-```diff
- class SomeClass
- {
- public function run()
- {
-- self::someStatic();
-+ $this->someStatic();
- }
-
-- private static function someStatic()
-+ private function someStatic()
- {
- }
- }
-```
-
-
-
## Renaming
### PseudoNamespaceToNamespaceRector
@@ -7027,27 +6488,6 @@ return static function (RectorConfig $rectorConfig): void {
## Strict
-### AddConstructorParentCallRector
-
-Fixer for PHPStan reports by strict type rule - "PHPStan\Rules\Classes\RequireParentConstructCallRule"
-
-- class: [`Rector\Strict\Rector\ClassMethod\AddConstructorParentCallRector`](../rules/Strict/Rector/ClassMethod/AddConstructorParentCallRector.php)
-
-```diff
- class SunshineCommand extends ParentClassWithConstructor
- {
-- public function __construct()
-+ public function __construct(ParentDependency $parentDependency)
- {
- $value = 5;
-+
-+ parent::__construct($parentDependency);
- }
- }
-```
-
-
-
### BooleanInBooleanNotRuleFixerRector
Fixer for PHPStan reports by strict type rule - "PHPStan\Rules\BooleansInConditions\BooleanInBooleanNotRule"
@@ -7594,51 +7034,6 @@ return static function (RectorConfig $rectorConfig): void {
-### MethodCallToMethodCallRector
-
-Change method one method from one service to a method call to in another service
-
-:wrench: **configure it!**
-
-- class: [`Rector\Transform\Rector\MethodCall\MethodCallToMethodCallRector`](../rules/Transform/Rector/MethodCall/MethodCallToMethodCallRector.php)
-
-```php
-ruleWithConfiguration(MethodCallToMethodCallRector::class, [
- new MethodCallToMethodCall('FirstDependency', 'go', 'SecondDependency', 'away'),
- ]);
-};
-```
-
-↓
-
-```diff
- class SomeClass
- {
- public function __construct(
-- private FirstDependency $firstDependency
-+ private SecondDependency $secondDependency
- ) {
- }
-
- public function run()
- {
-- $this->firstDependency->go();
-+ $this->secondDependency->away();
- }
- }
-```
-
-
-
### MethodCallToPropertyFetchRector
Turns method call `"$this->something()"` to property fetch "$this->something"
@@ -7723,95 +7118,6 @@ return static function (RectorConfig $rectorConfig): void {
-### NewArgToMethodCallRector
-
-Change new with specific argument to method call
-
-:wrench: **configure it!**
-
-- class: [`Rector\Transform\Rector\New_\NewArgToMethodCallRector`](../rules/Transform/Rector/New_/NewArgToMethodCallRector.php)
-
-```php
-ruleWithConfiguration(NewArgToMethodCallRector::class, [
- new NewArgToMethodCall('Dotenv', true, 'usePutenv'),
- ]);
-};
-```
-
-↓
-
-```diff
- class SomeClass
- {
- public function run()
- {
-- $dotenv = new Dotenv(true);
-+ $dotenv = new Dotenv();
-+ $dotenv->usePutenv();
- }
- }
-```
-
-
-
-### NewToConstructorInjectionRector
-
-Change defined new type to constructor injection
-
-:wrench: **configure it!**
-
-- class: [`Rector\Transform\Rector\New_\NewToConstructorInjectionRector`](../rules/Transform/Rector/New_/NewToConstructorInjectionRector.php)
-
-```php
-ruleWithConfiguration(NewToConstructorInjectionRector::class, [
- 'Validator',
- ]);
-};
-```
-
-↓
-
-```diff
- class SomeClass
- {
-+ /**
-+ * @var Validator
-+ */
-+ private $validator;
-+
-+ public function __construct(Validator $validator)
-+ {
-+ $this->validator = $validator;
-+ }
-+
- public function run()
- {
-- $validator = new Validator();
-- $validator->validate(1000);
-+ $this->validator->validate(1000);
- }
- }
-```
-
-
-
### NewToStaticCallRector
Change new Object to static call
@@ -7965,42 +7271,6 @@ return static function (RectorConfig $rectorConfig): void {
-### RemoveAllowDynamicPropertiesAttributeRector
-
-Remove the `AllowDynamicProperties` attribute from all classes
-
-:wrench: **configure it!**
-
-- class: [`Rector\Transform\Rector\Class_\RemoveAllowDynamicPropertiesAttributeRector`](../rules/Transform/Rector/Class_/RemoveAllowDynamicPropertiesAttributeRector.php)
-
-```php
-ruleWithConfiguration(RemoveAllowDynamicPropertiesAttributeRector::class, [
- 'Example\*',
- ]);
-};
-```
-
-↓
-
-```diff
- namespace Example\Domain;
-
--#[AllowDynamicProperties]
- class SomeObject {
- public string $someProperty = 'hello world';
- }
-```
-
-
-
### ReplaceParentCallByPropertyCallRector
Changes method calls in child of specific types to defined property method call
@@ -8241,42 +7511,6 @@ return static function (RectorConfig $rectorConfig): void {
-### UnsetAndIssetToMethodCallRector
-
-Turns defined `__isset`/`__unset` calls to specific method calls.
-
-:wrench: **configure it!**
-
-- class: [`Rector\Transform\Rector\Isset_\UnsetAndIssetToMethodCallRector`](../rules/Transform/Rector/Isset_/UnsetAndIssetToMethodCallRector.php)
-
-```php
-ruleWithConfiguration(UnsetAndIssetToMethodCallRector::class, [
- new UnsetAndIssetToMethodCall('SomeContainer', 'hasService', 'removeService'),
- ]);
-};
-```
-
-↓
-
-```diff
- $container = new SomeContainer;
--isset($container["someKey"]);
--unset($container["someKey"]);
-+$container->hasService("someKey");
-+$container->removeService("someKey");
-```
-
-
-
### WrapReturnRector
Wrap return value of specific method
@@ -8764,6 +7998,25 @@ Flip negated ternary of instanceof to direct use of object
+### NumericReturnTypeFromStrictScalarReturnsRector
+
+Change numeric return type based on strict returns type operations
+
+- class: [`Rector\TypeDeclaration\Rector\ClassMethod\NumericReturnTypeFromStrictScalarReturnsRector`](../rules/TypeDeclaration/Rector/ClassMethod/NumericReturnTypeFromStrictScalarReturnsRector.php)
+
+```diff
+ class SomeClass
+ {
+- public function resolve(int $first, int $second)
++ public function resolve(int $first, int $second): int
+ {
+ return $first - $second;
+ }
+ }
+```
+
+
+
### ParamAnnotationIncorrectNullableRector
Add or remove null type from `@param` phpdoc typehint based on php parameter type declaration
diff --git a/e2e/finalize/composer.json b/e2e/finalize/composer.json
deleted file mode 100644
index cebce1733e6e..000000000000
--- a/e2e/finalize/composer.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "autoload": {
- "psr-4": {
- "Rector\\e2e\\": "src"
- }
- },
- "require-dev": {
- "doctrine/orm": "^2.7"
- }
-}
diff --git a/e2e/finalize/rector.php b/e2e/finalize/rector.php
deleted file mode 100644
index fc2e8cae58a1..000000000000
--- a/e2e/finalize/rector.php
+++ /dev/null
@@ -1,11 +0,0 @@
-services();
- $services->set(FinalizeClassesWithoutChildrenRector::class);
-};
diff --git a/e2e/finalize/src/SkipSomeEntity.php b/e2e/finalize/src/SkipSomeEntity.php
deleted file mode 100644
index 11baf123becb..000000000000
--- a/e2e/finalize/src/SkipSomeEntity.php
+++ /dev/null
@@ -1,14 +0,0 @@
-paths([__DIR__ . '/src/']);
- $services = $rectorConfig->services();
- $services->set(MakeInheritedMethodVisibilitySameAsParentRector::class);
+ $rectorConfig->rule(MakeInheritedMethodVisibilitySameAsParentRector::class);
};
diff --git a/packages/BetterPhpDocParser/PhpDoc/ArrayItemNode.php b/packages/BetterPhpDocParser/PhpDoc/ArrayItemNode.php
index c80b8531d02c..6cac2fcd5430 100644
--- a/packages/BetterPhpDocParser/PhpDoc/ArrayItemNode.php
+++ b/packages/BetterPhpDocParser/PhpDoc/ArrayItemNode.php
@@ -3,13 +3,11 @@
declare (strict_types=1);
namespace Rector\BetterPhpDocParser\PhpDoc;
-use PhpParser\Node\Scalar\String_;
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use Stringable;
final class ArrayItemNode implements PhpDocTagValueNode
{
- use NodeAttributes;
/**
* @var mixed
*/
@@ -17,39 +15,24 @@ final class ArrayItemNode implements PhpDocTagValueNode
/**
* @var mixed
*/
- public $key;
- /**
- * @var String_::KIND_*|null
- */
- public $kindValueQuoted = null;
- /**
- * @var int|null
- */
- public $kindKeyQuoted = null;
+ public $key = null;
+ use NodeAttributes;
/**
- * @param String_::KIND_*|null $kindValueQuoted
* @param mixed $value
* @param mixed $key
*/
- public function __construct($value, $key, ?int $kindValueQuoted = null, ?int $kindKeyQuoted = null)
+ public function __construct($value, $key = null)
{
$this->value = $value;
$this->key = $key;
- $this->kindValueQuoted = $kindValueQuoted;
- $this->kindKeyQuoted = $kindKeyQuoted;
}
public function __toString() : string
{
$value = '';
- if ($this->kindKeyQuoted === String_::KIND_DOUBLE_QUOTED) {
- $value .= '"' . $this->key . '" = ';
- } elseif ($this->key !== null) {
+ if ($this->key !== null) {
$value .= $this->key . '=';
}
- // @todo depends on the context! possibly the top array is quting this stinrg already
- if ($this->kindValueQuoted === String_::KIND_DOUBLE_QUOTED) {
- $value .= '"' . $this->value . '"';
- } elseif (\is_array($this->value)) {
+ if (\is_array($this->value)) {
foreach ($this->value as $singleValue) {
$value .= $singleValue;
}
diff --git a/packages/BetterPhpDocParser/PhpDoc/StringNode.php b/packages/BetterPhpDocParser/PhpDoc/StringNode.php
new file mode 100644
index 000000000000..9f34973c8677
--- /dev/null
+++ b/packages/BetterPhpDocParser/PhpDoc/StringNode.php
@@ -0,0 +1,33 @@
+value = $value;
+ $this->value = \str_replace('""', '"', $this->value);
+ if (\strpos($this->value, "'") !== \false && \strpos($this->value, "\n") === \false) {
+ $kind = String_::KIND_DOUBLE_QUOTED;
+ } else {
+ $kind = String_::KIND_SINGLE_QUOTED;
+ }
+ $this->setAttribute(AttributeKey::KIND, $kind);
+ }
+ public function __toString() : string
+ {
+ return '"' . \str_replace('"', '""', $this->value) . '"';
+ }
+}
diff --git a/packages/BetterPhpDocParser/PhpDocInfo/PhpDocInfo.php b/packages/BetterPhpDocParser/PhpDocInfo/PhpDocInfo.php
index e51f2fd27468..4c989a0a8c45 100644
--- a/packages/BetterPhpDocParser/PhpDocInfo/PhpDocInfo.php
+++ b/packages/BetterPhpDocParser/PhpDocInfo/PhpDocInfo.php
@@ -39,23 +39,6 @@
*/
final class PhpDocInfo
{
- /**
- * @var array, string>
- */
- private const TAGS_TYPES_TO_NAMES = [ReturnTagValueNode::class => '@return', ParamTagValueNode::class => '@param', VarTagValueNode::class => '@var', MethodTagValueNode::class => '@method', PropertyTagValueNode::class => '@property'];
- /**
- * @var bool
- */
- private $isSingleLine = \false;
- /**
- * @readonly
- * @var \PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode
- */
- private $originalPhpDocNode;
- /**
- * @var bool
- */
- private $hasChanged = \false;
/**
* @readonly
* @var \PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode
@@ -96,6 +79,23 @@ final class PhpDocInfo
* @var \Rector\BetterPhpDocParser\PhpDocNodeFinder\PhpDocNodeByTypeFinder
*/
private $phpDocNodeByTypeFinder;
+ /**
+ * @var array, string>
+ */
+ private const TAGS_TYPES_TO_NAMES = [ReturnTagValueNode::class => '@return', ParamTagValueNode::class => '@param', VarTagValueNode::class => '@var', MethodTagValueNode::class => '@method', PropertyTagValueNode::class => '@property'];
+ /**
+ * @var bool
+ */
+ private $isSingleLine = \false;
+ /**
+ * @readonly
+ * @var \PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode
+ */
+ private $originalPhpDocNode;
+ /**
+ * @var bool
+ */
+ private $hasChanged = \false;
public function __construct(PhpDocNode $phpDocNode, BetterTokenIterator $betterTokenIterator, StaticTypeMapper $staticTypeMapper, \PhpParser\Node $node, AnnotationNaming $annotationNaming, CurrentNodeProvider $currentNodeProvider, RectorChangeCollector $rectorChangeCollector, PhpDocNodeByTypeFinder $phpDocNodeByTypeFinder)
{
$this->phpDocNode = $phpDocNode;
@@ -158,7 +158,6 @@ public function getTagsByName(string $name) : array
$tags = \array_filter($tags, static function (PhpDocTagNode $phpDocTagNode) use($name) : bool {
return $phpDocTagNode->name === $name;
});
- $tags = \array_values($tags);
return \array_values($tags);
}
public function getParamType(string $name) : Type
@@ -236,6 +235,9 @@ public function getByAnnotationClass(string $class) : ?DoctrineAnnotationTagValu
$doctrineAnnotationTagValueNodes = $this->phpDocNodeByTypeFinder->findDoctrineAnnotationsByClass($this->phpDocNode, $class);
return $doctrineAnnotationTagValueNodes[0] ?? null;
}
+ /**
+ * @api used in tests
+ */
public function hasByAnnotationClass(string $class) : bool
{
return $this->findByAnnotationClass($class) !== [];
@@ -247,20 +249,6 @@ public function hasByAnnotationClasses(array $annotationsClasses) : bool
{
return $this->getByAnnotationClasses($annotationsClasses) instanceof DoctrineAnnotationTagValueNode;
}
- /**
- * @param string[] $desiredClasses
- */
- public function findOneByAnnotationClasses(array $desiredClasses) : ?DoctrineAnnotationTagValueNode
- {
- foreach ($desiredClasses as $desiredClass) {
- $doctrineAnnotationTagValueNode = $this->findOneByAnnotationClass($desiredClass);
- if (!$doctrineAnnotationTagValueNode instanceof DoctrineAnnotationTagValueNode) {
- continue;
- }
- return $doctrineAnnotationTagValueNode;
- }
- return null;
- }
public function findOneByAnnotationClass(string $desiredClass) : ?DoctrineAnnotationTagValueNode
{
$foundTagValueNodes = $this->findByAnnotationClass($desiredClass);
diff --git a/packages/BetterPhpDocParser/PhpDocInfo/PhpDocInfoFactory.php b/packages/BetterPhpDocParser/PhpDocInfo/PhpDocInfoFactory.php
index 06e23fe94fa8..922da2d64876 100644
--- a/packages/BetterPhpDocParser/PhpDocInfo/PhpDocInfoFactory.php
+++ b/packages/BetterPhpDocParser/PhpDocInfo/PhpDocInfoFactory.php
@@ -21,10 +21,6 @@
use Rector\StaticTypeMapper\StaticTypeMapper;
final class PhpDocInfoFactory
{
- /**
- * @var array
- */
- private $phpDocInfosByObjectHash = [];
/**
* @readonly
* @var \Rector\BetterPhpDocParser\PhpDocNodeMapper
@@ -65,6 +61,10 @@ final class PhpDocInfoFactory
* @var \Rector\BetterPhpDocParser\PhpDocNodeFinder\PhpDocNodeByTypeFinder
*/
private $phpDocNodeByTypeFinder;
+ /**
+ * @var array
+ */
+ private $phpDocInfosByObjectHash = [];
public function __construct(PhpDocNodeMapper $phpDocNodeMapper, CurrentNodeProvider $currentNodeProvider, Lexer $lexer, BetterPhpDocParser $betterPhpDocParser, StaticTypeMapper $staticTypeMapper, AnnotationNaming $annotationNaming, RectorChangeCollector $rectorChangeCollector, PhpDocNodeByTypeFinder $phpDocNodeByTypeFinder)
{
$this->phpDocNodeMapper = $phpDocNodeMapper;
diff --git a/packages/BetterPhpDocParser/PhpDocInfo/TokenIteratorFactory.php b/packages/BetterPhpDocParser/PhpDocInfo/TokenIteratorFactory.php
index 75b214df5aa5..01b0cfa11a26 100644
--- a/packages/BetterPhpDocParser/PhpDocInfo/TokenIteratorFactory.php
+++ b/packages/BetterPhpDocParser/PhpDocInfo/TokenIteratorFactory.php
@@ -9,10 +9,6 @@
use Rector\Core\Util\Reflection\PrivatesAccessor;
final class TokenIteratorFactory
{
- /**
- * @var string
- */
- private const INDEX = 'index';
/**
* @readonly
* @var \PHPStan\PhpDocParser\Lexer\Lexer
@@ -23,6 +19,10 @@ final class TokenIteratorFactory
* @var \Rector\Core\Util\Reflection\PrivatesAccessor
*/
private $privatesAccessor;
+ /**
+ * @var string
+ */
+ private const INDEX = 'index';
public function __construct(Lexer $lexer, PrivatesAccessor $privatesAccessor)
{
$this->lexer = $lexer;
diff --git a/packages/BetterPhpDocParser/PhpDocManipulator/PhpDocClassRenamer.php b/packages/BetterPhpDocParser/PhpDocManipulator/PhpDocClassRenamer.php
index 1448acf7520b..3a8b509dda25 100644
--- a/packages/BetterPhpDocParser/PhpDocManipulator/PhpDocClassRenamer.php
+++ b/packages/BetterPhpDocParser/PhpDocManipulator/PhpDocClassRenamer.php
@@ -7,6 +7,7 @@
use PhpParser\Node;
use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
+use Rector\BetterPhpDocParser\PhpDoc\StringNode;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocParser\ClassAnnotationMatcher;
use Rector\BetterPhpDocParser\ValueObject\PhpDoc\DoctrineAnnotation\CurlyListNode;
@@ -54,11 +55,15 @@ private function processAssertChoiceTagValueNode(array $oldToNewClasses, PhpDocI
}
$callableCallbackArrayItems = $callbackClass->getValues();
$classNameArrayItemNode = $callableCallbackArrayItems[0];
+ $classNameStringNode = $classNameArrayItemNode->value;
+ if (!$classNameStringNode instanceof StringNode) {
+ return;
+ }
foreach ($oldToNewClasses as $oldClass => $newClass) {
- if ($classNameArrayItemNode->value !== $oldClass) {
+ if ($classNameStringNode->value !== $oldClass) {
continue;
}
- $classNameArrayItemNode->value = $newClass;
+ $classNameStringNode->value = $newClass;
// trigger reprint
$classNameArrayItemNode->setAttribute(PhpDocAttributeKey::ORIG_NODE, null);
break;
@@ -86,20 +91,25 @@ private function processSerializerTypeTagValueNode(array $oldToNewClasses, PhpDo
}
$classNameArrayItemNode = $doctrineAnnotationTagValueNode->getSilentValue();
foreach ($oldToNewClasses as $oldClass => $newClass) {
- if ($classNameArrayItemNode instanceof ArrayItemNode) {
- if ($classNameArrayItemNode->value === $oldClass) {
- $classNameArrayItemNode->value = $newClass;
+ if ($classNameArrayItemNode instanceof ArrayItemNode && $classNameArrayItemNode->value instanceof StringNode) {
+ $classNameStringNode = $classNameArrayItemNode->value;
+ if ($classNameStringNode->value === $oldClass) {
+ $classNameStringNode->value = $newClass;
continue;
}
- $classNameArrayItemNode->value = Strings::replace($classNameArrayItemNode->value, '#\\b' . \preg_quote($oldClass, '#') . '\\b#', $newClass);
+ $classNameStringNode->value = Strings::replace($classNameStringNode->value, '#\\b' . \preg_quote($oldClass, '#') . '\\b#', $newClass);
$classNameArrayItemNode->setAttribute(PhpDocAttributeKey::ORIG_NODE, null);
}
$currentTypeArrayItemNode = $doctrineAnnotationTagValueNode->getValue('type');
if (!$currentTypeArrayItemNode instanceof ArrayItemNode) {
continue;
}
- if ($currentTypeArrayItemNode->value === $oldClass) {
- $currentTypeArrayItemNode->value = $newClass;
+ $currentTypeStringNode = $currentTypeArrayItemNode->value;
+ if (!$currentTypeStringNode instanceof StringNode) {
+ continue;
+ }
+ if ($currentTypeStringNode->value === $oldClass) {
+ $currentTypeStringNode->value = $newClass;
}
}
}
@@ -113,14 +123,18 @@ private function processDoctrineToMany(DoctrineAnnotationTagValueNode $doctrineA
if (!$targetEntityArrayItemNode instanceof ArrayItemNode) {
return;
}
- $targetEntityClass = $targetEntityArrayItemNode->value;
+ $targetEntityStringNode = $targetEntityArrayItemNode->value;
+ if (!$targetEntityStringNode instanceof StringNode) {
+ return;
+ }
+ $targetEntityClass = $targetEntityStringNode->value;
// resolve to FQN
$tagFullyQualifiedName = $this->classAnnotationMatcher->resolveTagFullyQualifiedName($targetEntityClass, $node);
foreach ($oldToNewClasses as $oldClass => $newClass) {
if ($tagFullyQualifiedName !== $oldClass) {
continue;
}
- $targetEntityArrayItemNode->value = $newClass;
+ $targetEntityStringNode->value = $newClass;
$targetEntityArrayItemNode->setAttribute(PhpDocAttributeKey::ORIG_NODE, null);
}
}
diff --git a/packages/BetterPhpDocParser/PhpDocManipulator/PhpDocTypeChanger.php b/packages/BetterPhpDocParser/PhpDocManipulator/PhpDocTypeChanger.php
index 0f5ed5b72403..ce579da1ba2e 100644
--- a/packages/BetterPhpDocParser/PhpDocManipulator/PhpDocTypeChanger.php
+++ b/packages/BetterPhpDocParser/PhpDocManipulator/PhpDocTypeChanger.php
@@ -3,7 +3,9 @@
declare (strict_types=1);
namespace Rector\BetterPhpDocParser\PhpDocManipulator;
+use PhpParser\Node\FunctionLike;
use PhpParser\Node\Param;
+use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstFetchNode;
@@ -28,22 +30,14 @@
use Rector\BetterPhpDocParser\ValueObject\Type\BracketsAwareUnionTypeNode;
use Rector\BetterPhpDocParser\ValueObject\Type\SpacingAwareArrayTypeNode;
use Rector\BetterPhpDocParser\ValueObject\Type\SpacingAwareCallableTypeNode;
+use Rector\Comments\NodeDocBlock\DocBlockUpdater;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\TypeComparator\TypeComparator;
-use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Rector\TypeDeclaration\PhpDocParser\ParamPhpDocNodeFactory;
final class PhpDocTypeChanger
{
- /**
- * @var array>
- */
- private const ALLOWED_TYPES = [GenericTypeNode::class, SpacingAwareArrayTypeNode::class, SpacingAwareCallableTypeNode::class, ArrayShapeNode::class];
- /**
- * @var string[]
- */
- private const ALLOWED_IDENTIFIER_TYPENODE_TYPES = ['class-string'];
/**
* @readonly
* @var \Rector\StaticTypeMapper\StaticTypeMapper
@@ -79,7 +73,20 @@ final class PhpDocTypeChanger
* @var \Rector\BetterPhpDocParser\Guard\NewPhpDocFromPHPStanTypeGuard
*/
private $newPhpDocFromPHPStanTypeGuard;
- public function __construct(StaticTypeMapper $staticTypeMapper, TypeComparator $typeComparator, ParamPhpDocNodeFactory $paramPhpDocNodeFactory, NodeNameResolver $nodeNameResolver, CommentsMerger $commentsMerger, PhpDocInfoFactory $phpDocInfoFactory, NewPhpDocFromPHPStanTypeGuard $newPhpDocFromPHPStanTypeGuard)
+ /**
+ * @readonly
+ * @var \Rector\Comments\NodeDocBlock\DocBlockUpdater
+ */
+ private $docBlockUpdater;
+ /**
+ * @var array>
+ */
+ private const ALLOWED_TYPES = [GenericTypeNode::class, SpacingAwareArrayTypeNode::class, SpacingAwareCallableTypeNode::class, ArrayShapeNode::class];
+ /**
+ * @var string[]
+ */
+ private const ALLOWED_IDENTIFIER_TYPENODE_TYPES = ['class-string'];
+ public function __construct(StaticTypeMapper $staticTypeMapper, TypeComparator $typeComparator, ParamPhpDocNodeFactory $paramPhpDocNodeFactory, NodeNameResolver $nodeNameResolver, CommentsMerger $commentsMerger, PhpDocInfoFactory $phpDocInfoFactory, NewPhpDocFromPHPStanTypeGuard $newPhpDocFromPHPStanTypeGuard, DocBlockUpdater $docBlockUpdater)
{
$this->staticTypeMapper = $staticTypeMapper;
$this->typeComparator = $typeComparator;
@@ -88,8 +95,9 @@ public function __construct(StaticTypeMapper $staticTypeMapper, TypeComparator $
$this->commentsMerger = $commentsMerger;
$this->phpDocInfoFactory = $phpDocInfoFactory;
$this->newPhpDocFromPHPStanTypeGuard = $newPhpDocFromPHPStanTypeGuard;
+ $this->docBlockUpdater = $docBlockUpdater;
}
- public function changeVarType(PhpDocInfo $phpDocInfo, Type $newType) : void
+ public function changeVarType(Stmt $stmt, PhpDocInfo $phpDocInfo, Type $newType) : void
{
// better skip, could crash hard
if ($phpDocInfo->hasInvalidTag('@var')) {
@@ -107,7 +115,7 @@ public function changeVarType(PhpDocInfo $phpDocInfo, Type $newType) : void
return;
}
// override existing type
- $newPHPStanPhpDocTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType, TypeKind::PROPERTY);
+ $newPHPStanPhpDocTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType);
$currentVarTagValueNode = $phpDocInfo->getVarTagValueNode();
if ($currentVarTagValueNode instanceof VarTagValueNode) {
// only change type
@@ -118,8 +126,9 @@ public function changeVarType(PhpDocInfo $phpDocInfo, Type $newType) : void
$varTagValueNode = new VarTagValueNode($newPHPStanPhpDocTypeNode, '', '');
$phpDocInfo->addTagValueNode($varTagValueNode);
}
+ $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($stmt);
}
- public function changeReturnType(PhpDocInfo $phpDocInfo, Type $newType) : bool
+ public function changeReturnType(FunctionLike $functionLike, PhpDocInfo $phpDocInfo, Type $newType) : bool
{
// better not touch this, can crash
if ($phpDocInfo->hasInvalidTag('@return')) {
@@ -133,7 +142,7 @@ public function changeReturnType(PhpDocInfo $phpDocInfo, Type $newType) : bool
return \false;
}
// override existing type
- $newPHPStanPhpDocTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType, TypeKind::RETURN);
+ $newPHPStanPhpDocTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType);
$currentReturnTagValueNode = $phpDocInfo->getReturnTagValue();
if ($currentReturnTagValueNode instanceof ReturnTagValueNode) {
// only change type
@@ -144,9 +153,10 @@ public function changeReturnType(PhpDocInfo $phpDocInfo, Type $newType) : bool
$returnTagValueNode = new ReturnTagValueNode($newPHPStanPhpDocTypeNode, '');
$phpDocInfo->addTagValueNode($returnTagValueNode);
}
+ $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($functionLike);
return \true;
}
- public function changeParamType(PhpDocInfo $phpDocInfo, Type $newType, Param $param, string $paramName) : void
+ public function changeParamType(FunctionLike $functionLike, PhpDocInfo $phpDocInfo, Type $newType, Param $param, string $paramName) : void
{
// better skip, could crash hard
if ($phpDocInfo->hasInvalidTag('@param')) {
@@ -155,7 +165,7 @@ public function changeParamType(PhpDocInfo $phpDocInfo, Type $newType, Param $pa
if (!$this->newPhpDocFromPHPStanTypeGuard->isLegal($newType)) {
return;
}
- $phpDocTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType, TypeKind::PARAM);
+ $phpDocTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType);
$paramTagValueNode = $phpDocInfo->getParamTagValueByName($paramName);
// override existing type
if ($paramTagValueNode instanceof ParamTagValueNode) {
@@ -174,6 +184,7 @@ public function changeParamType(PhpDocInfo $phpDocInfo, Type $newType, Param $pa
$paramTagValueNode = $this->paramPhpDocNodeFactory->create($phpDocTypeNode, $param);
$phpDocInfo->addTagValueNode($paramTagValueNode);
}
+ $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($functionLike);
}
public function isAllowed(TypeNode $typeNode) : bool
{
@@ -203,7 +214,7 @@ public function copyPropertyDocToParam(ClassMethod $classMethod, Property $prope
}
$varTagValueNode = $phpDocInfo->getVarTagValueNode();
if (!$varTagValueNode instanceof VarTagValueNode) {
- $this->processKeepComments($property, $param);
+ $this->processKeepComments($classMethod, $property, $param);
return;
}
if ($varTagValueNode->description !== '') {
@@ -217,27 +228,30 @@ public function copyPropertyDocToParam(ClassMethod $classMethod, Property $prope
return;
}
$phpDocInfo->removeByType(VarTagValueNode::class);
+ $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($property);
$param->setAttribute(AttributeKey::PHP_DOC_INFO, $phpDocInfo);
$phpDocInfo = $classMethod->getAttribute(AttributeKey::PHP_DOC_INFO);
$paramType = $this->staticTypeMapper->mapPHPStanPhpDocTypeToPHPStanType($varTagValueNode, $property);
- $this->changeParamType($phpDocInfo, $paramType, $param, $paramVarName);
- $this->processKeepComments($property, $param);
+ $this->changeParamType($classMethod, $phpDocInfo, $paramType, $param, $paramVarName);
+ $this->processKeepComments($classMethod, $property, $param);
}
/**
* @api doctrine
*/
- public function changeVarTypeNode(PhpDocInfo $phpDocInfo, TypeNode $typeNode) : void
+ public function changeVarTypeNode(Stmt $stmt, PhpDocInfo $phpDocInfo, TypeNode $typeNode) : void
{
// add completely new one
$varTagValueNode = new VarTagValueNode($typeNode, '', '');
$phpDocInfo->addTagValueNode($varTagValueNode);
+ $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($stmt);
}
- private function processKeepComments(Property $property, Param $param) : void
+ private function processKeepComments(ClassMethod $classMethod, Property $property, Param $param) : void
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($param);
$varTagValueNode = $phpDocInfo->getVarTagValueNode();
$toBeRemoved = !$varTagValueNode instanceof VarTagValueNode;
$this->commentsMerger->keepComments($param, [$property]);
+ $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($classMethod);
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($param);
$varTagValueNode = $phpDocInfo->getVarTagValueNode();
if (!$toBeRemoved) {
@@ -250,5 +264,6 @@ private function processKeepComments(Property $property, Param $param) : void
return;
}
$phpDocInfo->removeByType(VarTagValueNode::class);
+ $this->docBlockUpdater->updateRefactoredNodeWithPhpDocInfo($classMethod);
}
}
diff --git a/packages/BetterPhpDocParser/PhpDocNodeMapper.php b/packages/BetterPhpDocParser/PhpDocNodeMapper.php
index 1158b58ee155..7e44f3ba6878 100644
--- a/packages/BetterPhpDocParser/PhpDocNodeMapper.php
+++ b/packages/BetterPhpDocParser/PhpDocNodeMapper.php
@@ -38,7 +38,7 @@ final class PhpDocNodeMapper
/**
* @param BasePhpDocNodeVisitorInterface[] $phpDocNodeVisitors
*/
- public function __construct(CurrentTokenIteratorProvider $currentTokenIteratorProvider, ParentConnectingPhpDocNodeVisitor $parentConnectingPhpDocNodeVisitor, CloningPhpDocNodeVisitor $cloningPhpDocNodeVisitor, array $phpDocNodeVisitors)
+ public function __construct(CurrentTokenIteratorProvider $currentTokenIteratorProvider, ParentConnectingPhpDocNodeVisitor $parentConnectingPhpDocNodeVisitor, CloningPhpDocNodeVisitor $cloningPhpDocNodeVisitor, iterable $phpDocNodeVisitors)
{
$this->currentTokenIteratorProvider = $currentTokenIteratorProvider;
$this->parentConnectingPhpDocNodeVisitor = $parentConnectingPhpDocNodeVisitor;
diff --git a/packages/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php b/packages/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php
index 69ad12b86879..7ac7df77dc20 100644
--- a/packages/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php
+++ b/packages/BetterPhpDocParser/PhpDocParser/BetterPhpDocParser.php
@@ -50,7 +50,7 @@ final class BetterPhpDocParser extends PhpDocParser
/**
* @param PhpDocNodeDecoratorInterface[] $phpDocNodeDecorators
*/
- public function __construct(TypeParser $typeParser, ConstExprParser $constExprParser, CurrentNodeProvider $currentNodeProvider, TokenIteratorFactory $tokenIteratorFactory, array $phpDocNodeDecorators, PrivatesAccessor $privatesAccessor = null)
+ public function __construct(TypeParser $typeParser, ConstExprParser $constExprParser, CurrentNodeProvider $currentNodeProvider, TokenIteratorFactory $tokenIteratorFactory, iterable $phpDocNodeDecorators, PrivatesAccessor $privatesAccessor = null)
{
$privatesAccessor = $privatesAccessor ?? new PrivatesAccessor();
$this->currentNodeProvider = $currentNodeProvider;
diff --git a/packages/BetterPhpDocParser/PhpDocParser/ClassAnnotationMatcher.php b/packages/BetterPhpDocParser/PhpDocParser/ClassAnnotationMatcher.php
index d97634061f6b..6e500dd3d0e0 100644
--- a/packages/BetterPhpDocParser/PhpDocParser/ClassAnnotationMatcher.php
+++ b/packages/BetterPhpDocParser/PhpDocParser/ClassAnnotationMatcher.php
@@ -18,10 +18,6 @@
*/
final class ClassAnnotationMatcher
{
- /**
- * @var array
- */
- private $fullyQualifiedNameByHash = [];
/**
* @readonly
* @var \Rector\CodingStyle\NodeAnalyzer\UseImportNameMatcher
@@ -37,6 +33,10 @@ final class ClassAnnotationMatcher
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @var array
+ */
+ private $fullyQualifiedNameByHash = [];
public function __construct(UseImportNameMatcher $useImportNameMatcher, UseImportsResolver $useImportsResolver, ReflectionProvider $reflectionProvider)
{
$this->useImportNameMatcher = $useImportNameMatcher;
@@ -61,7 +61,7 @@ private function _resolveTagFullyQualifiedName(string $tag, Node $node, bool $re
return $this->fullyQualifiedNameByHash[$uniqueHash];
}
$tag = \ltrim($tag, '@');
- $uses = $this->useImportsResolver->resolveForNode($node);
+ $uses = $this->useImportsResolver->resolve();
$fullyQualifiedClass = $this->resolveFullyQualifiedClass($uses, $node, $tag, $returnNullOnUnknownClass);
if ($fullyQualifiedClass === null) {
if ($returnNullOnUnknownClass) {
diff --git a/packages/BetterPhpDocParser/PhpDocParser/DoctrineAnnotationDecorator.php b/packages/BetterPhpDocParser/PhpDocParser/DoctrineAnnotationDecorator.php
index cab0be4e292e..44b6ec155c9b 100644
--- a/packages/BetterPhpDocParser/PhpDocParser/DoctrineAnnotationDecorator.php
+++ b/packages/BetterPhpDocParser/PhpDocParser/DoctrineAnnotationDecorator.php
@@ -23,21 +23,6 @@
use Rector\Core\Util\StringUtils;
final class DoctrineAnnotationDecorator implements PhpDocNodeDecoratorInterface
{
- /**
- * Special short annotations, that are resolved as FQN by Doctrine annotation parser
- * @var string[]
- */
- private const ALLOWED_SHORT_ANNOTATIONS = ['Target'];
- /**
- * @see https://regex101.com/r/95kIw4/1
- * @var string
- */
- private const LONG_ANNOTATION_REGEX = '#@\\\\(?.*?)(?\\(.*?\\))#';
- /**
- * @see https://regex101.com/r/xWaLOz/1
- * @var string
- */
- private const NESTED_ANNOTATION_END_REGEX = '#(\\s+)?\\}\\)(\\s+)?#';
/**
* @readonly
* @var \Rector\BetterPhpDocParser\PhpDocParser\ClassAnnotationMatcher
@@ -58,6 +43,21 @@ final class DoctrineAnnotationDecorator implements PhpDocNodeDecoratorInterface
* @var \Rector\BetterPhpDocParser\Attributes\AttributeMirrorer
*/
private $attributeMirrorer;
+ /**
+ * Special short annotations, that are resolved as FQN by Doctrine annotation parser
+ * @var string[]
+ */
+ private const ALLOWED_SHORT_ANNOTATIONS = ['Target'];
+ /**
+ * @see https://regex101.com/r/95kIw4/1
+ * @var string
+ */
+ private const LONG_ANNOTATION_REGEX = '#@\\\\(?.*?)(?\\(.*?\\))#';
+ /**
+ * @see https://regex101.com/r/xWaLOz/1
+ * @var string
+ */
+ private const NESTED_ANNOTATION_END_REGEX = '#(\\s+)?\\}\\)(\\s+)?#';
public function __construct(\Rector\BetterPhpDocParser\PhpDocParser\ClassAnnotationMatcher $classAnnotationMatcher, \Rector\BetterPhpDocParser\PhpDocParser\StaticDoctrineAnnotationParser $staticDoctrineAnnotationParser, TokenIteratorFactory $tokenIteratorFactory, AttributeMirrorer $attributeMirrorer)
{
$this->classAnnotationMatcher = $classAnnotationMatcher;
diff --git a/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser.php b/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser.php
index e1f9e1c30ba0..68b00aa8dd2e 100644
--- a/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser.php
+++ b/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser.php
@@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Lexer\Lexer;
use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
+use Rector\BetterPhpDocParser\PhpDoc\StringNode;
use Rector\BetterPhpDocParser\PhpDocParser\StaticDoctrineAnnotationParser\ArrayParser;
use Rector\BetterPhpDocParser\PhpDocParser\StaticDoctrineAnnotationParser\PlainValueParser;
use Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator;
@@ -52,7 +53,7 @@ public function resolveAnnotationMethodCall(BetterTokenIterator $tokenIterator)
/**
* @api tests
* @see https://github.com/doctrine/annotations/blob/c66f06b7c83e9a2a7523351a9d5a4b55f885e574/lib/Doctrine/Common/Annotations/DocParser.php#L1215-L1224
- * @return CurlyListNode|string|array|ConstExprNode|DoctrineAnnotationTagValueNode
+ * @return CurlyListNode|string|array|ConstExprNode|DoctrineAnnotationTagValueNode|StringNode
*/
public function resolveAnnotationValue(BetterTokenIterator $tokenIterator)
{
@@ -107,7 +108,7 @@ private function resolveAnnotationValues(BetterTokenIterator $tokenIterator) : a
return $this->arrayParser->createArrayFromValues($values);
}
/**
- * @return CurlyListNode|string|array|ConstExprNode|DoctrineAnnotationTagValueNode
+ * @return CurlyListNode|string|array|ConstExprNode|DoctrineAnnotationTagValueNode|StringNode
*/
private function parseValue(BetterTokenIterator $tokenIterator)
{
diff --git a/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser/ArrayParser.php b/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser/ArrayParser.php
index 096f8d2b13c5..1b6643d46442 100644
--- a/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser/ArrayParser.php
+++ b/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser/ArrayParser.php
@@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
+use Rector\BetterPhpDocParser\PhpDoc\StringNode;
use Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator;
/**
* @see \Rector\Tests\BetterPhpDocParser\PhpDocParser\StaticDoctrineAnnotationParser\ArrayParserTest
@@ -143,25 +144,29 @@ private function resolveQuoteKind($val) : ?int
return null;
}
/**
- * @param mixed $key
- * @param mixed $value
+ * @param mixed $rawKey
+ * @param mixed $rawValue
*/
- private function createArrayItemFromKeyAndValue($key, $value) : ArrayItemNode
+ private function createArrayItemFromKeyAndValue($rawKey, $rawValue) : ArrayItemNode
{
- $valueQuoteKind = $this->resolveQuoteKind($value);
- if (\is_string($value) && $valueQuoteKind === String_::KIND_DOUBLE_QUOTED) {
+ $valueQuoteKind = $this->resolveQuoteKind($rawValue);
+ if (\is_string($rawValue) && $valueQuoteKind === String_::KIND_DOUBLE_QUOTED) {
// give raw value
- $value = \trim($value, '"');
+ $value = new StringNode(\substr($rawValue, 1, \strlen($rawValue) - 2));
+ } else {
+ $value = $rawValue;
}
- $keyQuoteKind = $this->resolveQuoteKind($key);
- if (\is_string($key) && $keyQuoteKind === String_::KIND_DOUBLE_QUOTED) {
+ $keyQuoteKind = $this->resolveQuoteKind($rawKey);
+ if (\is_string($rawKey) && $keyQuoteKind === String_::KIND_DOUBLE_QUOTED) {
// give raw value
- $key = \trim($key, '"');
+ $key = new StringNode(\substr($rawKey, 1, \strlen($rawKey) - 2));
+ } else {
+ $key = $rawKey;
}
if ($key !== null) {
- return new ArrayItemNode($value, $key, $valueQuoteKind, $keyQuoteKind);
+ return new ArrayItemNode($value, $key);
}
- return new ArrayItemNode($value, null, $valueQuoteKind, $keyQuoteKind);
+ return new ArrayItemNode($value);
}
/**
* @param mixed $value
diff --git a/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser/PlainValueParser.php b/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser/PlainValueParser.php
index e19458e136d9..ddcfb85c1c87 100644
--- a/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser/PlainValueParser.php
+++ b/packages/BetterPhpDocParser/PhpDocParser/StaticDoctrineAnnotationParser/PlainValueParser.php
@@ -11,6 +11,7 @@
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
+use Rector\BetterPhpDocParser\PhpDoc\StringNode;
use Rector\BetterPhpDocParser\PhpDocParser\ClassAnnotationMatcher;
use Rector\BetterPhpDocParser\PhpDocParser\StaticDoctrineAnnotationParser;
use Rector\BetterPhpDocParser\ValueObject\Parser\BetterTokenIterator;
@@ -20,14 +21,6 @@
use RectorPrefix202306\Symfony\Contracts\Service\Attribute\Required;
final class PlainValueParser
{
- /**
- * @var \Rector\BetterPhpDocParser\PhpDocParser\StaticDoctrineAnnotationParser
- */
- private $staticDoctrineAnnotationParser;
- /**
- * @var \Rector\BetterPhpDocParser\PhpDocParser\StaticDoctrineAnnotationParser\ArrayParser
- */
- private $arrayParser;
/**
* @readonly
* @var \Rector\BetterPhpDocParser\PhpDocParser\ClassAnnotationMatcher
@@ -38,6 +31,14 @@ final class PlainValueParser
* @var \Rector\Core\Configuration\CurrentNodeProvider
*/
private $currentNodeProvider;
+ /**
+ * @var \Rector\BetterPhpDocParser\PhpDocParser\StaticDoctrineAnnotationParser
+ */
+ private $staticDoctrineAnnotationParser;
+ /**
+ * @var \Rector\BetterPhpDocParser\PhpDocParser\StaticDoctrineAnnotationParser\ArrayParser
+ */
+ private $arrayParser;
public function __construct(ClassAnnotationMatcher $classAnnotationMatcher, CurrentNodeProvider $currentNodeProvider)
{
$this->classAnnotationMatcher = $classAnnotationMatcher;
@@ -52,7 +53,7 @@ public function autowire(StaticDoctrineAnnotationParser $staticDoctrineAnnotatio
$this->arrayParser = $arrayParser;
}
/**
- * @return string|mixed[]|ConstExprNode|DoctrineAnnotationTagValueNode
+ * @return string|mixed[]|ConstExprNode|DoctrineAnnotationTagValueNode|StringNode
*/
public function parseValue(BetterTokenIterator $tokenIterator)
{
@@ -89,7 +90,7 @@ public function parseValue(BetterTokenIterator $tokenIterator)
}
$end = $tokenIterator->currentPosition();
if ($start + 1 < $end) {
- return $tokenIterator->printFromTo($start, $end);
+ return new StringNode($tokenIterator->printFromTo($start, $end));
}
return $currentTokenValue;
}
diff --git a/packages/BetterPhpDocParser/Printer/PhpDocInfoPrinter.php b/packages/BetterPhpDocParser/Printer/PhpDocInfoPrinter.php
index 4aba09181ad8..46636c96bffa 100644
--- a/packages/BetterPhpDocParser/Printer/PhpDocInfoPrinter.php
+++ b/packages/BetterPhpDocParser/Printer/PhpDocInfoPrinter.php
@@ -26,6 +26,26 @@
*/
final class PhpDocInfoPrinter
{
+ /**
+ * @readonly
+ * @var \Rector\BetterPhpDocParser\Printer\EmptyPhpDocDetector
+ */
+ private $emptyPhpDocDetector;
+ /**
+ * @readonly
+ * @var \Rector\BetterPhpDocParser\Printer\DocBlockInliner
+ */
+ private $docBlockInliner;
+ /**
+ * @readonly
+ * @var \Rector\BetterPhpDocParser\Printer\RemoveNodesStartAndEndResolver
+ */
+ private $removeNodesStartAndEndResolver;
+ /**
+ * @readonly
+ * @var \Rector\BetterPhpDocParser\PhpDocNodeVisitor\ChangedPhpDocNodeVisitor
+ */
+ private $changedPhpDocNodeVisitor;
/**
* @var string
* @see https://regex101.com/r/Ab0Vey/1
@@ -71,26 +91,6 @@ final class PhpDocInfoPrinter
* @var \Rector\PhpDocParser\PhpDocParser\PhpDocNodeTraverser
*/
private $changedPhpDocNodeTraverser;
- /**
- * @readonly
- * @var \Rector\BetterPhpDocParser\Printer\EmptyPhpDocDetector
- */
- private $emptyPhpDocDetector;
- /**
- * @readonly
- * @var \Rector\BetterPhpDocParser\Printer\DocBlockInliner
- */
- private $docBlockInliner;
- /**
- * @readonly
- * @var \Rector\BetterPhpDocParser\Printer\RemoveNodesStartAndEndResolver
- */
- private $removeNodesStartAndEndResolver;
- /**
- * @readonly
- * @var \Rector\BetterPhpDocParser\PhpDocNodeVisitor\ChangedPhpDocNodeVisitor
- */
- private $changedPhpDocNodeVisitor;
public function __construct(\Rector\BetterPhpDocParser\Printer\EmptyPhpDocDetector $emptyPhpDocDetector, \Rector\BetterPhpDocParser\Printer\DocBlockInliner $docBlockInliner, \Rector\BetterPhpDocParser\Printer\RemoveNodesStartAndEndResolver $removeNodesStartAndEndResolver, ChangedPhpDocNodeVisitor $changedPhpDocNodeVisitor)
{
$this->emptyPhpDocDetector = $emptyPhpDocDetector;
diff --git a/packages/BetterPhpDocParser/ValueObject/PhpDoc/DoctrineAnnotation/AbstractValuesAwareNode.php b/packages/BetterPhpDocParser/ValueObject/PhpDoc/DoctrineAnnotation/AbstractValuesAwareNode.php
index 0c085199b7ee..eb950bae5dae 100644
--- a/packages/BetterPhpDocParser/ValueObject/PhpDoc/DoctrineAnnotation/AbstractValuesAwareNode.php
+++ b/packages/BetterPhpDocParser/ValueObject/PhpDoc/DoctrineAnnotation/AbstractValuesAwareNode.php
@@ -6,14 +6,10 @@
use PHPStan\PhpDocParser\Ast\NodeAttributes;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
+use Rector\BetterPhpDocParser\PhpDoc\StringNode;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
abstract class AbstractValuesAwareNode implements PhpDocTagValueNode
{
- use NodeAttributes;
- /**
- * @var bool
- */
- protected $hasChanged = \false;
/**
* @var ArrayItemNode[]
*/
@@ -26,6 +22,11 @@ abstract class AbstractValuesAwareNode implements PhpDocTagValueNode
* @var string|null
*/
protected $silentKey;
+ use NodeAttributes;
+ /**
+ * @var bool
+ */
+ protected $hasChanged = \false;
/**
* @param ArrayItemNode[] $values Must be public so node traverser can go through them
*/
@@ -41,7 +42,7 @@ public function __construct(array $values = [], ?string $originalContent = null,
public function removeValue(string $desiredKey) : void
{
foreach ($this->values as $key => $value) {
- if ($value->key !== $desiredKey) {
+ if (!$this->isValueKeyEquals($value, $desiredKey)) {
continue;
}
unset($this->values[$key]);
@@ -77,7 +78,7 @@ public function getValuesWithSilentKey() : array
public function getValue(string $desiredKey) : ?ArrayItemNode
{
foreach ($this->values as $value) {
- if ($value->key === $desiredKey) {
+ if ($this->isValueKeyEquals($value, $desiredKey)) {
return $value;
}
}
@@ -116,6 +117,13 @@ protected function printValuesContent(array $values) : string
}
return $itemContents;
}
+ private function isValueKeyEquals(ArrayItemNode $arrayItemNode, string $desiredKey) : bool
+ {
+ if ($arrayItemNode->key instanceof StringNode) {
+ return $arrayItemNode->key->value === $desiredKey;
+ }
+ return $arrayItemNode->key === $desiredKey;
+ }
/**
* @param mixed $value
*/
diff --git a/packages/Caching/Detector/ChangedFilesDetector.php b/packages/Caching/Detector/ChangedFilesDetector.php
index b74e75003398..c9e2ecdcf1ef 100644
--- a/packages/Caching/Detector/ChangedFilesDetector.php
+++ b/packages/Caching/Detector/ChangedFilesDetector.php
@@ -14,14 +14,6 @@
*/
final class ChangedFilesDetector
{
- /**
- * @var array
- */
- private $dependentFiles = [];
- /**
- * @var array
- */
- private $cachableFiles = [];
/**
* @readonly
* @var \Rector\Caching\Config\FileHashComputer
@@ -37,6 +29,14 @@ final class ChangedFilesDetector
* @var \Rector\Core\Util\FileHasher
*/
private $fileHasher;
+ /**
+ * @var array
+ */
+ private $dependentFiles = [];
+ /**
+ * @var array
+ */
+ private $cachableFiles = [];
public function __construct(FileHashComputer $fileHashComputer, Cache $cache, FileHasher $fileHasher)
{
$this->fileHashComputer = $fileHashComputer;
diff --git a/packages/Caching/ValueObject/Storage/FileCacheStorage.php b/packages/Caching/ValueObject/Storage/FileCacheStorage.php
index ae744c30848a..39d764c48ffe 100644
--- a/packages/Caching/ValueObject/Storage/FileCacheStorage.php
+++ b/packages/Caching/ValueObject/Storage/FileCacheStorage.php
@@ -17,10 +17,12 @@
final class FileCacheStorage implements CacheStorageInterface
{
/**
+ * @readonly
* @var string
*/
private $directory;
/**
+ * @readonly
* @var \Symfony\Component\Filesystem\Filesystem
*/
private $filesystem;
@@ -55,7 +57,7 @@ public function save(string $key, string $variableKey, $data) : void
$cacheFilePaths = $this->getCacheFilePaths($key);
$this->filesystem->mkdir($cacheFilePaths->getFirstDirectory());
$this->filesystem->mkdir($cacheFilePaths->getSecondDirectory());
- $path = $cacheFilePaths->getFilePath();
+ $filePath = $cacheFilePaths->getFilePath();
$tmpPath = \sprintf('%s/%s.tmp', $this->directory, Random::generate());
$errorBefore = \error_get_last();
$exported = @\var_export(new CacheItem($variableKey, $data), \true);
@@ -65,13 +67,13 @@ public function save(string $key, string $variableKey, $data) : void
}
// for performance reasons we don't use SmartFileSystem
FileSystem::write($tmpPath, \sprintf("
- */
- private $affectedFiles = [];
- public function addFile(File $file) : void
- {
- $this->affectedFiles[$file->getFilePath()] = $file;
- }
- public function getNext() : ?File
- {
- if ($this->affectedFiles !== []) {
- return \current($this->affectedFiles);
- }
- return null;
- }
- public function removeFromList(File $file) : void
- {
- unset($this->affectedFiles[$file->getFilePath()]);
- }
-}
diff --git a/packages/ChangesReporting/Output/ConsoleOutputFormatter.php b/packages/ChangesReporting/Output/ConsoleOutputFormatter.php
index a9db9c95015e..8747ee912fe1 100644
--- a/packages/ChangesReporting/Output/ConsoleOutputFormatter.php
+++ b/packages/ChangesReporting/Output/ConsoleOutputFormatter.php
@@ -13,15 +13,6 @@
use Rector\Core\ValueObject\Reporting\FileDiff;
final class ConsoleOutputFormatter implements OutputFormatterInterface
{
- /**
- * @var string
- */
- public const NAME = 'console';
- /**
- * @var string
- * @see https://regex101.com/r/q8I66g/1
- */
- private const ON_LINE_REGEX = '# on line #';
/**
* @readonly
* @var \Rector\Core\Contract\Console\OutputStyleInterface
@@ -32,6 +23,15 @@ final class ConsoleOutputFormatter implements OutputFormatterInterface
* @var \Rector\ChangesReporting\Annotation\RectorsChangelogResolver
*/
private $rectorsChangelogResolver;
+ /**
+ * @var string
+ */
+ public const NAME = 'console';
+ /**
+ * @var string
+ * @see https://regex101.com/r/q8I66g/1
+ */
+ private const ON_LINE_REGEX = '# on line #';
public function __construct(OutputStyleInterface $rectorOutputStyle, RectorsChangelogResolver $rectorsChangelogResolver)
{
$this->rectorOutputStyle = $rectorOutputStyle;
@@ -43,7 +43,6 @@ public function report(ProcessResult $processResult, Configuration $configuratio
$this->reportFileDiffs($processResult->getFileDiffs());
}
$this->reportErrors($processResult->getErrors());
- $this->reportRemovedFilesAndNodes($processResult);
if ($processResult->getErrors() !== []) {
return;
}
@@ -105,35 +104,15 @@ private function reportErrors(array $errors) : void
$this->rectorOutputStyle->error($message);
}
}
- private function reportRemovedFilesAndNodes(ProcessResult $processResult) : void
- {
- if ($processResult->getAddedFilesCount() !== 0) {
- $message = \sprintf('%d files were added', $processResult->getAddedFilesCount());
- $this->rectorOutputStyle->note($message);
- }
- if ($processResult->getRemovedFilesCount() !== 0) {
- $message = \sprintf('%d files were removed', $processResult->getRemovedFilesCount());
- $this->rectorOutputStyle->note($message);
- }
- $this->reportRemovedNodes($processResult);
- }
private function normalizePathsToRelativeWithLine(string $errorMessage) : string
{
$regex = '#' . \preg_quote(\getcwd(), '#') . '/#';
$errorMessage = Strings::replace($errorMessage, $regex);
return Strings::replace($errorMessage, self::ON_LINE_REGEX);
}
- private function reportRemovedNodes(ProcessResult $processResult) : void
- {
- if ($processResult->getRemovedNodeCount() === 0) {
- return;
- }
- $message = \sprintf('%d nodes were removed', $processResult->getRemovedNodeCount());
- $this->rectorOutputStyle->warning($message);
- }
private function createSuccessMessage(ProcessResult $processResult, Configuration $configuration) : string
{
- $changeCount = \count($processResult->getFileDiffs()) + $processResult->getRemovedAndAddedFilesCount();
+ $changeCount = \count($processResult->getFileDiffs());
if ($changeCount === 0) {
return 'Rector is done!';
}
diff --git a/packages/ChangesReporting/Output/JsonOutputFormatter.php b/packages/ChangesReporting/Output/JsonOutputFormatter.php
index 68a01500b660..ba7f51f416b8 100644
--- a/packages/ChangesReporting/Output/JsonOutputFormatter.php
+++ b/packages/ChangesReporting/Output/JsonOutputFormatter.php
@@ -12,15 +12,15 @@
use Rector\Parallel\ValueObject\Bridge;
final class JsonOutputFormatter implements OutputFormatterInterface
{
- /**
- * @var string
- */
- public const NAME = 'json';
/**
* @readonly
* @var \Rector\ChangesReporting\Annotation\RectorsChangelogResolver
*/
private $rectorsChangelogResolver;
+ /**
+ * @var string
+ */
+ public const NAME = 'json';
public function __construct(RectorsChangelogResolver $rectorsChangelogResolver)
{
$this->rectorsChangelogResolver = $rectorsChangelogResolver;
@@ -31,7 +31,7 @@ public function getName() : string
}
public function report(ProcessResult $processResult, Configuration $configuration) : void
{
- $errorsJson = ['totals' => ['changed_files' => \count($processResult->getFileDiffs()), 'removed_and_added_files_count' => $processResult->getRemovedAndAddedFilesCount(), 'removed_node_count' => $processResult->getRemovedNodeCount()]];
+ $errorsJson = ['totals' => ['changed_files' => \count($processResult->getFileDiffs())]];
$fileDiffs = $processResult->getFileDiffs();
\ksort($fileDiffs);
foreach ($fileDiffs as $fileDiff) {
diff --git a/packages/ChangesReporting/ValueObject/RectorWithLineChange.php b/packages/ChangesReporting/ValueObject/RectorWithLineChange.php
index 15f4190a63f0..bdd33212ca4d 100644
--- a/packages/ChangesReporting/ValueObject/RectorWithLineChange.php
+++ b/packages/ChangesReporting/ValueObject/RectorWithLineChange.php
@@ -8,6 +8,11 @@
use RectorPrefix202306\Webmozart\Assert\Assert;
final class RectorWithLineChange implements SerializableInterface
{
+ /**
+ * @readonly
+ * @var int
+ */
+ private $line;
/**
* @var string
*/
@@ -21,11 +26,6 @@ final class RectorWithLineChange implements SerializableInterface
* @readonly
*/
private $rectorClass;
- /**
- * @readonly
- * @var int
- */
- private $line;
/**
* @param string|\Rector\Core\Contract\Rector\RectorInterface $rectorClass
*/
diff --git a/packages/Comments/NodeTraverser/CommentRemovingNodeTraverser.php b/packages/Comments/NodeTraverser/CommentRemovingNodeTraverser.php
index 868e8b47d069..cbaec495479e 100644
--- a/packages/Comments/NodeTraverser/CommentRemovingNodeTraverser.php
+++ b/packages/Comments/NodeTraverser/CommentRemovingNodeTraverser.php
@@ -10,5 +10,6 @@ final class CommentRemovingNodeTraverser extends NodeTraverser
public function __construct(CommentRemovingNodeVisitor $commentRemovingNodeVisitor)
{
$this->addVisitor($commentRemovingNodeVisitor);
+ parent::__construct();
}
}
diff --git a/packages/Config/RectorConfig.php b/packages/Config/RectorConfig.php
index d4cdc3be62c4..0d03017b0d92 100644
--- a/packages/Config/RectorConfig.php
+++ b/packages/Config/RectorConfig.php
@@ -7,9 +7,13 @@
use Rector\Core\Configuration\Option;
use Rector\Core\Configuration\ValueObjectInliner;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
+use Rector\Core\Contract\Rector\NonPhpRectorInterface;
+use Rector\Core\Contract\Rector\PhpRectorInterface;
use Rector\Core\Contract\Rector\RectorInterface;
use Rector\Core\ValueObject\PhpVersion;
use RectorPrefix202306\Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
+use RectorPrefix202306\Symfony\Component\DependencyInjection\Loader\Configurator\ServiceConfigurator;
+use RectorPrefix202306\Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator;
use RectorPrefix202306\Webmozart\Assert\Assert;
/**
* @api
@@ -18,6 +22,10 @@
*/
final class RectorConfig extends ContainerConfigurator
{
+ /**
+ * @var \Symfony\Component\DependencyInjection\Loader\Configurator\ServicesConfigurator|null
+ */
+ private $servicesConfigurator;
/**
* @param string[] $paths
*/
@@ -104,7 +112,6 @@ public function ruleWithConfiguration(string $rectorClass, array $configuration)
Assert::classExists($rectorClass);
Assert::isAOf($rectorClass, RectorInterface::class);
Assert::isAOf($rectorClass, ConfigurableRectorInterface::class);
- $services = $this->services();
// decorate with value object inliner so Symfony understands, see https://getrector.org/blog/2020/09/07/how-to-inline-value-object-in-symfony-php-config
\array_walk_recursive($configuration, static function (&$value) {
if (\is_object($value)) {
@@ -112,7 +119,9 @@ public function ruleWithConfiguration(string $rectorClass, array $configuration)
}
return $value;
});
- $services->set($rectorClass)->call('configure', [$configuration]);
+ $servicesConfigurator = $this->getServices();
+ $rectorService = $servicesConfigurator->set($rectorClass)->public()->autowire()->call('configure', [$configuration]);
+ $this->tagRectorService($rectorService, $rectorClass);
}
/**
* @param class-string $rectorClass
@@ -121,8 +130,9 @@ public function rule(string $rectorClass) : void
{
Assert::classExists($rectorClass);
Assert::isAOf($rectorClass, RectorInterface::class);
- $services = $this->services();
- $services->set($rectorClass);
+ $servicesConfigurator = $this->getServices();
+ $rectorService = $servicesConfigurator->set($rectorClass)->public()->autowire();
+ $this->tagRectorService($rectorService, $rectorClass);
}
/**
* @param array> $rectorClasses
@@ -216,4 +226,24 @@ public function indent(string $character, int $count) : void
$parameters->set(Option::INDENT_CHAR, $character);
$parameters->set(Option::INDENT_SIZE, $count);
}
+ private function getServices() : ServicesConfigurator
+ {
+ if ($this->servicesConfigurator instanceof ServicesConfigurator) {
+ return $this->servicesConfigurator;
+ }
+ $this->servicesConfigurator = $this->services();
+ return $this->servicesConfigurator;
+ }
+ /**
+ * @param class-string $rectorClass
+ */
+ private function tagRectorService(ServiceConfigurator $rectorServiceConfigurator, string $rectorClass) : void
+ {
+ $rectorServiceConfigurator->tag(RectorInterface::class);
+ if (\is_a($rectorClass, PhpRectorInterface::class, \true)) {
+ $rectorServiceConfigurator->tag(PhpRectorInterface::class);
+ } elseif (\is_a($rectorClass, NonPhpRectorInterface::class, \true)) {
+ $rectorServiceConfigurator->tag(NonPhpRectorInterface::class);
+ }
+ }
}
diff --git a/packages/Defluent/NodeAnalyzer/FluentChainMethodCallNodeAnalyzer.php b/packages/Defluent/NodeAnalyzer/FluentChainMethodCallNodeAnalyzer.php
deleted file mode 100644
index 25e4a908b8cb..000000000000
--- a/packages/Defluent/NodeAnalyzer/FluentChainMethodCallNodeAnalyzer.php
+++ /dev/null
@@ -1,41 +0,0 @@
-methodCall()->chainedMethodCall()"
- */
-final class FluentChainMethodCallNodeAnalyzer
-{
- /**
- * @api doctrine
- */
- public function resolveRootMethodCall(MethodCall $methodCall) : ?MethodCall
- {
- $callerNode = $methodCall->var;
- while ($callerNode instanceof MethodCall && $callerNode->var instanceof MethodCall) {
- $callerNode = $callerNode->var;
- }
- if ($callerNode instanceof MethodCall) {
- return $callerNode;
- }
- return null;
- }
- /**
- * @return \PhpParser\Node\Expr|\PhpParser\Node\Name
- */
- public function resolveRootExpr(MethodCall $methodCall)
- {
- $callerNode = $methodCall->var;
- while ($callerNode instanceof MethodCall || $callerNode instanceof StaticCall) {
- $callerNode = $callerNode instanceof StaticCall ? $callerNode->class : $callerNode->var;
- }
- return $callerNode;
- }
-}
diff --git a/packages/FileSystemRector/Contract/AddedFileInterface.php b/packages/FileSystemRector/Contract/AddedFileInterface.php
deleted file mode 100644
index 7802beaee1b0..000000000000
--- a/packages/FileSystemRector/Contract/AddedFileInterface.php
+++ /dev/null
@@ -1,9 +0,0 @@
-nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator;
- $this->fileWithoutNamespaceNodeTraverser = $fileWithoutNamespaceNodeTraverser;
$this->rectorParser = $rectorParser;
+ $this->currentFileProvider = $currentFileProvider;
}
/**
* @api tests only
@@ -42,8 +42,10 @@ public function __construct(NodeScopeAndMetadataDecorator $nodeScopeAndMetadataD
public function parseFileInfoToNodesAndDecorate(string $filePath) : array
{
$stmts = $this->rectorParser->parseFile($filePath);
- $stmts = $this->fileWithoutNamespaceNodeTraverser->traverse($stmts);
$file = new File($filePath, FileSystem::read($filePath));
- return $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($file, $stmts);
+ $stmts = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($file, $stmts);
+ $file->hydrateStmtsAndTokens($stmts, $stmts, []);
+ $this->currentFileProvider->setFile($file);
+ return $stmts;
}
}
diff --git a/packages/FileSystemRector/ValueObject/AddedFileWithContent.php b/packages/FileSystemRector/ValueObject/AddedFileWithContent.php
deleted file mode 100644
index 198dda539cac..000000000000
--- a/packages/FileSystemRector/ValueObject/AddedFileWithContent.php
+++ /dev/null
@@ -1,47 +0,0 @@
-filePath = $filePath;
- $this->fileContent = $fileContent;
- if ($filePath === $fileContent) {
- throw new ShouldNotHappenException('File path and content are the same, probably a bug');
- }
- }
- public function getRealPath() : string
- {
- $realPath = \realpath($this->filePath);
- if ($realPath === \false) {
- throw new ShouldNotHappenException();
- }
- return $realPath;
- }
- public function getFilePath() : string
- {
- return $this->filePath;
- }
- public function getFileContent() : string
- {
- return $this->fileContent;
- }
-}
diff --git a/packages/FileSystemRector/ValueObject/AddedFileWithNodes.php b/packages/FileSystemRector/ValueObject/AddedFileWithNodes.php
deleted file mode 100644
index 78c8039037e3..000000000000
--- a/packages/FileSystemRector/ValueObject/AddedFileWithNodes.php
+++ /dev/null
@@ -1,40 +0,0 @@
-filePath = $filePath;
- $this->nodes = $nodes;
- }
- public function getFilePath() : string
- {
- return $this->filePath;
- }
- /**
- * @return Node\Stmt[]
- */
- public function getNodes() : array
- {
- return $this->nodes;
- }
-}
diff --git a/packages/NodeCollector/BinaryOpTreeRootLocator.php b/packages/NodeCollector/BinaryOpTreeRootLocator.php
deleted file mode 100644
index 7146ffa41a64..000000000000
--- a/packages/NodeCollector/BinaryOpTreeRootLocator.php
+++ /dev/null
@@ -1,48 +0,0 @@
- $binaryOpClass
- */
- public function findOperationRoot(Expr $expr, string $binaryOpClass) : Expr
- {
- $parentNode = $expr->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentNode instanceof Node) {
- // No more parents so the Expr node must be root.
- return $expr;
- }
- if (\get_class($parentNode) !== $binaryOpClass) {
- // If the Expr node is not a child of the desired operation,
- // it must already be the root of the operation tree.
- return $expr;
- }
- /** @var BinaryOp $parentNode */
- $isParentARightAssociativeTree = $parentNode->right === $expr && \get_class($expr) === $binaryOpClass;
- if ($isParentARightAssociativeTree) {
- // The Expr node is the right child of its parent but it is the desired operation (BinaryOp b c).
- // Since the AST fragment (BinaryOp a >(BinaryOp b c)<) corresponds to a right-associative,
- // the current node must be the root of a left-associative tree.
- return $expr;
- }
- // We already know the parent is the desired operation and the current node is not its right child.
- // This means the parent is a root of a larger left-associative tree so we continue recursively.
- return $this->findOperationRoot($parentNode, $binaryOpClass);
- }
-}
diff --git a/packages/NodeCollector/NodeAnalyzer/ArrayCallableMethodMatcher.php b/packages/NodeCollector/NodeAnalyzer/ArrayCallableMethodMatcher.php
index ef13ae0aec78..bb60b2b34dd8 100644
--- a/packages/NodeCollector/NodeAnalyzer/ArrayCallableMethodMatcher.php
+++ b/packages/NodeCollector/NodeAnalyzer/ArrayCallableMethodMatcher.php
@@ -3,17 +3,13 @@
declare (strict_types=1);
namespace Rector\NodeCollector\NodeAnalyzer;
-use PhpParser\Node\Arg;
-use PhpParser\Node\Attribute;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\ClassConstFetch;
-use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Scalar\String_;
-use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Analyser\Scope;
+use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\MixedType;
@@ -22,21 +18,15 @@
use PHPStan\Type\Type;
use PHPStan\Type\TypeWithClassName;
use Rector\Core\Enum\ObjectReference;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
+use Rector\Core\Reflection\ReflectionResolver;
use Rector\Core\ValueObject\MethodName;
use Rector\NodeCollector\ValueObject\ArrayCallable;
use Rector\NodeCollector\ValueObject\ArrayCallableDynamicMethod;
-use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
final class ArrayCallableMethodMatcher
{
- /**
- * @readonly
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
/**
* @readonly
* @var \Rector\NodeTypeResolver\NodeTypeResolver
@@ -54,16 +44,15 @@ final class ArrayCallableMethodMatcher
private $reflectionProvider;
/**
* @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
+ * @var \Rector\Core\Reflection\ReflectionResolver
*/
- private $betterNodeFinder;
- public function __construct(NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, ValueResolver $valueResolver, ReflectionProvider $reflectionProvider, BetterNodeFinder $betterNodeFinder)
+ private $reflectionResolver;
+ public function __construct(NodeTypeResolver $nodeTypeResolver, ValueResolver $valueResolver, ReflectionProvider $reflectionProvider, ReflectionResolver $reflectionResolver)
{
- $this->nodeNameResolver = $nodeNameResolver;
$this->nodeTypeResolver = $nodeTypeResolver;
$this->valueResolver = $valueResolver;
$this->reflectionProvider = $reflectionProvider;
- $this->betterNodeFinder = $betterNodeFinder;
+ $this->reflectionResolver = $reflectionResolver;
}
/**
* Matches array like: "[$this, 'methodName']" → ['ClassName', 'methodName']
@@ -88,8 +77,7 @@ public function match(Array_ $array, Scope $scope)
if (!$callerType instanceof TypeWithClassName) {
return null;
}
- $isInAttribute = (bool) $this->betterNodeFinder->findParentType($array, Attribute::class);
- if ($isInAttribute) {
+ if ($array->getAttribute(AttributeKey::IS_ARRAY_IN_ATTRIBUTE) === \true) {
return null;
}
$values = $this->valueResolver->getValue($array);
@@ -140,15 +128,11 @@ private function shouldSkipAssociativeArray($values) : bool
*/
private function isCallbackAtFunctionNames(Array_ $array, array $functionNames) : bool
{
- $parentNode = $array->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentNode instanceof Arg) {
- return \false;
- }
- $parentParentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentParentNode instanceof FuncCall) {
+ $fromFuncCallName = $array->getAttribute(AttributeKey::FROM_FUNC_CALL_NAME);
+ if ($fromFuncCallName === null) {
return \false;
}
- return $this->nodeNameResolver->isNames($parentParentNode, $functionNames);
+ return \in_array($fromFuncCallName, $functionNames, \true);
}
/**
* @return \PHPStan\Type\MixedType|\PHPStan\Type\ObjectType
@@ -157,11 +141,11 @@ private function resolveClassConstFetchType(ClassConstFetch $classConstFetch, Sc
{
$classConstantReference = $this->valueResolver->getValue($classConstFetch);
if ($classConstantReference === ObjectReference::STATIC) {
- $classLike = $this->betterNodeFinder->findParentType($classConstFetch, Class_::class);
- if (!$classLike instanceof ClassLike) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($classConstFetch);
+ if (!$classReflection instanceof ClassReflection || !$classReflection->isClass()) {
return new MixedType();
}
- $classConstantReference = (string) $this->nodeNameResolver->getName($classLike);
+ $classConstantReference = $classReflection->getName();
}
// non-class value
if (!\is_string($classConstantReference)) {
diff --git a/packages/NodeNameResolver/Error/InvalidNameNodeReporter.php b/packages/NodeNameResolver/Error/InvalidNameNodeReporter.php
deleted file mode 100644
index 9ee46f0a59f0..000000000000
--- a/packages/NodeNameResolver/Error/InvalidNameNodeReporter.php
+++ /dev/null
@@ -1,87 +0,0 @@
-currentFileProvider = $currentFileProvider;
- $this->nodePrinter = $nodePrinter;
- $this->filePathHelper = $filePathHelper;
- }
- /**
- * @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall $node
- */
- public function reportInvalidNodeForName($node) : void
- {
- $message = \sprintf('Pick more specific node than "%s", e.g. "$node->name"', \get_class($node));
- $file = $this->currentFileProvider->getFile();
- if ($file instanceof File) {
- $message .= \PHP_EOL . \PHP_EOL;
- $relativeFilePath = $this->filePathHelper->relativePath($file->getFilePath());
- $message .= \sprintf('Caused in "%s" file on line %d on code "%s"', $relativeFilePath, $node->getStartLine(), $this->nodePrinter->print($node));
- }
- $backtrace = \debug_backtrace();
- $rectorBacktrace = $this->matchRectorBacktraceCall($backtrace);
- if ($rectorBacktrace !== null) {
- // issues to find the file in prefixed
- if (\file_exists($rectorBacktrace[self::FILE])) {
- $filePath = $rectorBacktrace[self::FILE];
- $relativeFilePath = $this->filePathHelper->relativePath($filePath);
- $fileAndLine = $relativeFilePath . ':' . $rectorBacktrace['line'];
- } else {
- $fileAndLine = $rectorBacktrace[self::FILE] . ':' . $rectorBacktrace['line'];
- }
- $message .= \PHP_EOL . \PHP_EOL;
- $message .= \sprintf('Look at "%s"', $fileAndLine);
- }
- throw new ShouldNotHappenException($message);
- }
- /**
- * @param mixed[] $backtrace
- * @return string[]|null
- */
- private function matchRectorBacktraceCall(array $backtrace) : ?array
- {
- foreach ($backtrace as $singleBacktrace) {
- if (!isset($singleBacktrace['object'])) {
- continue;
- }
- // match a Rector class
- if (!\is_a($singleBacktrace['object'], RectorInterface::class)) {
- continue;
- }
- return $singleBacktrace;
- }
- return $backtrace[1] ?? null;
- }
-}
diff --git a/packages/NodeNameResolver/NodeNameResolver.php b/packages/NodeNameResolver/NodeNameResolver.php
index 55c00cc338ad..04d9bf2c61d5 100644
--- a/packages/NodeNameResolver/NodeNameResolver.php
+++ b/packages/NodeNameResolver/NodeNameResolver.php
@@ -16,22 +16,10 @@
use Rector\Core\NodeAnalyzer\CallAnalyzer;
use Rector\Core\Util\StringUtils;
use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
-use Rector\NodeNameResolver\Error\InvalidNameNodeReporter;
use Rector\NodeNameResolver\Regex\RegexPatternDetector;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class NodeNameResolver
{
- /**
- * Used to check if a string might contain a regex or fnmatch pattern
- *
- * @var string
- * @see https://regex101.com/r/ImTV1W/1
- */
- private const CONTAINS_WILDCARD_CHARS_REGEX = '/[\\*\\#\\~\\/]/';
- /**
- * @var array
- */
- private $nodeNameResolversByClass = [];
/**
* @readonly
* @var \Rector\NodeNameResolver\Regex\RegexPatternDetector
@@ -42,11 +30,6 @@ final class NodeNameResolver
* @var \Rector\CodingStyle\Naming\ClassNaming
*/
private $classNaming;
- /**
- * @readonly
- * @var \Rector\NodeNameResolver\Error\InvalidNameNodeReporter
- */
- private $invalidNameNodeReporter;
/**
* @readonly
* @var \Rector\Core\NodeAnalyzer\CallAnalyzer
@@ -57,14 +40,24 @@ final class NodeNameResolver
* @readonly
*/
private $nodeNameResolvers = [];
+ /**
+ * Used to check if a string might contain a regex or fnmatch pattern
+ *
+ * @var string
+ * @see https://regex101.com/r/ImTV1W/1
+ */
+ private const CONTAINS_WILDCARD_CHARS_REGEX = '/[\\*\\#\\~\\/]/';
+ /**
+ * @var array
+ */
+ private $nodeNameResolversByClass = [];
/**
* @param NodeNameResolverInterface[] $nodeNameResolvers
*/
- public function __construct(RegexPatternDetector $regexPatternDetector, ClassNaming $classNaming, InvalidNameNodeReporter $invalidNameNodeReporter, CallAnalyzer $callAnalyzer, array $nodeNameResolvers = [])
+ public function __construct(RegexPatternDetector $regexPatternDetector, ClassNaming $classNaming, CallAnalyzer $callAnalyzer, iterable $nodeNameResolvers = [])
{
$this->regexPatternDetector = $regexPatternDetector;
$this->classNaming = $classNaming;
- $this->invalidNameNodeReporter = $invalidNameNodeReporter;
$this->callAnalyzer = $callAnalyzer;
$this->nodeNameResolvers = $nodeNameResolvers;
}
@@ -132,11 +125,8 @@ public function getName($node) : ?string
if (\is_string($namespacedName)) {
return $namespacedName;
}
- if ($node instanceof MethodCall || $node instanceof StaticCall) {
- if ($this->isCallOrIdentifier($node->name)) {
- return null;
- }
- $this->invalidNameNodeReporter->reportInvalidNodeForName($node);
+ if (($node instanceof MethodCall || $node instanceof StaticCall) && $this->isCallOrIdentifier($node->name)) {
+ return null;
}
$scope = $node->getAttribute(AttributeKey::SCOPE);
$resolvedName = $this->resolveNodeName($node, $scope);
diff --git a/packages/NodeNameResolver/NodeNameResolver/ClassConstFetchNameResolver.php b/packages/NodeNameResolver/NodeNameResolver/ClassConstFetchNameResolver.php
index 4780a185ae80..ab0c44392404 100644
--- a/packages/NodeNameResolver/NodeNameResolver/ClassConstFetchNameResolver.php
+++ b/packages/NodeNameResolver/NodeNameResolver/ClassConstFetchNameResolver.php
@@ -4,27 +4,16 @@
namespace Rector\NodeNameResolver\NodeNameResolver;
use PhpParser\Node;
+use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ClassConstFetch;
+use PhpParser\Node\Expr\Error;
use PHPStan\Analyser\Scope;
use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
-use Rector\NodeNameResolver\NodeNameResolver;
-use RectorPrefix202306\Symfony\Contracts\Service\Attribute\Required;
/**
* @implements NodeNameResolverInterface
*/
final class ClassConstFetchNameResolver implements NodeNameResolverInterface
{
- /**
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
- /**
- * @required
- */
- public function autowire(NodeNameResolver $nodeNameResolver) : void
- {
- $this->nodeNameResolver = $nodeNameResolver;
- }
public function getNode() : string
{
return ClassConstFetch::class;
@@ -34,14 +23,14 @@ public function getNode() : string
*/
public function resolve(Node $node, ?Scope $scope) : ?string
{
- $class = $this->nodeNameResolver->getName($node->class);
- $name = $this->nodeNameResolver->getName($node->name);
- if ($class === null) {
+ if ($node->class instanceof Expr) {
return null;
}
- if ($name === null) {
+ if ($node->name instanceof Error) {
return null;
}
+ $class = $node->class->toString();
+ $name = $node->name->toString();
return $class . '::' . $name;
}
}
diff --git a/packages/NodeNameResolver/NodeNameResolver/ClassConstNameResolver.php b/packages/NodeNameResolver/NodeNameResolver/ClassConstNameResolver.php
index af7e3346b775..1de130895d22 100644
--- a/packages/NodeNameResolver/NodeNameResolver/ClassConstNameResolver.php
+++ b/packages/NodeNameResolver/NodeNameResolver/ClassConstNameResolver.php
@@ -7,24 +7,11 @@
use PhpParser\Node\Stmt\ClassConst;
use PHPStan\Analyser\Scope;
use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
-use Rector\NodeNameResolver\NodeNameResolver;
-use RectorPrefix202306\Symfony\Contracts\Service\Attribute\Required;
/**
* @implements NodeNameResolverInterface
*/
final class ClassConstNameResolver implements NodeNameResolverInterface
{
- /**
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
- /**
- * @required
- */
- public function autowire(NodeNameResolver $nodeNameResolver) : void
- {
- $this->nodeNameResolver = $nodeNameResolver;
- }
public function getNode() : string
{
return ClassConst::class;
@@ -38,6 +25,6 @@ public function resolve(Node $node, ?Scope $scope) : ?string
return null;
}
$onlyConstant = $node->consts[0];
- return $this->nodeNameResolver->getName($onlyConstant);
+ return $onlyConstant->name->toString();
}
}
diff --git a/packages/NodeNameResolver/NodeNameResolver/ClassNameResolver.php b/packages/NodeNameResolver/NodeNameResolver/ClassNameResolver.php
index 3cdb2185a758..0fc56be67a05 100644
--- a/packages/NodeNameResolver/NodeNameResolver/ClassNameResolver.php
+++ b/packages/NodeNameResolver/NodeNameResolver/ClassNameResolver.php
@@ -9,24 +9,11 @@
use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Analyser\Scope;
use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
-use Rector\NodeNameResolver\NodeNameResolver;
-use RectorPrefix202306\Symfony\Contracts\Service\Attribute\Required;
/**
* @implements NodeNameResolverInterface
*/
final class ClassNameResolver implements NodeNameResolverInterface
{
- /**
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
- /**
- * @required
- */
- public function autowire(NodeNameResolver $nodeNameResolver) : void
- {
- $this->nodeNameResolver = $nodeNameResolver;
- }
public function getNode() : string
{
return ClassLike::class;
@@ -42,6 +29,6 @@ public function resolve(Node $node, ?Scope $scope) : ?string
if (!$node->name instanceof Identifier) {
return null;
}
- return $this->nodeNameResolver->getName($node->name);
+ return $node->name->toString();
}
}
diff --git a/packages/NodeNameResolver/NodeNameResolver/NameNameResolver.php b/packages/NodeNameResolver/NodeNameResolver/NameNameResolver.php
index 68167f35da2f..19aeefa9220e 100644
--- a/packages/NodeNameResolver/NodeNameResolver/NameNameResolver.php
+++ b/packages/NodeNameResolver/NodeNameResolver/NameNameResolver.php
@@ -4,25 +4,14 @@
namespace Rector\NodeNameResolver\NodeNameResolver;
use PhpParser\Node;
-use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Name;
use PHPStan\Analyser\Scope;
use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
-use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @implements NodeNameResolverInterface
*/
final class NameNameResolver implements NodeNameResolverInterface
{
- /**
- * @readonly
- * @var \Rector\NodeNameResolver\NodeNameResolver\FuncCallNameResolver
- */
- private $funcCallNameResolver;
- public function __construct(\Rector\NodeNameResolver\NodeNameResolver\FuncCallNameResolver $funcCallNameResolver)
- {
- $this->funcCallNameResolver = $funcCallNameResolver;
- }
public function getNode() : string
{
return Name::class;
@@ -32,11 +21,6 @@ public function getNode() : string
*/
public function resolve(Node $node, ?Scope $scope) : ?string
{
- // possible function parent
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentNode instanceof FuncCall) {
- return $this->funcCallNameResolver->resolve($parentNode, $scope);
- }
return $node->toString();
}
}
diff --git a/packages/NodeNameResolver/NodeNameResolver/ParamNameResolver.php b/packages/NodeNameResolver/NodeNameResolver/ParamNameResolver.php
index 07ba0481d3ec..e1701de9e179 100644
--- a/packages/NodeNameResolver/NodeNameResolver/ParamNameResolver.php
+++ b/packages/NodeNameResolver/NodeNameResolver/ParamNameResolver.php
@@ -4,27 +4,16 @@
namespace Rector\NodeNameResolver\NodeNameResolver;
use PhpParser\Node;
+use PhpParser\Node\Expr;
+use PhpParser\Node\Expr\Error;
use PhpParser\Node\Param;
use PHPStan\Analyser\Scope;
use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
-use Rector\NodeNameResolver\NodeNameResolver;
-use RectorPrefix202306\Symfony\Contracts\Service\Attribute\Required;
/**
* @implements NodeNameResolverInterface
*/
final class ParamNameResolver implements NodeNameResolverInterface
{
- /**
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
- /**
- * @required
- */
- public function autowire(NodeNameResolver $nodeNameResolver) : void
- {
- $this->nodeNameResolver = $nodeNameResolver;
- }
public function getNode() : string
{
return Param::class;
@@ -34,6 +23,12 @@ public function getNode() : string
*/
public function resolve(Node $node, ?Scope $scope) : ?string
{
- return $this->nodeNameResolver->getName($node->var);
+ if ($node->var instanceof Error) {
+ return null;
+ }
+ if ($node->var->name instanceof Expr) {
+ return null;
+ }
+ return $node->var->name;
}
}
diff --git a/packages/NodeNameResolver/NodeNameResolver/PropertyNameResolver.php b/packages/NodeNameResolver/NodeNameResolver/PropertyNameResolver.php
index bbc3bdc8df4c..01928d8080e2 100644
--- a/packages/NodeNameResolver/NodeNameResolver/PropertyNameResolver.php
+++ b/packages/NodeNameResolver/NodeNameResolver/PropertyNameResolver.php
@@ -7,24 +7,11 @@
use PhpParser\Node\Stmt\Property;
use PHPStan\Analyser\Scope;
use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
-use Rector\NodeNameResolver\NodeNameResolver;
-use RectorPrefix202306\Symfony\Contracts\Service\Attribute\Required;
/**
* @implements NodeNameResolverInterface
*/
final class PropertyNameResolver implements NodeNameResolverInterface
{
- /**
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
- /**
- * @required
- */
- public function autowire(NodeNameResolver $nodeNameResolver) : void
- {
- $this->nodeNameResolver = $nodeNameResolver;
- }
public function getNode() : string
{
return Property::class;
@@ -38,6 +25,6 @@ public function resolve(Node $node, ?Scope $scope) : ?string
return null;
}
$onlyProperty = $node->props[0];
- return $this->nodeNameResolver->getName($onlyProperty);
+ return $onlyProperty->name->toString();
}
}
diff --git a/packages/NodeNameResolver/NodeNameResolver/UseNameResolver.php b/packages/NodeNameResolver/NodeNameResolver/UseNameResolver.php
index 82a9ae536b82..9eca70fe4e5c 100644
--- a/packages/NodeNameResolver/NodeNameResolver/UseNameResolver.php
+++ b/packages/NodeNameResolver/NodeNameResolver/UseNameResolver.php
@@ -7,24 +7,11 @@
use PhpParser\Node\Stmt\Use_;
use PHPStan\Analyser\Scope;
use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
-use Rector\NodeNameResolver\NodeNameResolver;
-use RectorPrefix202306\Symfony\Contracts\Service\Attribute\Required;
/**
* @implements NodeNameResolverInterface
*/
final class UseNameResolver implements NodeNameResolverInterface
{
- /**
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
- /**
- * @required
- */
- public function autowire(NodeNameResolver $nodeNameResolver) : void
- {
- $this->nodeNameResolver = $nodeNameResolver;
- }
public function getNode() : string
{
return Use_::class;
@@ -38,6 +25,6 @@ public function resolve(Node $node, ?Scope $scope) : ?string
return null;
}
$onlyUse = $node->uses[0];
- return $this->nodeNameResolver->getName($onlyUse);
+ return $onlyUse->name->toString();
}
}
diff --git a/packages/NodeNameResolver/NodeNameResolver/VariableNameResolver.php b/packages/NodeNameResolver/NodeNameResolver/VariableNameResolver.php
index b44b0f4e6ece..fed6d44b1b5b 100644
--- a/packages/NodeNameResolver/NodeNameResolver/VariableNameResolver.php
+++ b/packages/NodeNameResolver/NodeNameResolver/VariableNameResolver.php
@@ -5,11 +5,9 @@
use PhpParser\Node;
use PhpParser\Node\Expr;
-use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\Variable;
use PHPStan\Analyser\Scope;
use Rector\NodeNameResolver\Contract\NodeNameResolverInterface;
-use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @implements NodeNameResolverInterface
*/
@@ -24,11 +22,6 @@ public function getNode() : string
*/
public function resolve(Node $node, ?Scope $scope) : ?string
{
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
- // skip $some->$dynamicMethodName()
- if ($parentNode instanceof MethodCall && $node === $parentNode->name) {
- return null;
- }
if ($node->name instanceof Expr) {
return null;
}
diff --git a/packages/NodeNestingScope/ContextAnalyzer.php b/packages/NodeNestingScope/ContextAnalyzer.php
index 7784df5f212b..a795ff3bded4 100644
--- a/packages/NodeNestingScope/ContextAnalyzer.php
+++ b/packages/NodeNestingScope/ContextAnalyzer.php
@@ -4,60 +4,21 @@
namespace Rector\NodeNestingScope;
use PhpParser\Node;
-use PhpParser\Node\FunctionLike;
-use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\If_;
-use PhpParser\Node\Stmt\Switch_;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
-use Rector\NodeNestingScope\ValueObject\ControlStructure;
+use Rector\NodeTypeResolver\Node\AttributeKey;
final class ContextAnalyzer
{
- /**
- * Nodes that break the scope they way up, e.g. class method
- * @var array>
- */
- private const BREAK_NODES = [FunctionLike::class, ClassMethod::class];
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- public function __construct(BetterNodeFinder $betterNodeFinder)
- {
- $this->betterNodeFinder = $betterNodeFinder;
- }
- public function isInLoop(Node $node) : bool
- {
- $item0Unpacked = ControlStructure::LOOP_NODES;
- $item1Unpacked = self::BREAK_NODES;
- $firstParent = $this->betterNodeFinder->findParentByTypes($node, \array_merge($item0Unpacked, $item1Unpacked));
- if (!$firstParent instanceof Node) {
- return \false;
- }
- foreach (ControlStructure::LOOP_NODES as $type) {
- if (\is_a($firstParent, $type, \true)) {
- return \true;
- }
- }
- return \false;
- }
/**
* @api
*/
- public function isInSwitch(Node $node) : bool
+ public function isInLoop(Node $node) : bool
{
- return (bool) $this->betterNodeFinder->findParentType($node, Switch_::class);
+ return $node->getAttribute(AttributeKey::IS_IN_LOOP) === \true;
}
/**
* @api
*/
public function isInIf(Node $node) : bool
{
- $item1Unpacked = self::BREAK_NODES;
- $previousNode = $this->betterNodeFinder->findParentByTypes($node, \array_merge([If_::class], $item1Unpacked));
- if (!$previousNode instanceof Node) {
- return \false;
- }
- return $previousNode instanceof If_;
+ return $node->getAttribute(AttributeKey::IS_IN_IF) === \true;
}
}
diff --git a/packages/NodeNestingScope/ScopeNestingComparator.php b/packages/NodeNestingScope/ScopeNestingComparator.php
deleted file mode 100644
index e523c9316538..000000000000
--- a/packages/NodeNestingScope/ScopeNestingComparator.php
+++ /dev/null
@@ -1,76 +0,0 @@
-betterNodeFinder = $betterNodeFinder;
- $this->nodeComparator = $nodeComparator;
- }
- public function isNodeConditionallyScoped(Expr $expr) : bool
- {
- $foundParent = $this->betterNodeFinder->findParentByTypes($expr, ControlStructure::CONDITIONAL_NODE_SCOPE_TYPES + [FunctionLike::class]);
- if (!$foundParent instanceof Node) {
- return \false;
- }
- // is in both if/else branches
- if ($this->isInBothIfElseBranch($foundParent, $expr)) {
- return \false;
- }
- if (!$foundParent instanceof Else_) {
- return !$foundParent instanceof FunctionLike;
- }
- if (!$this->nodeComparator->areNodesEqual($expr, $this->doubleIfBranchExprs)) {
- return !$foundParent instanceof FunctionLike;
- }
- return \false;
- }
- private function isInBothIfElseBranch(Node $foundParentNode, Expr $seekedExpr) : bool
- {
- if ($foundParentNode instanceof Else_) {
- return $this->nodeComparator->isNodeEqual($seekedExpr, $this->doubleIfBranchExprs);
- }
- if (!$foundParentNode instanceof If_) {
- return \false;
- }
- $foundIfNode = (bool) $this->betterNodeFinder->findFirst($foundParentNode->stmts, function (Node $node) use($seekedExpr) : bool {
- return $this->nodeComparator->areNodesEqual($node, $seekedExpr);
- });
- if (!$foundParentNode->else instanceof Else_) {
- return \false;
- }
- $foundElseNode = (bool) $this->betterNodeFinder->findFirst($foundParentNode->else, function (Node $node) use($seekedExpr) : bool {
- return $this->nodeComparator->areNodesEqual($node, $seekedExpr);
- });
- if ($foundIfNode && $foundElseNode) {
- $this->doubleIfBranchExprs[] = $seekedExpr;
- return \true;
- }
- return \false;
- }
-}
diff --git a/packages/NodeNestingScope/ValueObject/ControlStructure.php b/packages/NodeNestingScope/ValueObject/ControlStructure.php
index 15b7b8e44b68..b6208fc7318b 100644
--- a/packages/NodeNestingScope/ValueObject/ControlStructure.php
+++ b/packages/NodeNestingScope/ValueObject/ControlStructure.php
@@ -5,13 +5,11 @@
use PhpParser\Node;
use PhpParser\Node\Expr\Match_;
-use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Case_;
use PhpParser\Node\Stmt\Catch_;
use PhpParser\Node\Stmt\Do_;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\ElseIf_;
-use PhpParser\Node\Stmt\For_;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Switch_;
@@ -23,8 +21,4 @@ final class ControlStructure
* @var array>
*/
public const CONDITIONAL_NODE_SCOPE_TYPES = [If_::class, While_::class, Do_::class, Else_::class, ElseIf_::class, Catch_::class, Case_::class, Match_::class, Switch_::class, Foreach_::class];
- /**
- * @var array>
- */
- public const LOOP_NODES = [For_::class, Foreach_::class, While_::class, Do_::class];
}
diff --git a/packages/NodeRemoval/BreakingRemovalGuard.php b/packages/NodeRemoval/BreakingRemovalGuard.php
deleted file mode 100644
index 84f17d932cbd..000000000000
--- a/packages/NodeRemoval/BreakingRemovalGuard.php
+++ /dev/null
@@ -1,63 +0,0 @@
-isLegalNodeRemoval($node)) {
- return;
- }
- // validate the node can be removed
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentNode instanceof Node) {
- throw new ShouldNotHappenException();
- }
- throw new ShouldNotHappenException(\sprintf('Node "%s" on line %d is child of "%s", so it cannot be removed as it would break PHP code. Change or remove the parent node instead.', \get_class($node), $node->getLine(), \get_class($parentNode)));
- }
- /**
- * @api
- */
- public function isLegalNodeRemoval(Node $node) : bool
- {
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentNode instanceof If_ && $parentNode->cond === $node) {
- return \false;
- }
- if ($parentNode instanceof BooleanNot) {
- $parentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
- }
- if ($parentNode instanceof Assign) {
- return \false;
- }
- if ($this->isIfCondition($node)) {
- return \false;
- }
- return !$this->isWhileCondition($node);
- }
- private function isIfCondition(Node $node) : bool
- {
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentNode instanceof If_) {
- return \false;
- }
- return $parentNode->cond === $node;
- }
- private function isWhileCondition(Node $node) : bool
- {
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentNode instanceof While_) {
- return \false;
- }
- return $parentNode->cond === $node;
- }
-}
diff --git a/packages/NodeRemoval/NodeRemover.php b/packages/NodeRemoval/NodeRemover.php
deleted file mode 100644
index 741ee2ed86f0..000000000000
--- a/packages/NodeRemoval/NodeRemover.php
+++ /dev/null
@@ -1,41 +0,0 @@
-nodesToRemoveCollector = $nodesToRemoveCollector;
- $this->rectorChangeCollector = $rectorChangeCollector;
- }
- /**
- * @deprecated Return NodeTraverser::* to remove node directly instead
- */
- public function removeNode(Node $node) : void
- {
- // this make sure to keep just added nodes, e.g. added class constant, that doesn't have analysis of full code in this run
- // if this is missing, there are false positive e.g. for unused private constant
- $isJustAddedNode = !(bool) $node->getAttribute(AttributeKey::ORIGINAL_NODE);
- if ($isJustAddedNode) {
- return;
- }
- $this->nodesToRemoveCollector->addNodeToRemove($node);
- $this->rectorChangeCollector->notifyNodeFileInfo($node);
- }
-}
diff --git a/packages/NodeTypeResolver/Contract/SourceLocatorProviderInterface.php b/packages/NodeTypeResolver/Contract/SourceLocatorProviderInterface.php
deleted file mode 100644
index 2d75644ab513..000000000000
--- a/packages/NodeTypeResolver/Contract/SourceLocatorProviderInterface.php
+++ /dev/null
@@ -1,10 +0,0 @@
-parameterProvider = $parameterProvider;
diff --git a/packages/NodeTypeResolver/MethodParameterTypeResolver.php b/packages/NodeTypeResolver/MethodParameterTypeResolver.php
deleted file mode 100644
index 46230160dc2a..000000000000
--- a/packages/NodeTypeResolver/MethodParameterTypeResolver.php
+++ /dev/null
@@ -1,64 +0,0 @@
-reflectionResolver = $reflectionResolver;
- }
- /**
- * @return Type[]
- */
- public function provideParameterTypesByStaticCall(StaticCall $staticCall, Scope $scope) : array
- {
- $methodReflection = $this->reflectionResolver->resolveMethodReflectionFromStaticCall($staticCall);
- if (!$methodReflection instanceof MethodReflection) {
- return [];
- }
- return $this->provideParameterTypesFromMethodReflection($methodReflection, $staticCall, $scope);
- }
- /**
- * @return Type[]
- */
- public function provideParameterTypesByClassMethod(ClassMethod $classMethod, Scope $scope) : array
- {
- $methodReflection = $this->reflectionResolver->resolveMethodReflectionFromClassMethod($classMethod);
- if (!$methodReflection instanceof MethodReflection) {
- return [];
- }
- return $this->provideParameterTypesFromMethodReflection($methodReflection, $classMethod, $scope);
- }
- /**
- * @return Type[]
- * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\StaticCall $node
- */
- private function provideParameterTypesFromMethodReflection(MethodReflection $methodReflection, $node, Scope $scope) : array
- {
- if ($methodReflection instanceof NativeMethodReflection) {
- // method "getParameters()" does not exist there
- return [];
- }
- $parameterTypes = [];
- $parametersAcceptor = ParametersAcceptorSelectorVariantsWrapper::select($methodReflection, $node, $scope);
- foreach ($parametersAcceptor->getParameters() as $parameterReflection) {
- $parameterTypes[] = $parameterReflection->getType();
- }
- return $parameterTypes;
- }
-}
diff --git a/packages/NodeTypeResolver/Node/AttributeKey.php b/packages/NodeTypeResolver/Node/AttributeKey.php
index c5228ffee377..a266793f0774 100644
--- a/packages/NodeTypeResolver/Node/AttributeKey.php
+++ b/packages/NodeTypeResolver/Node/AttributeKey.php
@@ -54,16 +54,6 @@ final class AttributeKey
* @var string
*/
public const ORIGINAL_NAME = 'originalName';
- /**
- * @api
- * @deprecated Use $node->namespacedName instead
- *
- * Internal php-parser name. @see \PhpParser\NodeVisitor\NameResolver
- * Do not change this even if you want!
- *
- * @var string
- */
- public const RESOLVED_NAME = 'resolvedName';
/**
* @deprecated Refactor to a custom visitors/parent node instead,
* @see https://phpstan.org/blog/preprocessing-ast-for-custom-rules
@@ -73,24 +63,6 @@ final class AttributeKey
* @var string
*/
public const PARENT_NODE = 'parent';
- /**
- * @api
- * @internal of php-parser, do not change
- * @deprecated Use StmtsAwareInterface instead
- *
- * @see https://github.com/nikic/PHP-Parser/pull/681/files
- * @var string
- */
- public const PREVIOUS_NODE = 'previous';
- /**
- * @api
- * @internal of php-parser, do not change
- * @deprecated Use StmtsAwareInterface instead
- *
- * @see https://github.com/nikic/PHP-Parser/pull/681/files
- * @var string
- */
- public const NEXT_NODE = 'next';
/**
* Internal php-parser name.
* Do not change this even if you want!
@@ -200,4 +172,80 @@ final class AttributeKey
* @var string
*/
public const STMT_KEY = 'stmt_key';
+ /**
+ * @var string
+ */
+ public const IS_BEING_ASSIGNED = 'is_being_assigned';
+ /**
+ * @var string
+ */
+ public const IS_MULTI_ASSIGN = 'is_multi_assign';
+ /**
+ * @var string
+ */
+ public const STATEMENT_DEPTH = 'statementDepth';
+ /**
+ * @var string
+ */
+ public const IS_IN_LOOP = 'is_in_loop';
+ /**
+ * @var string
+ */
+ public const IS_IN_IF = 'is_in_if';
+ /**
+ * @var string
+ */
+ public const IS_ISSET_VAR = 'is_isset_var';
+ /**
+ * @var string
+ */
+ public const IS_UNSET_VAR = 'is_unset_var';
+ /**
+ * @var string
+ */
+ public const IS_ARRAY_IN_ATTRIBUTE = 'is_array_in_attribute';
+ /**
+ * @var string
+ */
+ public const IS_OBJECT_CALLER = 'is_object_caller';
+ /**
+ * @var string
+ */
+ public const IS_NAMESPACE_NAME = 'is_namespace_name';
+ /**
+ * @var string
+ */
+ public const IS_USEUSE_NAME = 'is_useuse_name';
+ /**
+ * @var string
+ */
+ public const IS_STATICCALL_CLASS_NAME = 'is_staticcall_class_name';
+ /**
+ * @var string
+ */
+ public const IS_FUNCCALL_NAME = 'is_funccall_name';
+ /**
+ * @var string
+ */
+ public const IS_CONSTFETCH_NAME = 'is_constfetch_name';
+ /**
+ * @var string
+ */
+ public const IS_NEW_INSTANCE_NAME = 'is_new_instance_name';
+ /**
+ * @var string
+ */
+ public const IS_RETURN_EXPR = 'is_return_expr';
+ /**
+ * @var string
+ */
+ public const IS_ARG_VALUE = 'is_arg_value';
+ /**
+ * @var string
+ */
+ public const IS_PARAM_TYPE = 'is_param_type';
+ /**
+ * @var string
+ */
+ public const FROM_FUNC_CALL_NAME = 'FROM_FUNC_CALL_NAME';
}
diff --git a/packages/NodeTypeResolver/NodeScopeAndMetadataDecorator.php b/packages/NodeTypeResolver/NodeScopeAndMetadataDecorator.php
index 1f42eb912859..44c79c154ec8 100644
--- a/packages/NodeTypeResolver/NodeScopeAndMetadataDecorator.php
+++ b/packages/NodeTypeResolver/NodeScopeAndMetadataDecorator.php
@@ -7,6 +7,7 @@
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\CloningVisitor;
use PhpParser\NodeVisitor\ParentConnectingVisitor;
+use Rector\Core\PhpParser\NodeTraverser\FileWithoutNamespaceNodeTraverser;
use Rector\Core\ValueObject\Application\File;
use Rector\NodeTypeResolver\NodeVisitor\FunctionLikeParamArgPositionNodeVisitor;
use Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver;
@@ -14,17 +15,23 @@ final class NodeScopeAndMetadataDecorator
{
/**
* @readonly
- * @var \PhpParser\NodeTraverser
+ * @var \Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver
*/
- private $nodeTraverser;
+ private $phpStanNodeScopeResolver;
/**
* @readonly
- * @var \Rector\NodeTypeResolver\PHPStan\Scope\PHPStanNodeScopeResolver
+ * @var \Rector\Core\PhpParser\NodeTraverser\FileWithoutNamespaceNodeTraverser
*/
- private $phpStanNodeScopeResolver;
- public function __construct(CloningVisitor $cloningVisitor, PHPStanNodeScopeResolver $phpStanNodeScopeResolver, ParentConnectingVisitor $parentConnectingVisitor, FunctionLikeParamArgPositionNodeVisitor $functionLikeParamArgPositionNodeVisitor)
+ private $fileWithoutNamespaceNodeTraverser;
+ /**
+ * @readonly
+ * @var \PhpParser\NodeTraverser
+ */
+ private $nodeTraverser;
+ public function __construct(CloningVisitor $cloningVisitor, PHPStanNodeScopeResolver $phpStanNodeScopeResolver, ParentConnectingVisitor $parentConnectingVisitor, FunctionLikeParamArgPositionNodeVisitor $functionLikeParamArgPositionNodeVisitor, FileWithoutNamespaceNodeTraverser $fileWithoutNamespaceNodeTraverser)
{
$this->phpStanNodeScopeResolver = $phpStanNodeScopeResolver;
+ $this->fileWithoutNamespaceNodeTraverser = $fileWithoutNamespaceNodeTraverser;
$this->nodeTraverser = new NodeTraverser();
// needed also for format preserving printing
$this->nodeTraverser->addVisitor($cloningVisitor);
@@ -38,6 +45,7 @@ public function __construct(CloningVisitor $cloningVisitor, PHPStanNodeScopeReso
*/
public function decorateNodesFromFile(File $file, array $stmts) : array
{
+ $stmts = $this->fileWithoutNamespaceNodeTraverser->traverse($stmts);
$stmts = $this->phpStanNodeScopeResolver->processNodes($stmts, $file->getFilePath());
return $this->nodeTraverser->traverse($stmts);
}
diff --git a/packages/NodeTypeResolver/NodeTypeResolver.php b/packages/NodeTypeResolver/NodeTypeResolver.php
index e6c8b2dc1f65..8ab361a695bd 100644
--- a/packages/NodeTypeResolver/NodeTypeResolver.php
+++ b/packages/NodeTypeResolver/NodeTypeResolver.php
@@ -15,8 +15,8 @@
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\NullableType;
-use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Property;
+use PhpParser\Node\UnionType as NodeUnionType;
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassAutoloadingException;
use PHPStan\Reflection\ClassReflection;
@@ -42,10 +42,6 @@
use Rector\TypeDeclaration\PHPStan\ObjectTypeSpecifier;
final class NodeTypeResolver
{
- /**
- * @var array, NodeTypeResolverInterface>
- */
- private $nodeTypeResolvers = [];
/**
* @readonly
* @var \Rector\TypeDeclaration\PHPStan\ObjectTypeSpecifier
@@ -76,10 +72,14 @@ final class NodeTypeResolver
* @var \Rector\Core\Configuration\RenamedClassesDataCollector
*/
private $renamedClassesDataCollector;
+ /**
+ * @var array, NodeTypeResolverInterface>
+ */
+ private $nodeTypeResolvers = [];
/**
* @param NodeTypeResolverInterface[] $nodeTypeResolvers
*/
- public function __construct(ObjectTypeSpecifier $objectTypeSpecifier, ClassAnalyzer $classAnalyzer, GenericClassStringTypeCorrector $genericClassStringTypeCorrector, ReflectionProvider $reflectionProvider, AccessoryNonEmptyStringTypeCorrector $accessoryNonEmptyStringTypeCorrector, RenamedClassesDataCollector $renamedClassesDataCollector, array $nodeTypeResolvers)
+ public function __construct(ObjectTypeSpecifier $objectTypeSpecifier, ClassAnalyzer $classAnalyzer, GenericClassStringTypeCorrector $genericClassStringTypeCorrector, ReflectionProvider $reflectionProvider, AccessoryNonEmptyStringTypeCorrector $accessoryNonEmptyStringTypeCorrector, RenamedClassesDataCollector $renamedClassesDataCollector, iterable $nodeTypeResolvers)
{
$this->objectTypeSpecifier = $objectTypeSpecifier;
$this->classAnalyzer = $classAnalyzer;
@@ -130,7 +130,7 @@ public function isObjectType(Node $node, ObjectType $requiredObjectType) : bool
}
public function getType(Node $node) : Type
{
- if ($node instanceof Property && $node->type instanceof NullableType) {
+ if ($node instanceof Property && $node->type instanceof Node) {
return $this->getType($node->type);
}
if ($node instanceof NullableType) {
@@ -175,6 +175,13 @@ public function getType(Node $node) : Type
}
return new MixedType();
}
+ if ($node instanceof NodeUnionType) {
+ $types = [];
+ foreach ($node->types as $type) {
+ $types[] = $this->getType($type);
+ }
+ return new UnionType($types);
+ }
if (!$node instanceof Expr) {
return new MixedType();
}
diff --git a/packages/NodeTypeResolver/NodeTypeResolver/ClassMethodOrClassConstTypeResolver.php b/packages/NodeTypeResolver/NodeTypeResolver/ClassMethodOrClassConstTypeResolver.php
index 43c651cb45ba..ea46313943ff 100644
--- a/packages/NodeTypeResolver/NodeTypeResolver/ClassMethodOrClassConstTypeResolver.php
+++ b/packages/NodeTypeResolver/NodeTypeResolver/ClassMethodOrClassConstTypeResolver.php
@@ -5,39 +5,19 @@
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassConst;
-use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
+use PHPStan\Analyser\Scope;
+use PHPStan\Reflection\ClassReflection;
+use PHPStan\Type\ObjectType;
use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\Type;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
-use Rector\NodeTypeResolver\NodeTypeResolver;
-use RectorPrefix202306\Symfony\Contracts\Service\Attribute\Required;
+use Rector\NodeTypeResolver\Node\AttributeKey;
/**
* @implements NodeTypeResolverInterface
*/
final class ClassMethodOrClassConstTypeResolver implements NodeTypeResolverInterface
{
- /**
- * @var \Rector\NodeTypeResolver\NodeTypeResolver
- */
- private $nodeTypeResolver;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- public function __construct(BetterNodeFinder $betterNodeFinder)
- {
- $this->betterNodeFinder = $betterNodeFinder;
- }
- /**
- * @required
- */
- public function autowire(NodeTypeResolver $nodeTypeResolver) : void
- {
- $this->nodeTypeResolver = $nodeTypeResolver;
- }
/**
* @return array>
*/
@@ -50,11 +30,16 @@ public function getNodeClasses() : array
*/
public function resolve(Node $node) : Type
{
- $classLike = $this->betterNodeFinder->findParentType($node, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
+ $scope = $node->getAttribute(AttributeKey::SCOPE);
+ if (!$scope instanceof Scope) {
+ // anonymous class
+ return new ObjectWithoutClassType();
+ }
+ $classReflection = $scope->getClassReflection();
+ if (!$classReflection instanceof ClassReflection || $classReflection->isAnonymous()) {
// anonymous class
return new ObjectWithoutClassType();
}
- return $this->nodeTypeResolver->getType($classLike);
+ return new ObjectType($classReflection->getName());
}
}
diff --git a/packages/NodeTypeResolver/NodeTypeResolver/IdentifierTypeResolver.php b/packages/NodeTypeResolver/NodeTypeResolver/IdentifierTypeResolver.php
index 37a44db5cc6b..8a0ad70cd045 100644
--- a/packages/NodeTypeResolver/NodeTypeResolver/IdentifierTypeResolver.php
+++ b/packages/NodeTypeResolver/NodeTypeResolver/IdentifierTypeResolver.php
@@ -5,10 +5,15 @@
use PhpParser\Node;
use PhpParser\Node\Identifier;
+use PHPStan\Type\ArrayType;
use PHPStan\Type\BooleanType;
+use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\FloatType;
use PHPStan\Type\IntegerType;
+use PHPStan\Type\IterableType;
use PHPStan\Type\MixedType;
+use PHPStan\Type\NullType;
+use PHPStan\Type\ObjectWithoutClassType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
@@ -26,20 +31,39 @@ public function getNodeClasses() : array
}
/**
* @param Identifier $node
- * @return StringType|BooleanType|IntegerType|FloatType|MixedType
+ * @return StringType|BooleanType|ConstantBooleanType|NullType|ObjectWithoutClassType|ArrayType|IterableType|IntegerType|FloatType|MixedType
*/
public function resolve(Node $node) : Type
{
- if ($node->toLowerString() === 'string') {
+ $lowerString = $node->toLowerString();
+ if ($lowerString === 'string') {
return new StringType();
}
- if ($node->toLowerString() === 'bool') {
+ if ($lowerString === 'bool') {
return new BooleanType();
}
- if ($node->toLowerString() === 'int') {
+ if ($lowerString === 'false') {
+ return new ConstantBooleanType(\false);
+ }
+ if ($lowerString === 'true') {
+ return new ConstantBooleanType(\true);
+ }
+ if ($lowerString === 'null') {
+ return new NullType();
+ }
+ if ($lowerString === 'object') {
+ return new ObjectWithoutClassType();
+ }
+ if ($lowerString === 'array') {
+ return new ArrayType(new MixedType(), new MixedType());
+ }
+ if ($lowerString === 'int') {
return new IntegerType();
}
- if ($node->toLowerString() === 'float') {
+ if ($lowerString === 'iterable') {
+ return new IterableType(new MixedType(), new MixedType());
+ }
+ if ($lowerString === 'float') {
return new FloatType();
}
return new MixedType();
diff --git a/packages/NodeTypeResolver/NodeTypeResolver/NameTypeResolver.php b/packages/NodeTypeResolver/NodeTypeResolver/NameTypeResolver.php
index bd0736f95825..b831391eeb01 100644
--- a/packages/NodeTypeResolver/NodeTypeResolver/NameTypeResolver.php
+++ b/packages/NodeTypeResolver/NodeTypeResolver/NameTypeResolver.php
@@ -6,18 +6,16 @@
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
-use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassLike;
-use PHPStan\Reflection\ReflectionProvider;
+use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\ArrayType;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\Core\Enum\ObjectReference;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
-use Rector\NodeNameResolver\NodeNameResolver;
+use Rector\Core\Reflection\ReflectionResolver;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
+use RectorPrefix202306\Symfony\Contracts\Service\Attribute\Required;
/**
* @see \Rector\Tests\NodeTypeResolver\PerNodeTypeResolver\NameTypeResolver\NameTypeResolverTest
*
@@ -26,25 +24,15 @@
final class NameTypeResolver implements NodeTypeResolverInterface
{
/**
- * @readonly
- * @var \PHPStan\Reflection\ReflectionProvider
+ * @var \Rector\Core\Reflection\ReflectionResolver
*/
- private $reflectionProvider;
+ private $reflectionResolver;
/**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
+ * @required
*/
- private $betterNodeFinder;
- /**
- * @readonly
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
- public function __construct(ReflectionProvider $reflectionProvider, BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver)
+ public function autowire(ReflectionResolver $reflectionResolver) : void
{
- $this->reflectionProvider = $reflectionProvider;
- $this->betterNodeFinder = $betterNodeFinder;
- $this->nodeNameResolver = $nodeNameResolver;
+ $this->reflectionResolver = $reflectionResolver;
}
/**
* @return array>
@@ -72,18 +60,13 @@ public function resolve(Node $node) : Type
*/
private function resolveParent(Name $name)
{
- $class = $this->betterNodeFinder->findParentType($name, Class_::class);
- if (!$class instanceof Class_) {
- return new MixedType();
- }
- $className = $this->nodeNameResolver->getName($class);
- if (!\is_string($className)) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($name);
+ if (!$classReflection instanceof ClassReflection || !$classReflection->isClass()) {
return new MixedType();
}
- if (!$this->reflectionProvider->hasClass($className)) {
+ if ($classReflection->isAnonymous()) {
return new MixedType();
}
- $classReflection = $this->reflectionProvider->getClass($className);
$parentClassObjectTypes = [];
foreach ($classReflection->getParents() as $parentClassReflection) {
$parentClassObjectTypes[] = new ObjectType($parentClassReflection->getName());
@@ -100,11 +83,11 @@ private function resolveFullyQualifiedName(Name $name) : string
{
$nameValue = $name->toString();
if (\in_array($nameValue, [ObjectReference::SELF, ObjectReference::STATIC, 'this'], \true)) {
- $classLike = $this->betterNodeFinder->findParentType($name, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($name);
+ if (!$classReflection instanceof ClassReflection || $classReflection->isAnonymous()) {
return $name->toString();
}
- return (string) $this->nodeNameResolver->getName($classLike);
+ return $classReflection->getName();
}
return $nameValue;
}
diff --git a/packages/NodeTypeResolver/NodeTypeResolver/ParamTypeResolver.php b/packages/NodeTypeResolver/NodeTypeResolver/ParamTypeResolver.php
index 110989c7a990..8d21d39d286d 100644
--- a/packages/NodeTypeResolver/NodeTypeResolver/ParamTypeResolver.php
+++ b/packages/NodeTypeResolver/NodeTypeResolver/ParamTypeResolver.php
@@ -30,14 +30,6 @@
*/
final class ParamTypeResolver implements NodeTypeResolverInterface
{
- /**
- * @var \Rector\NodeTypeResolver\NodeTypeResolver
- */
- private $nodeTypeResolver;
- /**
- * @var \Rector\StaticTypeMapper\StaticTypeMapper
- */
- private $staticTypeMapper;
/**
* @readonly
* @var \Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser
@@ -58,6 +50,14 @@ final class ParamTypeResolver implements NodeTypeResolverInterface
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
*/
private $betterNodeFinder;
+ /**
+ * @var \Rector\NodeTypeResolver\NodeTypeResolver
+ */
+ private $nodeTypeResolver;
+ /**
+ * @var \Rector\StaticTypeMapper\StaticTypeMapper
+ */
+ private $staticTypeMapper;
public function __construct(SimpleCallableNodeTraverser $simpleCallableNodeTraverser, NodeNameResolver $nodeNameResolver, PhpDocInfoFactory $phpDocInfoFactory, BetterNodeFinder $betterNodeFinder)
{
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
diff --git a/packages/NodeTypeResolver/NodeTypeResolver/PropertyFetchTypeResolver.php b/packages/NodeTypeResolver/NodeTypeResolver/PropertyFetchTypeResolver.php
index c93caf0469ed..86a582ca055c 100644
--- a/packages/NodeTypeResolver/NodeTypeResolver/PropertyFetchTypeResolver.php
+++ b/packages/NodeTypeResolver/NodeTypeResolver/PropertyFetchTypeResolver.php
@@ -5,13 +5,11 @@
use PhpParser\Node;
use PhpParser\Node\Expr\PropertyFetch;
-use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\MixedType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;
@@ -24,10 +22,6 @@
*/
final class PropertyFetchTypeResolver implements NodeTypeResolverInterface
{
- /**
- * @var \Rector\NodeTypeResolver\NodeTypeResolver
- */
- private $nodeTypeResolver;
/**
* @readonly
* @var \Rector\NodeNameResolver\NodeNameResolver
@@ -39,15 +33,13 @@ final class PropertyFetchTypeResolver implements NodeTypeResolverInterface
*/
private $reflectionProvider;
/**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
+ * @var \Rector\NodeTypeResolver\NodeTypeResolver
*/
- private $betterNodeFinder;
- public function __construct(NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider, BetterNodeFinder $betterNodeFinder)
+ private $nodeTypeResolver;
+ public function __construct(NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->reflectionProvider = $reflectionProvider;
- $this->betterNodeFinder = $betterNodeFinder;
}
/**
* @required
@@ -75,14 +67,7 @@ public function resolve(Node $node) : Type
}
$scope = $node->getAttribute(AttributeKey::SCOPE);
if (!$scope instanceof Scope) {
- $classLike = $this->betterNodeFinder->findParentType($node, ClassLike::class);
- // fallback to class, since property fetches are not scoped by PHPStan
- if ($classLike instanceof ClassLike) {
- $scope = $classLike->getAttribute(AttributeKey::SCOPE);
- }
- if (!$scope instanceof Scope) {
- return new MixedType();
- }
+ return new MixedType();
}
return $scope->getType($node);
}
diff --git a/packages/NodeTypeResolver/NodeTypeResolver/PropertyTypeResolver.php b/packages/NodeTypeResolver/NodeTypeResolver/PropertyTypeResolver.php
index 47c390d143a7..f5ac1da8f764 100644
--- a/packages/NodeTypeResolver/NodeTypeResolver/PropertyTypeResolver.php
+++ b/packages/NodeTypeResolver/NodeTypeResolver/PropertyTypeResolver.php
@@ -10,8 +10,6 @@
use PHPStan\Type\Type;
use Rector\NodeTypeResolver\Contract\NodeTypeResolverInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;
-use Rector\NodeTypeResolver\NodeTypeResolver;
-use RectorPrefix202306\Symfony\Contracts\Service\Attribute\Required;
/**
* @see \Rector\Tests\NodeTypeResolver\PerNodeTypeResolver\PropertyTypeResolver\PropertyTypeResolverTest
*
@@ -20,15 +18,13 @@
final class PropertyTypeResolver implements NodeTypeResolverInterface
{
/**
- * @var \Rector\NodeTypeResolver\NodeTypeResolver
+ * @readonly
+ * @var \Rector\NodeTypeResolver\NodeTypeResolver\PropertyFetchTypeResolver
*/
- private $nodeTypeResolver;
- /**
- * @required
- */
- public function autowire(NodeTypeResolver $nodeTypeResolver) : void
+ private $propertyFetchTypeResolver;
+ public function __construct(\Rector\NodeTypeResolver\NodeTypeResolver\PropertyFetchTypeResolver $propertyFetchTypeResolver)
{
- $this->nodeTypeResolver = $nodeTypeResolver;
+ $this->propertyFetchTypeResolver = $propertyFetchTypeResolver;
}
/**
* @return array>
@@ -45,6 +41,6 @@ public function resolve(Node $node) : Type
// fake property to local PropertyFetch → PHPStan understands that
$propertyFetch = new PropertyFetch(new Variable('this'), (string) $node->props[0]->name);
$propertyFetch->setAttribute(AttributeKey::SCOPE, $node->getAttribute(AttributeKey::SCOPE));
- return $this->nodeTypeResolver->getType($propertyFetch);
+ return $this->propertyFetchTypeResolver->resolve($propertyFetch);
}
}
diff --git a/packages/NodeTypeResolver/NodeTypeResolver/StaticCallMethodCallTypeResolver.php b/packages/NodeTypeResolver/NodeTypeResolver/StaticCallMethodCallTypeResolver.php
index fd422791df96..b12ed78930c9 100644
--- a/packages/NodeTypeResolver/NodeTypeResolver/StaticCallMethodCallTypeResolver.php
+++ b/packages/NodeTypeResolver/NodeTypeResolver/StaticCallMethodCallTypeResolver.php
@@ -7,8 +7,8 @@
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
+use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\Php\PhpMethodReflection;
-use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use Rector\NodeNameResolver\NodeNameResolver;
@@ -22,24 +22,18 @@
*/
final class StaticCallMethodCallTypeResolver implements NodeTypeResolverInterface
{
- /**
- * @var \Rector\NodeTypeResolver\NodeTypeResolver
- */
- private $nodeTypeResolver;
/**
* @readonly
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
/**
- * @readonly
- * @var \PHPStan\Reflection\ReflectionProvider
+ * @var \Rector\NodeTypeResolver\NodeTypeResolver
*/
- private $reflectionProvider;
- public function __construct(NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider)
+ private $nodeTypeResolver;
+ public function __construct(NodeNameResolver $nodeNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
- $this->reflectionProvider = $reflectionProvider;
}
/**
* @required
@@ -78,8 +72,8 @@ public function resolve(Node $node) : Type
} else {
$callerType = $this->nodeTypeResolver->getType($node->class);
}
- foreach ($callerType->getReferencedClasses() as $referencedClass) {
- $classMethodReturnType = $this->resolveClassMethodReturnType($referencedClass, $node, $methodName, $scope);
+ foreach ($callerType->getObjectClassReflections() as $classReflection) {
+ $classMethodReturnType = $this->resolveClassMethodReturnType($classReflection, $node, $methodName, $scope);
if (!$classMethodReturnType instanceof MixedType) {
return $classMethodReturnType;
}
@@ -89,12 +83,8 @@ public function resolve(Node $node) : Type
/**
* @param \PhpParser\Node\Expr\StaticCall|\PhpParser\Node\Expr\MethodCall $node
*/
- private function resolveClassMethodReturnType(string $referencedClass, $node, string $methodName, Scope $scope) : Type
+ private function resolveClassMethodReturnType(ClassReflection $classReflection, $node, string $methodName, Scope $scope) : Type
{
- if (!$this->reflectionProvider->hasClass($referencedClass)) {
- return new MixedType();
- }
- $classReflection = $this->reflectionProvider->getClass($referencedClass);
foreach ($classReflection->getAncestors() as $ancestorClassReflection) {
if (!$ancestorClassReflection->hasMethod($methodName)) {
continue;
diff --git a/packages/NodeTypeResolver/NodeTypeResolver/VariableTypeResolver.php b/packages/NodeTypeResolver/NodeTypeResolver/VariableTypeResolver.php
index 52b4f61e7f76..b89bb67cfc9b 100644
--- a/packages/NodeTypeResolver/NodeTypeResolver/VariableTypeResolver.php
+++ b/packages/NodeTypeResolver/NodeTypeResolver/VariableTypeResolver.php
@@ -60,7 +60,7 @@ public function resolve(Node $node) : Type
}
private function resolveTypesFromScope(Variable $variable, string $variableName) : Type
{
- $scope = $this->resolveNodeScope($variable);
+ $scope = $variable->getAttribute(AttributeKey::SCOPE);
if (!$scope instanceof Scope) {
return new MixedType();
}
@@ -70,20 +70,4 @@ private function resolveTypesFromScope(Variable $variable, string $variableName)
// this → object type is easier to work with and consistent with the rest of the code
return $scope->getVariableType($variableName);
}
- private function resolveNodeScope(Variable $variable) : ?Scope
- {
- $scope = $variable->getAttribute(AttributeKey::SCOPE);
- if ($scope instanceof Scope) {
- return $scope;
- }
- return $this->resolveFromParentNodes($variable);
- }
- private function resolveFromParentNodes(Variable $variable) : ?Scope
- {
- $parentNode = $variable->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentNode instanceof Node) {
- return null;
- }
- return $parentNode->getAttribute(AttributeKey::SCOPE);
- }
}
diff --git a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ArgNodeVisitor.php b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ArgNodeVisitor.php
new file mode 100644
index 000000000000..ab92f37a8559
--- /dev/null
+++ b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ArgNodeVisitor.php
@@ -0,0 +1,36 @@
+name instanceof Name) {
+ return null;
+ }
+ $funcCallName = $node->name->toString();
+ foreach ($node->args as $arg) {
+ if (!$arg instanceof Arg) {
+ continue;
+ }
+ if (!$arg->value instanceof Array_) {
+ continue;
+ }
+ $arg->value->setAttribute(AttributeKey::FROM_FUNC_CALL_NAME, $funcCallName);
+ }
+ return null;
+ }
+}
diff --git a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/AssignedToNodeVisitor.php b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/AssignedToNodeVisitor.php
index a7036d0425fb..96140a71d653 100644
--- a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/AssignedToNodeVisitor.php
+++ b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/AssignedToNodeVisitor.php
@@ -18,7 +18,12 @@ public function enterNode(Node $node) : ?Node
if (!$node instanceof Assign) {
return null;
}
+ $node->var->setAttribute(AttributeKey::IS_BEING_ASSIGNED, \true);
$node->expr->setAttribute(AttributeKey::IS_ASSIGNED_TO, \true);
+ if ($node->expr instanceof Assign) {
+ $node->var->setAttribute(AttributeKey::IS_MULTI_ASSIGN, \true);
+ $node->expr->setAttribute(AttributeKey::IS_MULTI_ASSIGN, \true);
+ }
return null;
}
}
diff --git a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefReturnNodeVisitor.php b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefReturnNodeVisitor.php
index d937ec33ec7b..e1917ec753e1 100644
--- a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefReturnNodeVisitor.php
+++ b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefReturnNodeVisitor.php
@@ -35,15 +35,15 @@ public function enterNode(Node $node) : ?Node
if ($stmts === null) {
return null;
}
- $this->simpleCallableNodeTraverser->traverseNodesWithCallable($stmts, static function (Node $subNode) {
- if ($subNode instanceof Class_ || $subNode instanceof FunctionLike) {
+ $this->simpleCallableNodeTraverser->traverseNodesWithCallable($stmts, static function (Node $node) {
+ if ($node instanceof Class_ || $node instanceof FunctionLike) {
return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
}
- if (!$subNode instanceof Return_) {
+ if (!$node instanceof Return_) {
return null;
}
- $subNode->setAttribute(AttributeKey::IS_BYREF_RETURN, \true);
- return $subNode;
+ $node->setAttribute(AttributeKey::IS_BYREF_RETURN, \true);
+ return $node;
});
return null;
}
diff --git a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefVariableNodeVisitor.php b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefVariableNodeVisitor.php
index 59835cf29cc0..e5c60eb719c6 100644
--- a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefVariableNodeVisitor.php
+++ b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ByRefVariableNodeVisitor.php
@@ -4,6 +4,7 @@
namespace Rector\NodeTypeResolver\PHPStan\Scope\NodeVisitor;
use PhpParser\Node;
+use PhpParser\Node\Expr;
use PhpParser\Node\Expr\AssignRef;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Variable;
@@ -33,17 +34,16 @@ public function enterNode(Node $node) : ?Node
return null;
}
$byRefVariableNames = $this->resolveClosureUseIsByRefAttribute($node, []);
- foreach ($node->getParams() as $param) {
- if ($param->byRef && $param->var instanceof Variable) {
- $param->var->setAttribute(AttributeKey::IS_BYREF_VAR, \true);
- $byRefVariableNames[] = $param->var->name;
- }
- }
+ $byRefVariableNames = $this->resolveParamIsByRefAttribute($node, $byRefVariableNames);
$stmts = $node->getStmts();
if ($stmts === null) {
return null;
}
- $this->simpleCallableNodeTraverser->traverseNodesWithCallable($stmts, static function (Node $subNode) use($byRefVariableNames) : ?\PhpParser\Node\Expr\Variable {
+ $this->simpleCallableNodeTraverser->traverseNodesWithCallable($stmts, function (Node $subNode) use(&$byRefVariableNames) : ?\PhpParser\Node\Expr\Variable {
+ if ($subNode instanceof Closure) {
+ $byRefVariableNames = $this->resolveClosureUseIsByRefAttribute($subNode, $byRefVariableNames);
+ return null;
+ }
if (!$subNode instanceof Variable) {
return null;
}
@@ -55,6 +55,20 @@ public function enterNode(Node $node) : ?Node
});
return null;
}
+ /**
+ * @param string[] $byRefVariableNames
+ * @return string[]
+ */
+ private function resolveParamIsByRefAttribute(FunctionLike $functionLike, array $byRefVariableNames) : array
+ {
+ foreach ($functionLike->getParams() as $param) {
+ if ($param->byRef && $param->var instanceof Variable && !$param->var->name instanceof Expr) {
+ $param->var->setAttribute(AttributeKey::IS_BYREF_VAR, \true);
+ $byRefVariableNames[] = $param->var->name;
+ }
+ }
+ return $byRefVariableNames;
+ }
/**
* @param string[] $byRefVariableNames
* @return string[]
@@ -65,7 +79,7 @@ private function resolveClosureUseIsByRefAttribute(FunctionLike $functionLike, a
return $byRefVariableNames;
}
foreach ($functionLike->uses as $closureUse) {
- if ($closureUse->byRef && \is_string($closureUse->var->name)) {
+ if ($closureUse->byRef && !$closureUse->var->name instanceof Expr) {
$closureUse->var->setAttribute(AttributeKey::IS_BYREF_VAR, \true);
$byRefVariableNames[] = $closureUse->var->name;
}
diff --git a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ContextNodeVisitor.php b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ContextNodeVisitor.php
new file mode 100644
index 000000000000..ab7f1df5dd9d
--- /dev/null
+++ b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ContextNodeVisitor.php
@@ -0,0 +1,123 @@
+simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
+ }
+ public function enterNode(Node $node) : ?Node
+ {
+ if ($node instanceof For_ || $node instanceof Foreach_ || $node instanceof While_ || $node instanceof Do_) {
+ $this->processContextInLoop($node);
+ return null;
+ }
+ if ($node instanceof Isset_ || $node instanceof Unset_) {
+ $this->processContextInIssetOrUnset($node);
+ return null;
+ }
+ if ($node instanceof Attribute) {
+ $this->simpleCallableNodeTraverser->traverseNodesWithCallable($node->args, static function (Node $subNode) {
+ if ($subNode instanceof Array_) {
+ $subNode->setAttribute(AttributeKey::IS_ARRAY_IN_ATTRIBUTE, \true);
+ }
+ return null;
+ });
+ }
+ if ($node instanceof If_ || $node instanceof Else_ || $node instanceof ElseIf_) {
+ $this->processContextInIf($node);
+ return null;
+ }
+ if ($node instanceof Return_ && $node->expr instanceof Expr) {
+ $node->expr->setAttribute(AttributeKey::IS_RETURN_EXPR, \true);
+ }
+ if ($node instanceof Arg) {
+ $node->value->setAttribute(AttributeKey::IS_ARG_VALUE, \true);
+ }
+ if ($node instanceof Param) {
+ $this->processContextParam($node);
+ }
+ return null;
+ }
+ private function processContextParam(Param $param) : void
+ {
+ if (!$param->type instanceof Node) {
+ return;
+ }
+ $param->type->setAttribute(AttributeKey::IS_PARAM_TYPE, \true);
+ }
+ /**
+ * @param \PhpParser\Node\Expr\Isset_|\PhpParser\Node\Stmt\Unset_ $node
+ */
+ private function processContextInIssetOrUnset($node) : void
+ {
+ if ($node instanceof Isset_) {
+ foreach ($node->vars as $var) {
+ $var->setAttribute(AttributeKey::IS_ISSET_VAR, \true);
+ }
+ return;
+ }
+ foreach ($node->vars as $var) {
+ $var->setAttribute(AttributeKey::IS_UNSET_VAR, \true);
+ }
+ }
+ /**
+ * @param \PhpParser\Node\Stmt\If_|\PhpParser\Node\Stmt\Else_|\PhpParser\Node\Stmt\ElseIf_ $node
+ */
+ private function processContextInIf($node) : void
+ {
+ foreach ($node->stmts as $stmt) {
+ if ($stmt instanceof Break_) {
+ $stmt->setAttribute(AttributeKey::IS_IN_IF, \true);
+ }
+ }
+ }
+ /**
+ * @param \PhpParser\Node\Stmt\For_|\PhpParser\Node\Stmt\Foreach_|\PhpParser\Node\Stmt\While_|\PhpParser\Node\Stmt\Do_ $node
+ */
+ private function processContextInLoop($node) : void
+ {
+ $this->simpleCallableNodeTraverser->traverseNodesWithCallable($node->stmts, static function (Node $subNode) : ?int {
+ if ($subNode instanceof Class_ || $subNode instanceof Function_ || $subNode instanceof Closure) {
+ return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
+ }
+ if ($subNode instanceof If_ || $subNode instanceof Break_) {
+ $subNode->setAttribute(AttributeKey::IS_IN_LOOP, \true);
+ }
+ return null;
+ });
+ }
+}
diff --git a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/NameNodeVisitor.php b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/NameNodeVisitor.php
new file mode 100644
index 000000000000..cee1995e9779
--- /dev/null
+++ b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/NameNodeVisitor.php
@@ -0,0 +1,51 @@
+name instanceof Name) {
+ $node->name->setAttribute(AttributeKey::IS_NAMESPACE_NAME, \true);
+ return null;
+ }
+ if ($node instanceof UseUse && ($node->type === Use_::TYPE_NORMAL || $node->type === Use_::TYPE_UNKNOWN)) {
+ $node->name->setAttribute(AttributeKey::IS_USEUSE_NAME, \true);
+ return null;
+ }
+ if ($node instanceof FuncCall && $node->name instanceof Name) {
+ $node->name->setAttribute(AttributeKey::IS_FUNCCALL_NAME, \true);
+ return null;
+ }
+ if ($node instanceof ConstFetch) {
+ $node->name->setAttribute(AttributeKey::IS_CONSTFETCH_NAME, \true);
+ return null;
+ }
+ if ($node instanceof New_ && $node->class instanceof Name) {
+ $node->class->setAttribute(AttributeKey::IS_NEW_INSTANCE_NAME, \true);
+ return null;
+ }
+ if (!$node instanceof StaticCall) {
+ return null;
+ }
+ if (!$node->class instanceof Name) {
+ return null;
+ }
+ $node->class->setAttribute(AttributeKey::IS_STATICCALL_CLASS_NAME, \true);
+ return null;
+ }
+}
diff --git a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ObjectNodeVisitor.php b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ObjectNodeVisitor.php
new file mode 100644
index 000000000000..c70d9ad0dff2
--- /dev/null
+++ b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/ObjectNodeVisitor.php
@@ -0,0 +1,25 @@
+var->setAttribute(AttributeKey::IS_OBJECT_CALLER, \true);
+ return null;
+ }
+ if ($node instanceof StaticCall) {
+ $node->class->setAttribute(AttributeKey::IS_OBJECT_CALLER, \true);
+ }
+ return null;
+ }
+}
diff --git a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/RemoveDeepChainMethodCallNodeVisitor.php b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/RemoveDeepChainMethodCallNodeVisitor.php
index d29f7b165dd6..3ee5f0fff07c 100644
--- a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/RemoveDeepChainMethodCallNodeVisitor.php
+++ b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/RemoveDeepChainMethodCallNodeVisitor.php
@@ -18,6 +18,11 @@
*/
final class RemoveDeepChainMethodCallNodeVisitor extends NodeVisitorAbstract implements ScopeResolverNodeVisitorInterface
{
+ /**
+ * @readonly
+ * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
+ */
+ private $betterNodeFinder;
/**
* @readonly
* @var int
@@ -27,11 +32,6 @@ final class RemoveDeepChainMethodCallNodeVisitor extends NodeVisitorAbstract imp
* @var \PhpParser\Node\Stmt\Expression|null
*/
private $removingExpression;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
public function __construct(BetterNodeFinder $betterNodeFinder, ParameterProvider $parameterProvider)
{
$this->betterNodeFinder = $betterNodeFinder;
diff --git a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/StmtKeyNodeVisitor.php b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/StmtKeyNodeVisitor.php
index 7234ef4ab3ed..a27d9d58ab20 100644
--- a/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/StmtKeyNodeVisitor.php
+++ b/packages/NodeTypeResolver/PHPStan/Scope/NodeVisitor/StmtKeyNodeVisitor.php
@@ -6,12 +6,39 @@
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Declare_;
+use PhpParser\Node\Stmt\Namespace_;
use PhpParser\NodeVisitorAbstract;
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PHPStan\Scope\Contract\NodeVisitor\ScopeResolverNodeVisitorInterface;
final class StmtKeyNodeVisitor extends NodeVisitorAbstract implements ScopeResolverNodeVisitorInterface
{
+ /**
+ * @param Node[] $nodes
+ */
+ public function beforeTraverse(array $nodes)
+ {
+ if ($nodes === []) {
+ return null;
+ }
+ if (!$nodes[0] instanceof Declare_ && !$nodes[0] instanceof Namespace_) {
+ return null;
+ }
+ // on target node or no other root stmt, eg: only namespace without declare, no need to index
+ if (\count($nodes) === 1) {
+ return null;
+ }
+ // ensure statement depth is 0 to avoid declare in deep statements
+ // eg: declare(ticks=1) @see https://www.php.net/manual/en/control-structures.declare.php#123674
+ $statementDepth = $nodes[0]->getAttribute(AttributeKey::STATEMENT_DEPTH);
+ if ($statementDepth > 0 || $statementDepth === null) {
+ return null;
+ }
+ foreach ($nodes as $key => $node) {
+ $node->setAttribute(AttributeKey::STMT_KEY, $key);
+ }
+ return $nodes;
+ }
public function enterNode(Node $node) : ?Node
{
if (!$node instanceof StmtsAwareInterface && !$node instanceof ClassLike && !$node instanceof Declare_) {
@@ -20,6 +47,7 @@ public function enterNode(Node $node) : ?Node
if ($node->stmts === null) {
return null;
}
+ $node->stmts = \array_values($node->stmts);
// re-index stmt key under current node
foreach ($node->stmts as $key => $childStmt) {
$childStmt->setAttribute(AttributeKey::STMT_KEY, $key);
diff --git a/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php b/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php
index 7ba6f930b7c7..a699d54cffb7 100644
--- a/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php
+++ b/packages/NodeTypeResolver/PHPStan/Scope/PHPStanNodeScopeResolver.php
@@ -11,12 +11,23 @@
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\AssignOp;
use PhpParser\Node\Expr\BinaryOp;
+use PhpParser\Node\Expr\CallLike;
use PhpParser\Node\Expr\Cast;
+use PhpParser\Node\Expr\ClassConstFetch;
+use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
+use PhpParser\Node\Expr\MethodCall;
+use PhpParser\Node\Expr\New_;
+use PhpParser\Node\Expr\NullsafeMethodCall;
+use PhpParser\Node\Expr\PropertyFetch;
+use PhpParser\Node\Expr\StaticCall;
+use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Expr\Ternary;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
+use PhpParser\Node\IntersectionType;
use PhpParser\Node\Name;
+use PhpParser\Node\NullableType;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
@@ -32,6 +43,7 @@
use PhpParser\Node\Stmt\Switch_;
use PhpParser\Node\Stmt\Trait_;
use PhpParser\Node\Stmt\TryCatch;
+use PhpParser\Node\UnionType;
use PhpParser\NodeTraverser;
use PHPStan\AnalysedCodeException;
use PHPStan\Analyser\MutatingScope;
@@ -47,6 +59,8 @@
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
+use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
+use Rector\Core\PHPStan\NodeVisitor\WrappedNodeRestoringNodeVisitor;
use Rector\Core\Util\Reflection\PrivatesAccessor;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
@@ -58,15 +72,6 @@
*/
final class PHPStanNodeScopeResolver
{
- /**
- * @var string
- */
- private const CONTEXT = 'context';
- /**
- * @readonly
- * @var \PhpParser\NodeTraverser
- */
- private $nodeTraverser;
/**
* @readonly
* @var \Rector\Caching\Detector\ChangedFilesDetector
@@ -107,10 +112,19 @@ final class PHPStanNodeScopeResolver
* @var \Rector\Core\NodeAnalyzer\ClassAnalyzer
*/
private $classAnalyzer;
+ /**
+ * @var string
+ */
+ private const CONTEXT = 'context';
+ /**
+ * @readonly
+ * @var \PhpParser\NodeTraverser
+ */
+ private $nodeTraverser;
/**
* @param ScopeResolverNodeVisitorInterface[] $nodeVisitors
*/
- public function __construct(ChangedFilesDetector $changedFilesDetector, DependencyResolver $dependencyResolver, NodeScopeResolver $nodeScopeResolver, ReflectionProvider $reflectionProvider, array $nodeVisitors, \Rector\NodeTypeResolver\PHPStan\Scope\ScopeFactory $scopeFactory, PrivatesAccessor $privatesAccessor, NodeNameResolver $nodeNameResolver, ClassAnalyzer $classAnalyzer)
+ public function __construct(ChangedFilesDetector $changedFilesDetector, DependencyResolver $dependencyResolver, NodeScopeResolver $nodeScopeResolver, ReflectionProvider $reflectionProvider, iterable $nodeVisitors, \Rector\NodeTypeResolver\PHPStan\Scope\ScopeFactory $scopeFactory, PrivatesAccessor $privatesAccessor, NodeNameResolver $nodeNameResolver, ClassAnalyzer $classAnalyzer)
{
$this->changedFilesDetector = $changedFilesDetector;
$this->dependencyResolver = $dependencyResolver;
@@ -141,9 +155,16 @@ public function processNodes(array $stmts, string $filePath, ?MutatingScope $for
$scope = $formerMutatingScope ?? $this->scopeFactory->createFromFile($filePath);
// skip chain method calls, performance issue: https://github.com/phpstan/phpstan/issues/254
$nodeCallback = function (Node $node, MutatingScope $mutatingScope) use(&$nodeCallback, $isScopeRefreshing, $filePath) : void {
+ if ($node instanceof FileWithoutNamespace) {
+ $this->nodeScopeResolver->processNodes($node->stmts, $mutatingScope, $nodeCallback);
+ return;
+ }
if (($node instanceof Expression || $node instanceof Return_ || $node instanceof Assign || $node instanceof EnumCase || $node instanceof AssignOp || $node instanceof Cast) && $node->expr instanceof Expr) {
$node->expr->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
+ if ($node instanceof Assign || $node instanceof AssignOp) {
+ $this->processAssign($node, $mutatingScope);
+ }
if ($node instanceof Ternary) {
$this->processTernary($node, $mutatingScope);
}
@@ -178,9 +199,31 @@ public function processNodes(array $stmts, string $filePath, ?MutatingScope $for
if ($node instanceof FuncCall && $node->name instanceof Expr) {
$node->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
- if ($node instanceof Assign || $node instanceof AssignOp) {
- // decorate value as well
+ if ($node instanceof NullableType) {
+ $node->type->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ }
+ if ($node instanceof UnionType || $node instanceof IntersectionType) {
+ foreach ($node->types as $type) {
+ $type->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ }
+ }
+ if ($node instanceof StaticPropertyFetch) {
+ $node->class->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ $node->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ }
+ if ($node instanceof PropertyFetch) {
$node->var->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ $node->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ }
+ if ($node instanceof CallLike) {
+ $this->processCallike($node, $mutatingScope);
+ }
+ if ($node instanceof ConstFetch) {
+ $node->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ }
+ if ($node instanceof ClassConstFetch) {
+ $node->class->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ $node->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
}
if ($node instanceof Trait_) {
$traitName = $this->resolveClassName($node);
@@ -214,14 +257,64 @@ public function processNodes(array $stmts, string $filePath, ?MutatingScope $for
};
return $this->processNodesWithDependentFiles($filePath, $stmts, $scope, $nodeCallback);
}
- private function setChildOfUnreachableStatementNodeAttribute(Stmt $stmt, MutatingScope $mutatingScope) : void
+ private function processCallike(CallLike $callLike, MutatingScope $mutatingScope) : void
{
- if ($stmt->getAttribute(AttributeKey::IS_UNREACHABLE) !== \true) {
+ $this->processArgsForCallike($callLike, $mutatingScope);
+ if ($callLike instanceof StaticCall) {
+ $callLike->class->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ $callLike->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ }
+ if ($callLike instanceof MethodCall) {
+ $callLike->var->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ $callLike->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ }
+ if ($callLike instanceof FuncCall) {
+ $callLike->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ }
+ if ($callLike instanceof New_ && !$callLike->class instanceof Class_) {
+ $callLike->class->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ }
+ if ($callLike instanceof NullsafeMethodCall) {
+ $callLike->var->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ $callLike->name->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ }
+ }
+ private function processArgsForCallike(Expr $expr, MutatingScope $mutatingScope) : void
+ {
+ if (!$expr instanceof CallLike) {
return;
}
+ if (!$expr->isFirstClassCallable()) {
+ foreach ($expr->getArgs() as $arg) {
+ $arg->value->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ }
+ }
+ }
+ /**
+ * @param \PhpParser\Node\Expr\Assign|\PhpParser\Node\Expr\AssignOp $assign
+ */
+ private function processAssign($assign, MutatingScope $mutatingScope) : void
+ {
+ if (!$assign->var instanceof Variable || !$assign->var->name instanceof Variable) {
+ $assign->var->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ return;
+ }
+ $expr = $assign;
+ while ($expr instanceof Assign || $expr instanceof AssignOp) {
+ $this->processArgsForCallike($expr->expr, $mutatingScope);
+ // decorate value as well
+ $expr->var->setAttribute(AttributeKey::SCOPE, $mutatingScope);
+ $expr = $expr->expr;
+ }
+ }
+ private function setChildOfUnreachableStatementNodeAttribute(Stmt $stmt, MutatingScope $mutatingScope) : void
+ {
if (!$stmt instanceof StmtsAwareInterface && !$stmt instanceof ClassLike && !$stmt instanceof Declare_) {
return;
}
+ if ($stmt->getAttribute(AttributeKey::IS_UNREACHABLE) !== \true) {
+ return;
+ }
if ($stmt->stmts === null) {
return;
}
@@ -331,6 +424,9 @@ private function processNodesWithDependentFiles(string $filePath, array $stmts,
{
$this->nodeScopeResolver->processNodes($stmts, $mutatingScope, $nodeCallback);
$this->resolveAndSaveDependentFiles($stmts, $mutatingScope, $filePath);
+ $nodeTraverser = new NodeTraverser();
+ $nodeTraverser->addVisitor(new WrappedNodeRestoringNodeVisitor());
+ $nodeTraverser->traverse($stmts);
return $stmts;
}
/**
diff --git a/packages/NodeTypeResolver/PhpDocNodeVisitor/ClassRenamePhpDocNodeVisitor.php b/packages/NodeTypeResolver/PhpDocNodeVisitor/ClassRenamePhpDocNodeVisitor.php
index 9c1de81bfbda..0fea53a0bb16 100644
--- a/packages/NodeTypeResolver/PhpDocNodeVisitor/ClassRenamePhpDocNodeVisitor.php
+++ b/packages/NodeTypeResolver/PhpDocNodeVisitor/ClassRenamePhpDocNodeVisitor.php
@@ -6,8 +6,8 @@
use PhpParser\Node as PhpParserNode;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\GroupUse;
-use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Use_;
+use PHPStan\Analyser\Scope;
use PHPStan\PhpDocParser\Ast\Node;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
@@ -17,21 +17,14 @@
use Rector\Core\Configuration\CurrentNodeProvider;
use Rector\Core\Configuration\RectorConfigProvider;
use Rector\Core\Exception\ShouldNotHappenException;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Naming\Naming\UseImportsResolver;
-use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\ValueObject\OldToNewType;
use Rector\PhpDocParser\PhpDocParser\PhpDocNodeVisitor\AbstractPhpDocNodeVisitor;
-use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Rector\StaticTypeMapper\ValueObject\Type\ShortenedObjectType;
final class ClassRenamePhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
{
- /**
- * @var OldToNewType[]
- */
- private $oldToNewTypes = [];
/**
* @readonly
* @var \Rector\StaticTypeMapper\StaticTypeMapper
@@ -47,28 +40,20 @@ final class ClassRenamePhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
* @var \Rector\Naming\Naming\UseImportsResolver
*/
private $useImportsResolver;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- /**
- * @readonly
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
/**
* @readonly
* @var \Rector\Core\Configuration\RectorConfigProvider
*/
private $rectorConfigProvider;
- public function __construct(StaticTypeMapper $staticTypeMapper, CurrentNodeProvider $currentNodeProvider, UseImportsResolver $useImportsResolver, BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver, RectorConfigProvider $rectorConfigProvider)
+ /**
+ * @var OldToNewType[]
+ */
+ private $oldToNewTypes = [];
+ public function __construct(StaticTypeMapper $staticTypeMapper, CurrentNodeProvider $currentNodeProvider, UseImportsResolver $useImportsResolver, RectorConfigProvider $rectorConfigProvider)
{
$this->staticTypeMapper = $staticTypeMapper;
$this->currentNodeProvider = $currentNodeProvider;
$this->useImportsResolver = $useImportsResolver;
- $this->betterNodeFinder = $betterNodeFinder;
- $this->nodeNameResolver = $nodeNameResolver;
$this->rectorConfigProvider = $rectorConfigProvider;
}
public function beforeTraverse(Node $node) : void
@@ -105,7 +90,7 @@ public function enterNode(Node $node) : ?Node
if (!$objectType->equals($oldToNewType->getOldType())) {
continue;
}
- $newTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($oldToNewType->getNewType(), TypeKind::ANY);
+ $newTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($oldToNewType->getNewType());
$parentType = $node->getAttribute(PhpDocAttributeKey::PARENT);
if ($parentType instanceof TypeNode) {
// mirror attributes
@@ -137,15 +122,17 @@ private function resolveNamespacedName(IdentifierTypeNode $identifierTypeNode, P
if ($staticType instanceof ShortenedObjectType) {
return $name;
}
- $uses = $this->useImportsResolver->resolveForNode($phpParserNode);
- $namespace = $this->betterNodeFinder->findParentType($phpParserNode, Namespace_::class);
- if (!$namespace instanceof Namespace_) {
- return $this->resolveNamefromUse($uses, $name);
+ $uses = $this->useImportsResolver->resolve();
+ $scope = $phpParserNode->getAttribute(AttributeKey::SCOPE);
+ if (!$scope instanceof Scope) {
+ if (!$phpParserNode->hasAttribute(AttributeKey::ORIGINAL_NODE)) {
+ return $this->resolveNamefromUse($uses, $name);
+ }
+ return '';
}
- $originalNode = $namespace->getAttribute(AttributeKey::ORIGINAL_NODE);
- $namespaceName = (string) $this->nodeNameResolver->getName($namespace);
- if ($originalNode instanceof Namespace_ && !$this->nodeNameResolver->isName($originalNode, $namespaceName)) {
- return $name;
+ $namespaceName = $scope->getNamespace();
+ if ($namespaceName === null) {
+ return $this->resolveNamefromUse($uses, $name);
}
if ($uses === []) {
return $namespaceName . '\\' . $name;
diff --git a/packages/NodeTypeResolver/PhpDocNodeVisitor/NameImportingPhpDocNodeVisitor.php b/packages/NodeTypeResolver/PhpDocNodeVisitor/NameImportingPhpDocNodeVisitor.php
index 88887002f43f..69cf2bdaf4aa 100644
--- a/packages/NodeTypeResolver/PhpDocNodeVisitor/NameImportingPhpDocNodeVisitor.php
+++ b/packages/NodeTypeResolver/PhpDocNodeVisitor/NameImportingPhpDocNodeVisitor.php
@@ -25,10 +25,6 @@
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
final class NameImportingPhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
{
- /**
- * @var PhpParserNode|null
- */
- private $currentPhpParserNode;
/**
* @readonly
* @var \Rector\StaticTypeMapper\StaticTypeMapper
@@ -59,6 +55,10 @@ final class NameImportingPhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @var PhpParserNode|null
+ */
+ private $currentPhpParserNode;
public function __construct(StaticTypeMapper $staticTypeMapper, ParameterProvider $parameterProvider, ClassNameImportSkipper $classNameImportSkipper, UseNodesToAddCollector $useNodesToAddCollector, CurrentFileProvider $currentFileProvider, ReflectionProvider $reflectionProvider)
{
$this->staticTypeMapper = $staticTypeMapper;
diff --git a/packages/NodeTypeResolver/PhpDocNodeVisitor/UnderscoreRenamePhpDocNodeVisitor.php b/packages/NodeTypeResolver/PhpDocNodeVisitor/UnderscoreRenamePhpDocNodeVisitor.php
index 06a6049312f2..b9e3009e9821 100644
--- a/packages/NodeTypeResolver/PhpDocNodeVisitor/UnderscoreRenamePhpDocNodeVisitor.php
+++ b/packages/NodeTypeResolver/PhpDocNodeVisitor/UnderscoreRenamePhpDocNodeVisitor.php
@@ -12,10 +12,6 @@
use Rector\StaticTypeMapper\StaticTypeMapper;
final class UnderscoreRenamePhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
{
- /**
- * @var bool
- */
- private $hasChanged = \false;
/**
* @readonly
* @var \Rector\StaticTypeMapper\StaticTypeMapper
@@ -31,6 +27,10 @@ final class UnderscoreRenamePhpDocNodeVisitor extends AbstractPhpDocNodeVisitor
* @var \PhpParser\Node
*/
private $phpNode;
+ /**
+ * @var bool
+ */
+ private $hasChanged = \false;
public function __construct(StaticTypeMapper $staticTypeMapper, PseudoNamespaceToNamespace $pseudoNamespaceToNamespace, \PhpParser\Node $phpNode)
{
$this->staticTypeMapper = $staticTypeMapper;
diff --git a/packages/NodeTypeResolver/Reflection/BetterReflection/SourceLocator/IntermediateSourceLocator.php b/packages/NodeTypeResolver/Reflection/BetterReflection/SourceLocator/IntermediateSourceLocator.php
index 9e15776e3ca3..f59f689a1f41 100644
--- a/packages/NodeTypeResolver/Reflection/BetterReflection/SourceLocator/IntermediateSourceLocator.php
+++ b/packages/NodeTypeResolver/Reflection/BetterReflection/SourceLocator/IntermediateSourceLocator.php
@@ -8,29 +8,24 @@
use PHPStan\BetterReflection\Reflection\Reflection;
use PHPStan\BetterReflection\Reflector\Reflector;
use PHPStan\BetterReflection\SourceLocator\Type\SourceLocator;
-use Rector\NodeTypeResolver\Contract\SourceLocatorProviderInterface;
+use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider;
final class IntermediateSourceLocator implements SourceLocator
{
/**
- * @var SourceLocatorProviderInterface[]
* @readonly
+ * @var \Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider
*/
- private $sourceLocatorProviders;
- /**
- * @param SourceLocatorProviderInterface[] $sourceLocatorProviders
- */
- public function __construct(array $sourceLocatorProviders)
+ private $dynamicSourceLocatorProvider;
+ public function __construct(DynamicSourceLocatorProvider $dynamicSourceLocatorProvider)
{
- $this->sourceLocatorProviders = $sourceLocatorProviders;
+ $this->dynamicSourceLocatorProvider = $dynamicSourceLocatorProvider;
}
public function locateIdentifier(Reflector $reflector, Identifier $identifier) : ?Reflection
{
- foreach ($this->sourceLocatorProviders as $sourceLocatorProvider) {
- $sourceLocator = $sourceLocatorProvider->provide();
- $reflection = $sourceLocator->locateIdentifier($reflector, $identifier);
- if ($reflection instanceof Reflection) {
- return $reflection;
- }
+ $sourceLocator = $this->dynamicSourceLocatorProvider->provide();
+ $reflection = $sourceLocator->locateIdentifier($reflector, $identifier);
+ if ($reflection instanceof Reflection) {
+ return $reflection;
}
return null;
}
@@ -40,12 +35,10 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier) :
*/
public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType) : array
{
- foreach ($this->sourceLocatorProviders as $sourceLocatorProvider) {
- $sourceLocator = $sourceLocatorProvider->provide();
- $reflections = $sourceLocator->locateIdentifiersByType($reflector, $identifierType);
- if ($reflections !== []) {
- return $reflections;
- }
+ $sourceLocator = $this->dynamicSourceLocatorProvider->provide();
+ $reflections = $sourceLocator->locateIdentifiersByType($reflector, $identifierType);
+ if ($reflections !== []) {
+ return $reflections;
}
return [];
}
diff --git a/packages/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php b/packages/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php
index 0ceba8119481..4d6178829a3c 100644
--- a/packages/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php
+++ b/packages/NodeTypeResolver/Reflection/BetterReflection/SourceLocatorProvider/DynamicSourceLocatorProvider.php
@@ -9,14 +9,23 @@
use PHPStan\Reflection\BetterReflection\SourceLocator\FileNodesFetcher;
use PHPStan\Reflection\BetterReflection\SourceLocator\OptimizedDirectorySourceLocator;
use PHPStan\Reflection\BetterReflection\SourceLocator\OptimizedSingleFileSourceLocator;
-use Rector\NodeTypeResolver\Contract\SourceLocatorProviderInterface;
use Rector\Testing\PHPUnit\StaticPHPUnitEnvironment;
use RectorPrefix202306\Webmozart\Assert\Assert;
/**
* @api phpstan external
*/
-final class DynamicSourceLocatorProvider implements SourceLocatorProviderInterface
+final class DynamicSourceLocatorProvider
{
+ /**
+ * @readonly
+ * @var \PHPStan\Reflection\BetterReflection\SourceLocator\FileNodesFetcher
+ */
+ private $fileNodesFetcher;
+ /**
+ * @readonly
+ * @var \PHPStan\Php\PhpVersion
+ */
+ private $phpVersion;
/**
* @var string[]
*/
@@ -29,16 +38,6 @@ final class DynamicSourceLocatorProvider implements SourceLocatorProviderInterfa
* @var \PHPStan\BetterReflection\SourceLocator\Type\AggregateSourceLocator|null
*/
private $aggregateSourceLocator;
- /**
- * @readonly
- * @var \PHPStan\Reflection\BetterReflection\SourceLocator\FileNodesFetcher
- */
- private $fileNodesFetcher;
- /**
- * @readonly
- * @var \PHPStan\Php\PhpVersion
- */
- private $phpVersion;
public function __construct(FileNodesFetcher $fileNodesFetcher, PhpVersion $phpVersion)
{
$this->fileNodesFetcher = $fileNodesFetcher;
@@ -80,4 +79,8 @@ public function addFilesByDirectory(string $directory, array $files) : void
Assert::allString($files);
$this->filesByDirectory[$directory] = $files;
}
+ public function isPathsEmpty() : bool
+ {
+ return $this->filePaths === [] && $this->filesByDirectory === [];
+ }
}
diff --git a/packages/NodeTypeResolver/TypeAnalyzer/ArrayTypeAnalyzer.php b/packages/NodeTypeResolver/TypeAnalyzer/ArrayTypeAnalyzer.php
index 0a32cb937ce2..ef2f3a2218c3 100644
--- a/packages/NodeTypeResolver/TypeAnalyzer/ArrayTypeAnalyzer.php
+++ b/packages/NodeTypeResolver/TypeAnalyzer/ArrayTypeAnalyzer.php
@@ -10,6 +10,7 @@
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Property;
use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
+use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\Php\PhpPropertyReflection;
use PHPStan\Type\Accessory\HasOffsetType;
use PHPStan\Type\Accessory\NonEmptyArrayType;
@@ -20,7 +21,7 @@
use PHPStan\Type\Type;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
+use Rector\Core\PhpParser\ClassLikeAstResolver;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
@@ -36,11 +37,6 @@ final class ArrayTypeAnalyzer
* @var \Rector\NodeTypeResolver\NodeTypeResolver
*/
private $nodeTypeResolver;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
/**
* @readonly
* @var \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory
@@ -51,13 +47,18 @@ final class ArrayTypeAnalyzer
* @var \Rector\Core\Reflection\ReflectionResolver
*/
private $reflectionResolver;
- public function __construct(NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, BetterNodeFinder $betterNodeFinder, PhpDocInfoFactory $phpDocInfoFactory, ReflectionResolver $reflectionResolver)
+ /**
+ * @readonly
+ * @var \Rector\Core\PhpParser\ClassLikeAstResolver
+ */
+ private $classLikeAstResolver;
+ public function __construct(NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, PhpDocInfoFactory $phpDocInfoFactory, ReflectionResolver $reflectionResolver, ClassLikeAstResolver $classLikeAstResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->nodeTypeResolver = $nodeTypeResolver;
- $this->betterNodeFinder = $betterNodeFinder;
$this->phpDocInfoFactory = $phpDocInfoFactory;
$this->reflectionResolver = $reflectionResolver;
+ $this->classLikeAstResolver = $classLikeAstResolver;
}
public function isArrayType(Expr $expr) : bool
{
@@ -108,14 +109,16 @@ private function isPropertyFetchWithArrayDocblockWithoutDefault(Expr $expr) : bo
if (!$expr instanceof PropertyFetch && !$expr instanceof StaticPropertyFetch) {
return \false;
}
- $classLike = $this->betterNodeFinder->findParentType($expr, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($expr);
+ if (!$classReflection instanceof ClassReflection) {
return \false;
}
$propertyName = $this->nodeNameResolver->getName($expr->name);
if ($propertyName === null) {
return \false;
}
+ /** @var ClassLike $classLike */
+ $classLike = $this->classLikeAstResolver->resolveClassFromClassReflection($classReflection);
$property = $classLike->getProperty($propertyName);
if (!$property instanceof Property) {
return \false;
@@ -139,10 +142,12 @@ private function isPropertyFetchWithArrayDefault(Expr $expr) : bool
if (!$expr instanceof PropertyFetch && !$expr instanceof StaticPropertyFetch) {
return \false;
}
- $classLike = $this->betterNodeFinder->findParentType($expr, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($expr);
+ if (!$classReflection instanceof ClassReflection) {
return \false;
}
+ /** @var ClassLike $classLike */
+ $classLike = $this->classLikeAstResolver->resolveClassFromClassReflection($classReflection);
$propertyName = $this->nodeNameResolver->getName($expr->name);
if ($propertyName === null) {
return \false;
diff --git a/packages/NodeTypeResolver/TypeAnalyzer/CountableTypeAnalyzer.php b/packages/NodeTypeResolver/TypeAnalyzer/CountableTypeAnalyzer.php
index 0fa2be3a6b39..f4e51207e122 100644
--- a/packages/NodeTypeResolver/TypeAnalyzer/CountableTypeAnalyzer.php
+++ b/packages/NodeTypeResolver/TypeAnalyzer/CountableTypeAnalyzer.php
@@ -8,10 +8,6 @@
use Rector\NodeTypeResolver\NodeTypeResolver;
final class CountableTypeAnalyzer
{
- /**
- * @var ObjectType[]
- */
- private $countableObjectTypes = [];
/**
* @readonly
* @var \Rector\NodeTypeResolver\TypeAnalyzer\ArrayTypeAnalyzer
@@ -22,6 +18,10 @@ final class CountableTypeAnalyzer
* @var \Rector\NodeTypeResolver\NodeTypeResolver
*/
private $nodeTypeResolver;
+ /**
+ * @var ObjectType[]
+ */
+ private $countableObjectTypes = [];
public function __construct(\Rector\NodeTypeResolver\TypeAnalyzer\ArrayTypeAnalyzer $arrayTypeAnalyzer, NodeTypeResolver $nodeTypeResolver)
{
$this->arrayTypeAnalyzer = $arrayTypeAnalyzer;
diff --git a/packages/NodeTypeResolver/TypeComparator/TypeComparator.php b/packages/NodeTypeResolver/TypeComparator/TypeComparator.php
index 3c38dc894e01..12d223d59688 100644
--- a/packages/NodeTypeResolver/TypeComparator/TypeComparator.php
+++ b/packages/NodeTypeResolver/TypeComparator/TypeComparator.php
@@ -4,9 +4,9 @@
namespace Rector\NodeTypeResolver\TypeComparator;
use PhpParser\Node;
-use PhpParser\Node\Stmt\Class_;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
+use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\ArrayType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\Constant\ConstantArrayType;
@@ -22,7 +22,7 @@
use PHPStan\Type\TypeTraverser;
use PHPStan\Type\UnionType;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
+use Rector\Core\Reflection\ReflectionResolver;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\NodeTypeResolver\PHPStan\TypeHasher;
use Rector\StaticTypeMapper\StaticTypeMapper;
@@ -62,10 +62,10 @@ final class TypeComparator
private $typeFactory;
/**
* @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
+ * @var \Rector\Core\Reflection\ReflectionResolver
*/
- private $betterNodeFinder;
- public function __construct(TypeHasher $typeHasher, TypeNormalizer $typeNormalizer, StaticTypeMapper $staticTypeMapper, \Rector\NodeTypeResolver\TypeComparator\ArrayTypeComparator $arrayTypeComparator, \Rector\NodeTypeResolver\TypeComparator\ScalarTypeComparator $scalarTypeComparator, TypeFactory $typeFactory, BetterNodeFinder $betterNodeFinder)
+ private $reflectionResolver;
+ public function __construct(TypeHasher $typeHasher, TypeNormalizer $typeNormalizer, StaticTypeMapper $staticTypeMapper, \Rector\NodeTypeResolver\TypeComparator\ArrayTypeComparator $arrayTypeComparator, \Rector\NodeTypeResolver\TypeComparator\ScalarTypeComparator $scalarTypeComparator, TypeFactory $typeFactory, ReflectionResolver $reflectionResolver)
{
$this->typeHasher = $typeHasher;
$this->typeNormalizer = $typeNormalizer;
@@ -73,7 +73,7 @@ public function __construct(TypeHasher $typeHasher, TypeNormalizer $typeNormaliz
$this->arrayTypeComparator = $arrayTypeComparator;
$this->scalarTypeComparator = $scalarTypeComparator;
$this->typeFactory = $typeFactory;
- $this->betterNodeFinder = $betterNodeFinder;
+ $this->reflectionResolver = $reflectionResolver;
}
public function areTypesEqual(Type $firstType, Type $secondType) : bool
{
@@ -254,10 +254,10 @@ private function isThisTypeInFinalClass(Type $phpStanDocType, Type $phpParserNod
if (!$isStaticReturnDocTypeWithThisType) {
return \true;
}
- $class = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$class instanceof Class_) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($node);
+ if (!$classReflection instanceof ClassReflection || !$classReflection->isClass()) {
return \false;
}
- return $class->isFinal();
+ return $classReflection->isFinalByKeyword();
}
}
diff --git a/packages/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php b/packages/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php
index 2f04838d16b9..ac6f4570adba 100644
--- a/packages/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php
+++ b/packages/PHPStanStaticTypeMapper/Contract/TypeMapperInterface.php
@@ -21,9 +21,8 @@ interface TypeMapperInterface
public function getNodeClass() : string;
/**
* @param TType $type
- * @param TypeKind::* $typeKind
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode;
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode;
/**
* @param TType $type
* @param TypeKind::* $typeKind
diff --git a/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php b/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php
index 2ef74c3e7967..67dac40fff10 100644
--- a/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/PHPStanStaticTypeMapper.php
@@ -10,7 +10,9 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\Accessory\HasMethodType;
use PHPStan\Type\ConditionalType;
+use PHPStan\Type\ObjectShapeType;
use PHPStan\Type\Type;
+use Rector\BetterPhpDocParser\ValueObject\Type\FullyQualifiedIdentifierTypeNode;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
@@ -24,20 +26,17 @@ final class PHPStanStaticTypeMapper
/**
* @param TypeMapperInterface[] $typeMappers
*/
- public function __construct(array $typeMappers)
+ public function __construct(iterable $typeMappers)
{
$this->typeMappers = $typeMappers;
}
- /**
- * @param TypeKind::* $typeKind
- */
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
foreach ($this->typeMappers as $typeMapper) {
if (!\is_a($type, $typeMapper->getNodeClass(), \true)) {
continue;
}
- return $typeMapper->mapToPHPStanPhpDocTypeNode($type, $typeKind);
+ return $typeMapper->mapToPHPStanPhpDocTypeNode($type);
}
if ($type->isString()->yes()) {
return new IdentifierTypeNode('string');
@@ -48,6 +47,9 @@ public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeN
if ($type instanceof ConditionalType) {
return new IdentifierTypeNode('mixed');
}
+ if ($type instanceof ObjectShapeType) {
+ return new FullyQualifiedIdentifierTypeNode('stdClass');
+ }
throw new NotImplementedYetException(__METHOD__ . ' for ' . \get_class($type));
}
/**
diff --git a/packages/PHPStanStaticTypeMapper/TypeAnalyzer/UnionTypeCommonTypeNarrower.php b/packages/PHPStanStaticTypeMapper/TypeAnalyzer/UnionTypeCommonTypeNarrower.php
index 200fbd6e6cb7..e519ddc0428c 100644
--- a/packages/PHPStanStaticTypeMapper/TypeAnalyzer/UnionTypeCommonTypeNarrower.php
+++ b/packages/PHPStanStaticTypeMapper/TypeAnalyzer/UnionTypeCommonTypeNarrower.php
@@ -20,12 +20,6 @@
use Rector\NodeTypeResolver\NodeTypeCorrector\GenericClassStringTypeCorrector;
final class UnionTypeCommonTypeNarrower
{
- /**
- * Key = the winner Array = the group of types matched
- *
- * @var array|class-string<\PHPStan\PhpDocParser\Ast\Node>|class-string>>
- */
- private const PRIORITY_TYPES = [ClassLike::class => [ClassLike::class], FunctionLike::class => [FunctionLike::class], BinaryOp::class => [BinaryOp::class, Expr::class], Expr::class => [Node::class, Expr::class], Stmt::class => [Node::class, Stmt::class], PhpDocTagValueNode::class => [PhpDocTagValueNode::class, \PHPStan\PhpDocParser\Ast\Node::class], Node::class => [Node::class], RectorInterface::class => [RectorInterface::class]];
/**
* @readonly
* @var \Rector\NodeTypeResolver\NodeTypeCorrector\GenericClassStringTypeCorrector
@@ -36,6 +30,12 @@ final class UnionTypeCommonTypeNarrower
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * Key = the winner Array = the group of types matched
+ *
+ * @var array|class-string<\PHPStan\PhpDocParser\Ast\Node>|class-string>>
+ */
+ private const PRIORITY_TYPES = [ClassLike::class => [ClassLike::class], FunctionLike::class => [FunctionLike::class], BinaryOp::class => [BinaryOp::class, Expr::class], Expr::class => [Node::class, Expr::class], Stmt::class => [Node::class, Stmt::class], PhpDocTagValueNode::class => [PhpDocTagValueNode::class, \PHPStan\PhpDocParser\Ast\Node::class], Node::class => [Node::class], RectorInterface::class => [RectorInterface::class]];
public function __construct(GenericClassStringTypeCorrector $genericClassStringTypeCorrector, ReflectionProvider $reflectionProvider)
{
$this->genericClassStringTypeCorrector = $genericClassStringTypeCorrector;
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryLiteralStringTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryLiteralStringTypeMapper.php
index 2c43b9d2a497..72c65928b7ea 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryLiteralStringTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryLiteralStringTypeMapper.php
@@ -36,7 +36,7 @@ public function getNodeClass() : string
/**
* @param AccessoryLiteralStringType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('string');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNonEmptyStringTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNonEmptyStringTypeMapper.php
index 54ef8c126820..0e09e6b7b81f 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNonEmptyStringTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNonEmptyStringTypeMapper.php
@@ -36,7 +36,7 @@ public function getNodeClass() : string
/**
* @param AccessoryNonEmptyStringType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('string');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNonFalsyStringTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNonFalsyStringTypeMapper.php
index 6ac01bfaf45d..deecac5aa4f4 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNonFalsyStringTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNonFalsyStringTypeMapper.php
@@ -36,7 +36,7 @@ public function getNodeClass() : string
/**
* @param AccessoryNonFalsyStringType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('string');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNumericStringTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNumericStringTypeMapper.php
index b7ceb77b5fa5..c31d22595da1 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNumericStringTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/AccessoryNumericStringTypeMapper.php
@@ -36,7 +36,7 @@ public function getNodeClass() : string
/**
* @param AccessoryNumericStringType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('string');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/ArrayShapeTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/ArrayShapeTypeMapper.php
index f3c5d90a816b..bb88f0e756ca 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/ArrayShapeTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/ArrayShapeTypeMapper.php
@@ -12,7 +12,6 @@
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\MixedType;
use PHPStan\Type\NeverType;
-use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;
final class ArrayShapeTypeMapper
{
@@ -52,7 +51,7 @@ public function mapConstantArrayType(ConstantArrayType $constantArrayType)
}
$keyDocTypeNode = new IdentifierTypeNode($keyValue);
$valueType = $constantArrayType->getValueTypes()[$index];
- $valueDocTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($valueType, TypeKind::RETURN);
+ $valueDocTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($valueType);
$arrayShapeItemNodes[] = new ArrayShapeItemNode($keyDocTypeNode, $constantArrayType->isOptionalKey($index), $valueDocTypeNode);
}
return new ArrayShapeNode($arrayShapeItemNodes);
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php
index 4a9da6896039..f216a1267bf3 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/ArrayTypeMapper.php
@@ -22,7 +22,6 @@
use Rector\BetterPhpDocParser\ValueObject\Type\BracketsAwareUnionTypeNode;
use Rector\BetterPhpDocParser\ValueObject\Type\SpacingAwareArrayTypeNode;
use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;
-use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;
use Rector\PHPStanStaticTypeMapper\TypeAnalyzer\UnionTypeCommonTypeNarrower;
use Rector\TypeDeclaration\NodeTypeAnalyzer\DetailedTypeAnalyzer;
@@ -84,32 +83,31 @@ public function getNodeClass() : string
return ArrayType::class;
}
/**
- * @param TypeKind::* $typeKind
* @param ArrayType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
$itemType = $type->getItemType();
if ($itemType instanceof UnionType && !$type instanceof ConstantArrayType) {
- return $this->createArrayTypeNodeFromUnionType($itemType, $typeKind);
+ return $this->createArrayTypeNodeFromUnionType($itemType);
}
- if ($type instanceof ConstantArrayType && $typeKind === TypeKind::RETURN) {
+ if ($type instanceof ConstantArrayType) {
$arrayShapeNode = $this->arrayShapeTypeMapper->mapConstantArrayType($type);
if ($arrayShapeNode instanceof TypeNode) {
return $arrayShapeNode;
}
}
if ($itemType instanceof ArrayType && $this->isGenericArrayCandidate($itemType)) {
- return $this->createGenericArrayType($type, $typeKind, \true);
+ return $this->createGenericArrayType($type, \true);
}
if ($this->isGenericArrayCandidate($type)) {
- return $this->createGenericArrayType($type, $typeKind, \true);
+ return $this->createGenericArrayType($type, \true);
}
- $narrowedTypeNode = $this->narrowConstantArrayTypeOfUnionType($type, $itemType, $typeKind);
+ $narrowedTypeNode = $this->narrowConstantArrayTypeOfUnionType($type, $itemType);
if ($narrowedTypeNode instanceof TypeNode) {
return $narrowedTypeNode;
}
- $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($itemType, $typeKind);
+ $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($itemType);
return new SpacingAwareArrayTypeNode($itemTypeNode);
}
/**
@@ -119,14 +117,11 @@ public function mapToPhpParserNode(Type $type, string $typeKind) : ?Node
{
return new Identifier('array');
}
- /**
- * @param TypeKind::* $typeKind
- */
- private function createArrayTypeNodeFromUnionType(UnionType $unionType, string $typeKind) : SpacingAwareArrayTypeNode
+ private function createArrayTypeNodeFromUnionType(UnionType $unionType) : SpacingAwareArrayTypeNode
{
$unionedArrayType = [];
foreach ($unionType->getTypes() as $unionedType) {
- $typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($unionedType, $typeKind);
+ $typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($unionedType);
$unionedArrayType[(string) $typeNode] = $typeNode;
}
if (\count($unionedArrayType) > 1) {
@@ -166,22 +161,19 @@ private function isGenericArrayCandidate(ArrayType $arrayType) : bool
}
return \false;
}
- /**
- * @param TypeKind::* $typeKind
- */
- private function createGenericArrayType(ArrayType $arrayType, string $typeKind, bool $withKey = \false) : GenericTypeNode
+ private function createGenericArrayType(ArrayType $arrayType, bool $withKey = \false) : GenericTypeNode
{
$itemType = $arrayType->getItemType();
- $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($itemType, $typeKind);
+ $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($itemType);
$identifierTypeNode = new IdentifierTypeNode('array');
// is class-string[] list only
if ($this->isClassStringArrayType($arrayType)) {
$withKey = \false;
}
if ($withKey) {
- $keyTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($arrayType->getKeyType(), $typeKind);
+ $keyTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($arrayType->getKeyType());
if ($itemTypeNode instanceof BracketsAwareUnionTypeNode && $this->isPairClassTooDetailed($itemType)) {
- $genericTypes = [$keyTypeNode, $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode(new ClassStringType(), $typeKind)];
+ $genericTypes = [$keyTypeNode, $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode(new ClassStringType())];
} else {
$genericTypes = [$keyTypeNode, $itemTypeNode];
}
@@ -213,35 +205,31 @@ private function isIntegerKeyAndNonNestedArray(ArrayType $arrayType) : bool
}
return !$arrayType->getItemType() instanceof ArrayType;
}
- /**
- * @param TypeKind::* $typeKind
- */
- private function narrowConstantArrayTypeOfUnionType(ArrayType $arrayType, Type $itemType, string $typeKind) : ?TypeNode
+ private function narrowConstantArrayTypeOfUnionType(ArrayType $arrayType, Type $itemType) : ?TypeNode
{
if ($arrayType instanceof ConstantArrayType && $itemType instanceof UnionType) {
$narrowedItemType = $this->unionTypeCommonTypeNarrower->narrowToSharedObjectType($itemType);
if ($narrowedItemType instanceof ObjectType) {
- $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($narrowedItemType, $typeKind);
+ $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($narrowedItemType);
return new SpacingAwareArrayTypeNode($itemTypeNode);
}
$narrowedItemType = $this->unionTypeCommonTypeNarrower->narrowToGenericClassStringType($itemType);
if ($narrowedItemType instanceof GenericClassStringType) {
- return $this->createTypeNodeFromGenericClassStringType($narrowedItemType, $typeKind);
+ return $this->createTypeNodeFromGenericClassStringType($narrowedItemType);
}
}
return null;
}
/**
- * @param TypeKind::* $typeKind
* @return \PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode|\PHPStan\PhpDocParser\Ast\Type\GenericTypeNode
*/
- private function createTypeNodeFromGenericClassStringType(GenericClassStringType $genericClassStringType, string $typeKind)
+ private function createTypeNodeFromGenericClassStringType(GenericClassStringType $genericClassStringType)
{
$genericType = $genericClassStringType->getGenericType();
if ($genericType instanceof ObjectType && !$this->reflectionProvider->hasClass($genericType->getClassName())) {
return new IdentifierTypeNode($genericType->getClassName());
}
- $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($genericClassStringType, $typeKind);
+ $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($genericClassStringType);
return new GenericTypeNode(new IdentifierTypeNode('array'), [$itemTypeNode]);
}
private function isClassStringArrayType(ArrayType $arrayType) : bool
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php
index c08fb2255944..a710135050e1 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/BooleanTypeMapper.php
@@ -37,7 +37,7 @@ public function getNodeClass() : string
/**
* @param BooleanType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
if ($type instanceof ConstantBooleanType) {
return new IdentifierTypeNode($type->getValue() ? 'true' : 'false');
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php
index 3e1422b7cdf6..d1fbb92c57c1 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/CallableTypeMapper.php
@@ -39,12 +39,11 @@ public function getNodeClass() : string
return CallableType::class;
}
/**
- * @param TypeKind::* $typeKind
* @param CallableType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
- $returnTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($type->getReturnType(), $typeKind);
+ $returnTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($type->getReturnType());
return new SpacingAwareCallableTypeNode(new IdentifierTypeNode('callable'), [], $returnTypeNode);
}
/**
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php
index a693e4c5b060..634ae4623ae9 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/ClassStringTypeMapper.php
@@ -43,10 +43,10 @@ public function getNodeClass() : string
/**
* @param ClassStringType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
if ($type instanceof GenericClassStringType) {
- return $this->genericClassStringTypeMapper->mapToPHPStanPhpDocTypeNode($type, $typeKind);
+ return $this->genericClassStringTypeMapper->mapToPHPStanPhpDocTypeNode($type);
}
return new IdentifierTypeNode('class-string');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php
index b12cc6a206d0..59dcfb39827f 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/ClosureTypeMapper.php
@@ -36,11 +36,11 @@ public function getNodeClass() : string
/**
* @param ClosureType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
$identifierTypeNode = new IdentifierTypeNode($type->getClassName());
- $returnDocTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($type->getReturnType(), $typeKind);
- $callableTypeParameterNodes = $this->createCallableTypeParameterNodes($type, $typeKind);
+ $returnDocTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($type->getReturnType());
+ $callableTypeParameterNodes = $this->createCallableTypeParameterNodes($type);
// callable parameters must be of specific type
Assert::allIsInstanceOf($callableTypeParameterNodes, CallableTypeParameterNode::class);
return new SpacingAwareCallableTypeNode($identifierTypeNode, $callableTypeParameterNodes, $returnDocTypeNode);
@@ -64,15 +64,14 @@ public function autowire(PHPStanStaticTypeMapper $phpStanStaticTypeMapper) : voi
$this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper;
}
/**
- * @param TypeKind::* $typeKind
* @return CallableTypeParameterNode[]
*/
- private function createCallableTypeParameterNodes(ClosureType $closureType, string $typeKind) : array
+ private function createCallableTypeParameterNodes(ClosureType $closureType) : array
{
$callableTypeParameterNodes = [];
foreach ($closureType->getParameters() as $parameterReflection) {
/** @var ParameterReflection $parameterReflection */
- $typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($parameterReflection->getType(), $typeKind);
+ $typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($parameterReflection->getType());
$callableTypeParameterNodes[] = new CallableTypeParameterNode($typeNode, $parameterReflection->passedByReference()->yes(), $parameterReflection->isVariadic(), $parameterReflection->getName() !== '' && $parameterReflection->getName() !== '0' ? '$' . $parameterReflection->getName() : '', $parameterReflection->isOptional());
}
return $callableTypeParameterNodes;
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php
index b32238d7cd1f..e67840c43e20 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/ConditionalTypeForParameterMapper.php
@@ -7,6 +7,7 @@
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
use PHPStan\Type\ConditionalTypeForParameter;
use PHPStan\Type\Type;
+use PHPStan\Type\TypeCombinator;
use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;
@@ -36,11 +37,11 @@ public function getNodeClass() : string
}
/**
* @param ConditionalTypeForParameter $type
- * @param TypeKind::* $typeKind
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
- return $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($type->getTarget(), $typeKind);
+ $type = TypeCombinator::union($type->getIf(), $type->getElse());
+ return $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($type);
}
/**
* @param ConditionalTypeForParameter $type
@@ -48,6 +49,7 @@ public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeN
*/
public function mapToPhpParserNode(Type $type, string $typeKind) : ?Node
{
- return $this->phpStanStaticTypeMapper->mapToPhpParserNode($type->getTarget(), $typeKind);
+ $type = TypeCombinator::union($type->getIf(), $type->getElse());
+ return $this->phpStanStaticTypeMapper->mapToPhpParserNode($type, $typeKind);
}
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php
index 771c080e6892..c33404c09d10 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/FloatTypeMapper.php
@@ -36,7 +36,7 @@ public function getNodeClass() : string
/**
* @param FloatType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('float');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/GenericClassStringTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/GenericClassStringTypeMapper.php
index daaded24d835..573033d328d2 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/GenericClassStringTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/GenericClassStringTypeMapper.php
@@ -22,15 +22,15 @@
*/
final class GenericClassStringTypeMapper implements TypeMapperInterface
{
- /**
- * @var \Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper
- */
- private $phpStanStaticTypeMapper;
/**
* @readonly
* @var \Rector\Core\Php\PhpVersionProvider
*/
private $phpVersionProvider;
+ /**
+ * @var \Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper
+ */
+ private $phpStanStaticTypeMapper;
public function __construct(PhpVersionProvider $phpVersionProvider)
{
$this->phpVersionProvider = $phpVersionProvider;
@@ -52,11 +52,11 @@ public function getNodeClass() : string
/**
* @param GenericClassStringType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
$attributeAwareIdentifierTypeNode = new IdentifierTypeNode('class-string');
$genericType = $this->resolveGenericObjectType($type);
- $genericTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($genericType, $typeKind);
+ $genericTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($genericType);
return new GenericTypeNode($attributeAwareIdentifierTypeNode, [$genericTypeNode]);
}
/**
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php
index ed2aa5a3d35c..b9072c3a561a 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/HasMethodTypeMapper.php
@@ -33,7 +33,7 @@ public function getNodeClass() : string
/**
* @param HasMethodType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('object');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/HasOffsetTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/HasOffsetTypeMapper.php
index e5dd6aed4a32..c68f5046187c 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/HasOffsetTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/HasOffsetTypeMapper.php
@@ -26,7 +26,7 @@ public function getNodeClass() : string
/**
* @param HasOffsetType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new ArrayTypeNode(new IdentifierTypeNode('mixed'));
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/HasOffsetValueTypeTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/HasOffsetValueTypeTypeMapper.php
index cde309d1df3b..4b3d09abfbff 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/HasOffsetValueTypeTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/HasOffsetValueTypeTypeMapper.php
@@ -26,7 +26,7 @@ public function getNodeClass() : string
/**
* @param HasOffsetValueType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new ArrayTypeNode(new IdentifierTypeNode('mixed'));
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php
index 8b53ebc92b00..21d801f20cf6 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/HasPropertyTypeMapper.php
@@ -33,7 +33,7 @@ public function getNodeClass() : string
/**
* @param HasPropertyType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('object');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php
index b44750309b03..a75983f136e7 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/IntegerTypeMapper.php
@@ -36,7 +36,7 @@ public function getNodeClass() : string
/**
* @param IntegerType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('int');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php
index 49331eadd395..2998ddb1ca11 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/IntersectionTypeMapper.php
@@ -23,10 +23,6 @@
*/
final class IntersectionTypeMapper implements TypeMapperInterface
{
- /**
- * @var \Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper
- */
- private $phpStanStaticTypeMapper;
/**
* @readonly
* @var \Rector\Core\Php\PhpVersionProvider
@@ -37,6 +33,10 @@ final class IntersectionTypeMapper implements TypeMapperInterface
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @var \Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper
+ */
+ private $phpStanStaticTypeMapper;
public function __construct(PhpVersionProvider $phpVersionProvider, ReflectionProvider $reflectionProvider)
{
$this->phpVersionProvider = $phpVersionProvider;
@@ -59,11 +59,11 @@ public function getNodeClass() : string
/**
* @param IntersectionType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
$intersectionTypesNodes = [];
foreach ($type->getTypes() as $intersectionedType) {
- $intersectionTypesNodes[] = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($intersectionedType, $typeKind);
+ $intersectionTypesNodes[] = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($intersectionedType);
}
$intersectionTypesNodes = \array_unique($intersectionTypesNodes);
if (\count($intersectionTypesNodes) === 1) {
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php
index ea24fedb59bc..d9eed74deeaa 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/IterableTypeMapper.php
@@ -41,9 +41,9 @@ public function getNodeClass() : string
/**
* @param IterableType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
- $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($type->getItemType(), $typeKind);
+ $itemTypeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($type->getItemType());
if ($itemTypeNode instanceof UnionTypeNode) {
return $this->convertUnionArrayTypeNodesToArrayTypeOfUnionTypeNodes($itemTypeNode);
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php
index 6877ded0d198..5de46ec1f43e 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/MixedTypeMapper.php
@@ -36,7 +36,7 @@ public function getNodeClass() : string
/**
* @param MixedType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('mixed');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php
index 4ca0a2516ab9..424e16c960c2 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/NeverTypeMapper.php
@@ -9,7 +9,6 @@
use PHPStan\Type\NeverType;
use PHPStan\Type\Type;
use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;
-use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
/**
* @implements TypeMapperInterface
*/
@@ -23,15 +22,11 @@ public function getNodeClass() : string
return NeverType::class;
}
/**
- * @param TypeKind::* $typeKind
* @param NeverType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
- if ($typeKind === TypeKind::RETURN) {
- return new IdentifierTypeNode('never');
- }
- return new IdentifierTypeNode('mixed');
+ return new IdentifierTypeNode('never');
}
/**
* @param NeverType $type
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/NonEmptyArrayTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/NonEmptyArrayTypeMapper.php
index c4575383521b..62aa0b3c73b8 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/NonEmptyArrayTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/NonEmptyArrayTypeMapper.php
@@ -26,7 +26,7 @@ public function getNodeClass() : string
/**
* @param NonEmptyArrayType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new SpacingAwareArrayTypeNode(new IdentifierTypeNode('mixed'));
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php
index 77280ae1a616..bee99d121a2e 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/NullTypeMapper.php
@@ -26,7 +26,7 @@ public function getNodeClass() : string
/**
* @param NullType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('null');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php
index 1b8d9b8b7a3a..7cdaa1239607 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/ObjectTypeMapper.php
@@ -15,7 +15,6 @@
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
use Rector\PHPStanStaticTypeMapper\Contract\TypeMapperInterface;
-use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;
use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedGenericObjectType;
@@ -43,7 +42,7 @@ public function getNodeClass() : string
/**
* @param ObjectType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
if ($type instanceof ShortenedObjectType) {
return new IdentifierTypeNode($type->getClassName());
@@ -52,7 +51,7 @@ public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeN
return new IdentifierTypeNode($type->getClassName());
}
if ($type instanceof GenericObjectType) {
- return $this->mapGenericObjectType($type, $typeKind);
+ return $this->mapGenericObjectType($type);
}
if ($type instanceof NonExistingObjectType) {
// possibly generic type
@@ -97,10 +96,7 @@ public function autowire(PHPStanStaticTypeMapper $phpStanStaticTypeMapper) : voi
{
$this->phpStanStaticTypeMapper = $phpStanStaticTypeMapper;
}
- /**
- * @param TypeKind::* $typeKind
- */
- private function mapGenericObjectType(GenericObjectType $genericObjectType, string $typeKind) : TypeNode
+ private function mapGenericObjectType(GenericObjectType $genericObjectType) : TypeNode
{
$name = $this->resolveGenericObjectTypeName($genericObjectType);
$identifierTypeNode = new IdentifierTypeNode($name);
@@ -110,7 +106,7 @@ private function mapGenericObjectType(GenericObjectType $genericObjectType, stri
if ($name === 'Iterator' && $genericType instanceof MixedType && $key === 0) {
continue;
}
- $typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($genericType, $typeKind);
+ $typeNode = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($genericType);
$genericTypeNodes[] = $typeNode;
}
if ($genericTypeNodes === []) {
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php
index 1e69fc3d5e32..db5990f6174c 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/ObjectWithoutClassTypeMapper.php
@@ -42,7 +42,7 @@ public function getNodeClass() : string
/**
* @param ObjectWithoutClassType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
if ($type instanceof ParentObjectWithoutClassType) {
return new IdentifierTypeNode('parent');
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/OversizedArrayTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/OversizedArrayTypeMapper.php
index a2063648bbd8..f6e6b089165f 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/OversizedArrayTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/OversizedArrayTypeMapper.php
@@ -25,10 +25,9 @@ public function getNodeClass() : string
return OversizedArrayType::class;
}
/**
- * @param TypeKind::* $typeKind
* @param OversizedArrayType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new ArrayTypeNode(new IdentifierTypeNode('mixed'));
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php
index cf8dbcb062bf..cd0bfec89401 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/ParentStaticTypeMapper.php
@@ -26,7 +26,7 @@ public function getNodeClass() : string
/**
* @param ParentStaticType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode(ObjectReference::PARENT);
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php
index f145bbcb3a03..ee974fc5357a 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/ResourceTypeMapper.php
@@ -24,7 +24,7 @@ public function getNodeClass() : string
/**
* @param ResourceType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('resource');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/SelfObjectTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/SelfObjectTypeMapper.php
index ad1ab9d7dd99..0aba7e078f2a 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/SelfObjectTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/SelfObjectTypeMapper.php
@@ -25,7 +25,7 @@ public function getNodeClass() : string
/**
* @param SelfObjectType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('self');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php
index fd8051b90d0e..0f1f6f761a41 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/StaticTypeMapper.php
@@ -41,7 +41,7 @@ public function getNodeClass() : string
/**
* @param StaticType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new ThisTypeNode();
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php
index cae06e390c6e..b8198a57cf9e 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/StrictMixedTypeMapper.php
@@ -29,7 +29,7 @@ public function getNodeClass() : string
/**
* @param StrictMixedType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode(self::MIXED);
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php
index d16ffb0f601e..5f5afafd68ec 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/StringTypeMapper.php
@@ -36,7 +36,7 @@ public function getNodeClass() : string
/**
* @param StringType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('string');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/ThisTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/ThisTypeMapper.php
index e1ebf123b4ae..aaa3a114066b 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/ThisTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/ThisTypeMapper.php
@@ -25,7 +25,7 @@ public function getNodeClass() : string
/**
* @param ThisType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new ThisTypeNode();
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php
index 7dcc6010a841..c67f9aaed072 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/TypeWithClassNameTypeMapper.php
@@ -36,7 +36,7 @@ public function getNodeClass() : string
/**
* @param TypeWithClassName $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode('string-class');
}
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php
index 2c1734d0e4eb..c7ec9b521877 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/UnionTypeMapper.php
@@ -46,10 +46,6 @@
*/
final class UnionTypeMapper implements TypeMapperInterface
{
- /**
- * @var \Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper
- */
- private $phpStanStaticTypeMapper;
/**
* @readonly
* @var \Rector\PHPStanStaticTypeMapper\DoctrineTypeAnalyzer
@@ -85,6 +81,10 @@ final class UnionTypeMapper implements TypeMapperInterface
* @var \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory
*/
private $typeFactory;
+ /**
+ * @var \Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper
+ */
+ private $phpStanStaticTypeMapper;
public function __construct(DoctrineTypeAnalyzer $doctrineTypeAnalyzer, PhpVersionProvider $phpVersionProvider, UnionTypeAnalyzer $unionTypeAnalyzer, BoolUnionTypeAnalyzer $boolUnionTypeAnalyzer, UnionTypeCommonTypeNarrower $unionTypeCommonTypeNarrower, NodeNameResolver $nodeNameResolver, TypeFactory $typeFactory)
{
$this->doctrineTypeAnalyzer = $doctrineTypeAnalyzer;
@@ -112,7 +112,7 @@ public function getNodeClass() : string
/**
* @param UnionType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
$unionTypesNodes = [];
$skipIterable = $this->shouldSkipIterable($type);
@@ -120,7 +120,7 @@ public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeN
if ($unionedType instanceof IterableType && $skipIterable) {
continue;
}
- $unionTypesNodes[] = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($unionedType, $typeKind);
+ $unionTypesNodes[] = $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($unionedType);
}
$unionTypesNodes = \array_unique($unionTypesNodes);
return new BracketsAwareUnionTypeNode($unionTypesNodes);
diff --git a/packages/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php b/packages/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php
index bc6c445015e4..637f4056ee1c 100644
--- a/packages/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php
+++ b/packages/PHPStanStaticTypeMapper/TypeMapper/VoidTypeMapper.php
@@ -18,15 +18,15 @@
*/
final class VoidTypeMapper implements TypeMapperInterface
{
- /**
- * @var string
- */
- private const VOID = 'void';
/**
* @readonly
* @var \Rector\Core\Php\PhpVersionProvider
*/
private $phpVersionProvider;
+ /**
+ * @var string
+ */
+ private const VOID = 'void';
public function __construct(PhpVersionProvider $phpVersionProvider)
{
$this->phpVersionProvider = $phpVersionProvider;
@@ -41,7 +41,7 @@ public function getNodeClass() : string
/**
* @param VoidType $type
*/
- public function mapToPHPStanPhpDocTypeNode(Type $type, string $typeKind) : TypeNode
+ public function mapToPHPStanPhpDocTypeNode(Type $type) : TypeNode
{
return new IdentifierTypeNode(self::VOID);
}
diff --git a/packages/Parallel/Application/ParallelFileProcessor.php b/packages/Parallel/Application/ParallelFileProcessor.php
index 449b63879951..a73f97fcbf5d 100644
--- a/packages/Parallel/Application/ParallelFileProcessor.php
+++ b/packages/Parallel/Application/ParallelFileProcessor.php
@@ -35,14 +35,6 @@
*/
final class ParallelFileProcessor
{
- /**
- * @var int
- */
- private const SYSTEM_ERROR_LIMIT = 50;
- /**
- * @var \Symplify\EasyParallel\ValueObject\ProcessPool|null
- */
- private $processPool = null;
/**
* @readonly
* @var \Rector\Parallel\Command\WorkerCommandLineFactory
@@ -53,6 +45,14 @@ final class ParallelFileProcessor
* @var \Rector\Core\Configuration\Parameter\ParameterProvider
*/
private $parameterProvider;
+ /**
+ * @var int
+ */
+ private const SYSTEM_ERROR_LIMIT = 50;
+ /**
+ * @var \Symplify\EasyParallel\ValueObject\ProcessPool|null
+ */
+ private $processPool = null;
public function __construct(WorkerCommandLineFactory $workerCommandLineFactory, ParameterProvider $parameterProvider)
{
$this->workerCommandLineFactory = $workerCommandLineFactory;
@@ -104,6 +104,10 @@ public function process(Schedule $schedule, string $mainScript, callable $postFi
++$systemErrorsCount;
$reachedSystemErrorsCountLimit = \true;
$this->processPool->quitAll();
+ // This sleep has to be here, because event though we have called $this->processPool->quitAll(),
+ // it takes some time for the child processes to actually die, during which they can still write to cache
+ // @see https://github.com/rectorphp/rector-src/pull/3834/files#r1231696531
+ \sleep(1);
};
$timeoutInSeconds = $this->parameterProvider->provideIntParameter(Option::PARALLEL_JOB_TIMEOUT_IN_SECONDS);
for ($i = 0; $i < $numberOfProcesses; ++$i) {
diff --git a/packages/Parallel/WorkerRunner.php b/packages/Parallel/WorkerRunner.php
index 9959de5f910f..6b13671e3553 100644
--- a/packages/Parallel/WorkerRunner.php
+++ b/packages/Parallel/WorkerRunner.php
@@ -8,7 +8,6 @@
use RectorPrefix202306\Nette\Utils\FileSystem;
use Rector\Caching\Detector\ChangedFilesDetector;
use Rector\Core\Application\ApplicationFileProcessor;
-use Rector\Core\Application\FileSystem\RemovedAndAddedFilesProcessor;
use Rector\Core\Console\Style\RectorConsoleOutputStyle;
use Rector\Core\Contract\Processor\FileProcessorInterface;
use Rector\Core\Provider\CurrentFileProvider;
@@ -25,10 +24,6 @@
use Throwable;
final class WorkerRunner
{
- /**
- * @var string
- */
- private const RESULT = 'result';
/**
* @readonly
* @var \Rector\Core\Util\ArrayParametersMerger
@@ -49,11 +44,6 @@ final class WorkerRunner
* @var \Rector\Core\Console\Style\RectorConsoleOutputStyle
*/
private $rectorConsoleOutputStyle;
- /**
- * @readonly
- * @var \Rector\Core\Application\FileSystem\RemovedAndAddedFilesProcessor
- */
- private $removedAndAddedFilesProcessor;
/**
* @readonly
* @var \Rector\Core\Application\ApplicationFileProcessor
@@ -69,16 +59,19 @@ final class WorkerRunner
* @readonly
*/
private $fileProcessors = [];
+ /**
+ * @var string
+ */
+ private const RESULT = 'result';
/**
* @param FileProcessorInterface[] $fileProcessors
*/
- public function __construct(ArrayParametersMerger $arrayParametersMerger, CurrentFileProvider $currentFileProvider, DynamicSourceLocatorDecorator $dynamicSourceLocatorDecorator, RectorConsoleOutputStyle $rectorConsoleOutputStyle, RemovedAndAddedFilesProcessor $removedAndAddedFilesProcessor, ApplicationFileProcessor $applicationFileProcessor, ChangedFilesDetector $changedFilesDetector, array $fileProcessors = [])
+ public function __construct(ArrayParametersMerger $arrayParametersMerger, CurrentFileProvider $currentFileProvider, DynamicSourceLocatorDecorator $dynamicSourceLocatorDecorator, RectorConsoleOutputStyle $rectorConsoleOutputStyle, ApplicationFileProcessor $applicationFileProcessor, ChangedFilesDetector $changedFilesDetector, iterable $fileProcessors = [])
{
$this->arrayParametersMerger = $arrayParametersMerger;
$this->currentFileProvider = $currentFileProvider;
$this->dynamicSourceLocatorDecorator = $dynamicSourceLocatorDecorator;
$this->rectorConsoleOutputStyle = $rectorConsoleOutputStyle;
- $this->removedAndAddedFilesProcessor = $removedAndAddedFilesProcessor;
$this->applicationFileProcessor = $applicationFileProcessor;
$this->changedFilesDetector = $changedFilesDetector;
$this->fileProcessors = $fileProcessors;
@@ -114,7 +107,7 @@ public function run(Encoder $encoder, Decoder $decoder, Configuration $configura
$errorAndFileDiffs = $this->processFile($file, $configuration, $errorAndFileDiffs);
if ($errorAndFileDiffs[Bridge::SYSTEM_ERRORS] !== []) {
$this->invalidateFile($file);
- } elseif (!$configuration->isDryRun()) {
+ } elseif (!$configuration->isDryRun() || $errorAndFileDiffs[Bridge::FILE_DIFFS] === []) {
$this->changedFilesDetector->cacheFileWithDependencies($file->getFilePath());
}
} catch (Throwable $throwable) {
@@ -123,7 +116,6 @@ public function run(Encoder $encoder, Decoder $decoder, Configuration $configura
$this->invalidateFile($file);
}
}
- $this->removedAndAddedFilesProcessor->run($configuration);
/**
* this invokes all listeners listening $decoder->on(...) @see \Symplify\EasyParallel\Enum\ReactEvent::DATA
*/
diff --git a/packages/PhpAttribute/AnnotationToAttributeMapper.php b/packages/PhpAttribute/AnnotationToAttributeMapper.php
index af6b1cc76702..b18b52af15de 100644
--- a/packages/PhpAttribute/AnnotationToAttributeMapper.php
+++ b/packages/PhpAttribute/AnnotationToAttributeMapper.php
@@ -5,10 +5,14 @@
use PhpParser\BuilderHelpers;
use PhpParser\Node\Expr;
+use PhpParser\Node\Scalar\String_;
use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
+use Rector\BetterPhpDocParser\PhpDoc\StringNode;
+use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpAttribute\Contract\AnnotationToAttributeMapperInterface;
use Rector\PhpAttribute\Enum\DocTagNodeState;
+use RectorPrefix202306\Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
/**
* @see \Rector\Tests\PhpAttribute\AnnotationToAttributeMapper\AnnotationToAttributeMapperTest
*/
@@ -16,15 +20,14 @@ final class AnnotationToAttributeMapper
{
/**
* @var AnnotationToAttributeMapperInterface[]
- * @readonly
*/
- private $annotationToAttributeMappers;
+ private $annotationToAttributeMappers = [];
/**
- * @param AnnotationToAttributeMapperInterface[] $annotationToAttributeMappers
+ * @param RewindableGenerator $annotationToAttributeMappers
*/
- public function __construct(array $annotationToAttributeMappers)
+ public function __construct(iterable $annotationToAttributeMappers)
{
- $this->annotationToAttributeMappers = $annotationToAttributeMappers;
+ $this->annotationToAttributeMappers = \iterator_to_array($annotationToAttributeMappers->getIterator());
}
/**
* @return Expr|DocTagNodeState::REMOVE_ARRAY
@@ -47,6 +50,9 @@ public function map($value)
if ($value instanceof ArrayItemNode) {
return BuilderHelpers::normalizeValue((string) $value);
}
+ if ($value instanceof StringNode) {
+ return new String_($value->value, [AttributeKey::KIND => $value->getAttribute(AttributeKey::KIND)]);
+ }
// fallback
return BuilderHelpers::normalizeValue($value);
}
diff --git a/packages/PhpAttribute/AnnotationToAttributeMapper/ArrayAnnotationToAttributeMapper.php b/packages/PhpAttribute/AnnotationToAttributeMapper/ArrayAnnotationToAttributeMapper.php
index c483f14f6030..dc2b867c90f2 100644
--- a/packages/PhpAttribute/AnnotationToAttributeMapper/ArrayAnnotationToAttributeMapper.php
+++ b/packages/PhpAttribute/AnnotationToAttributeMapper/ArrayAnnotationToAttributeMapper.php
@@ -20,15 +20,15 @@
*/
final class ArrayAnnotationToAttributeMapper implements AnnotationToAttributeMapperInterface
{
- /**
- * @var \Rector\PhpAttribute\AnnotationToAttributeMapper
- */
- private $annotationToAttributeMapper;
/**
* @readonly
* @var \Rector\Core\PhpParser\Node\Value\ValueResolver
*/
private $valueResolver;
+ /**
+ * @var \Rector\PhpAttribute\AnnotationToAttributeMapper
+ */
+ private $annotationToAttributeMapper;
public function __construct(ValueResolver $valueResolver)
{
$this->valueResolver = $valueResolver;
diff --git a/packages/PhpAttribute/AnnotationToAttributeMapper/ArrayItemNodeAnnotationToAttributeMapper.php b/packages/PhpAttribute/AnnotationToAttributeMapper/ArrayItemNodeAnnotationToAttributeMapper.php
index d051f4324102..859f48ba047b 100644
--- a/packages/PhpAttribute/AnnotationToAttributeMapper/ArrayItemNodeAnnotationToAttributeMapper.php
+++ b/packages/PhpAttribute/AnnotationToAttributeMapper/ArrayItemNodeAnnotationToAttributeMapper.php
@@ -9,6 +9,7 @@
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Rector\BetterPhpDocParser\PhpDoc\ArrayItemNode;
use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
+use Rector\BetterPhpDocParser\PhpDoc\StringNode;
use Rector\Core\Validation\RectorAssert;
use Rector\PhpAttribute\AnnotationToAttributeMapper;
use Rector\PhpAttribute\Contract\AnnotationToAttributeMapperInterface;
@@ -49,19 +50,8 @@ public function map($arrayItemNode) : Expr
return new ArrayItem(new String_($valueExpr), null);
}
if ($arrayItemNode->key !== null) {
- switch ($arrayItemNode->kindKeyQuoted) {
- case String_::KIND_SINGLE_QUOTED:
- $keyValue = "'" . $arrayItemNode->key . "'";
- break;
- case String_::KIND_DOUBLE_QUOTED:
- $keyValue = '"' . $arrayItemNode->key . '"';
- break;
- default:
- $keyValue = $arrayItemNode->key;
- break;
- }
/** @var Expr $keyExpr */
- $keyExpr = $this->annotationToAttributeMapper->map($keyValue);
+ $keyExpr = $this->annotationToAttributeMapper->map($arrayItemNode->key);
} else {
if ($this->hasNoParenthesesAnnotation($arrayItemNode)) {
try {
@@ -79,7 +69,7 @@ public function map($arrayItemNode) : Expr
}
private function hasNoParenthesesAnnotation(ArrayItemNode $arrayItemNode) : bool
{
- if (\is_int($arrayItemNode->kindValueQuoted)) {
+ if ($arrayItemNode->value instanceof StringNode) {
return \false;
}
if (!\is_string($arrayItemNode->value)) {
diff --git a/packages/PhpAttribute/AnnotationToAttributeMapper/DoctrineAnnotationAnnotationToAttributeMapper.php b/packages/PhpAttribute/AnnotationToAttributeMapper/DoctrineAnnotationAnnotationToAttributeMapper.php
index 20def79c8ab6..6e909494e4fa 100644
--- a/packages/PhpAttribute/AnnotationToAttributeMapper/DoctrineAnnotationAnnotationToAttributeMapper.php
+++ b/packages/PhpAttribute/AnnotationToAttributeMapper/DoctrineAnnotationAnnotationToAttributeMapper.php
@@ -19,10 +19,6 @@
*/
final class DoctrineAnnotationAnnotationToAttributeMapper implements AnnotationToAttributeMapperInterface
{
- /**
- * @var \Rector\PhpAttribute\AnnotationToAttributeMapper
- */
- private $annotationToAttributeMapper;
/**
* @readonly
* @var \Rector\Core\Php\PhpVersionProvider
@@ -33,6 +29,10 @@ final class DoctrineAnnotationAnnotationToAttributeMapper implements AnnotationT
* @var \Rector\PhpAttribute\AttributeArrayNameInliner
*/
private $attributeArrayNameInliner;
+ /**
+ * @var \Rector\PhpAttribute\AnnotationToAttributeMapper
+ */
+ private $annotationToAttributeMapper;
public function __construct(PhpVersionProvider $phpVersionProvider, AttributeArrayNameInliner $attributeArrayNameInliner)
{
$this->phpVersionProvider = $phpVersionProvider;
diff --git a/packages/PhpAttribute/AnnotationToAttributeMapper/StringNodeAnnotationToAttributeMapper.php b/packages/PhpAttribute/AnnotationToAttributeMapper/StringNodeAnnotationToAttributeMapper.php
new file mode 100644
index 000000000000..3457ea187578
--- /dev/null
+++ b/packages/PhpAttribute/AnnotationToAttributeMapper/StringNodeAnnotationToAttributeMapper.php
@@ -0,0 +1,30 @@
+
+ */
+final class StringNodeAnnotationToAttributeMapper implements AnnotationToAttributeMapperInterface
+{
+ /**
+ * @param mixed $value
+ */
+ public function isCandidate($value) : bool
+ {
+ return $value instanceof StringNode;
+ }
+ /**
+ * @param StringNode $value
+ */
+ public function map($value) : Expr
+ {
+ return new String_($value->value, [AttributeKey::KIND => $value->getAttribute(AttributeKey::KIND)]);
+ }
+}
diff --git a/packages/PhpAttribute/NodeFactory/PhpNestedAttributeGroupFactory.php b/packages/PhpAttribute/NodeFactory/PhpNestedAttributeGroupFactory.php
index 634a4c924305..22422f874c14 100644
--- a/packages/PhpAttribute/NodeFactory/PhpNestedAttributeGroupFactory.php
+++ b/packages/PhpAttribute/NodeFactory/PhpNestedAttributeGroupFactory.php
@@ -23,11 +23,6 @@
use Rector\PhpAttribute\NodeAnalyzer\ExprParameterReflectionTypeCorrector;
final class PhpNestedAttributeGroupFactory
{
- /**
- * @var string
- * @see https://regex101.com/r/g3d9jy/1
- */
- private const SHORT_ORM_ALIAS_REGEX = '#^@ORM#';
/**
* @readonly
* @var \Rector\PhpAttribute\AnnotationToAttributeMapper
@@ -53,6 +48,11 @@ final class PhpNestedAttributeGroupFactory
* @var \Rector\PhpAttribute\AttributeArrayNameInliner
*/
private $attributeArrayNameInliner;
+ /**
+ * @var string
+ * @see https://regex101.com/r/g3d9jy/1
+ */
+ private const SHORT_ORM_ALIAS_REGEX = '#^@ORM#';
public function __construct(AnnotationToAttributeMapper $annotationToAttributeMapper, \Rector\PhpAttribute\NodeFactory\AttributeNameFactory $attributeNameFactory, \Rector\PhpAttribute\NodeFactory\NamedArgsFactory $namedArgsFactory, ExprParameterReflectionTypeCorrector $exprParameterReflectionTypeCorrector, AttributeArrayNameInliner $attributeArrayNameInliner)
{
$this->annotationToAttributeMapper = $annotationToAttributeMapper;
@@ -180,7 +180,7 @@ private function createFromExplicitProperties(NestedAnnotationToAttribute $neste
$attributeArgs = $this->createAttributeArgs($nestedDoctrineAnnotationTagValueNode, $nestedAnnotationToAttribute);
$originalIdentifier = $nestedDoctrineAnnotationTagValueNode->identifierTypeNode->name;
$attributeName = $this->resolveAliasedAttributeName($originalIdentifier, $annotationPropertyToAttributeClass);
- if ($annotationPropertyToAttributeClass->doesNeedNewImport() && \count($attributeName->parts) === 1) {
+ if ($annotationPropertyToAttributeClass->doesNeedNewImport() && \count($attributeName->getParts()) === 1) {
$attributeName->setAttribute(AttributeKey::EXTRA_USE_IMPORT, $annotationPropertyToAttributeClass->getAttributeClass());
}
$attribute = new Attribute($attributeName, $attributeArgs);
diff --git a/packages/PhpDocParser/NodeVisitor/CallableNodeVisitor.php b/packages/PhpDocParser/NodeVisitor/CallableNodeVisitor.php
index b90e0dec229e..32e8f68cd703 100644
--- a/packages/PhpDocParser/NodeVisitor/CallableNodeVisitor.php
+++ b/packages/PhpDocParser/NodeVisitor/CallableNodeVisitor.php
@@ -7,6 +7,7 @@
use PhpParser\Node\Expr;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Expression;
+use PhpParser\NodeTraverser;
use PhpParser\NodeVisitorAbstract;
final class CallableNodeVisitor extends NodeVisitorAbstract
{
@@ -14,6 +15,10 @@ final class CallableNodeVisitor extends NodeVisitorAbstract
* @var callable(Node): (int|Node|null)
*/
private $callable;
+ /**
+ * @var string|null
+ */
+ private $nodeHashToRemove;
/**
* @param callable(Node $node): (int|Node|null) $callable
*/
@@ -27,9 +32,24 @@ public function enterNode(Node $node)
$callable = $this->callable;
/** @var int|Node|null $newNode */
$newNode = $callable($node);
+ if ($newNode === NodeTraverser::REMOVE_NODE) {
+ $this->nodeHashToRemove = \spl_object_hash($originalNode);
+ return $originalNode;
+ }
if ($originalNode instanceof Stmt && $newNode instanceof Expr) {
return new Expression($newNode);
}
return $newNode;
}
+ /**
+ * @return int|\PhpParser\Node
+ */
+ public function leaveNode(Node $node)
+ {
+ if ($this->nodeHashToRemove === \spl_object_hash($node)) {
+ $this->nodeHashToRemove = null;
+ return NodeTraverser::REMOVE_NODE;
+ }
+ return $node;
+ }
}
diff --git a/packages/PhpDocParser/PhpDocParser/PhpDocNodeVisitor/CallablePhpDocNodeVisitor.php b/packages/PhpDocParser/PhpDocParser/PhpDocNodeVisitor/CallablePhpDocNodeVisitor.php
index 11200c101e72..751b87ca241f 100644
--- a/packages/PhpDocParser/PhpDocParser/PhpDocNodeVisitor/CallablePhpDocNodeVisitor.php
+++ b/packages/PhpDocParser/PhpDocParser/PhpDocNodeVisitor/CallablePhpDocNodeVisitor.php
@@ -6,15 +6,15 @@
use PHPStan\PhpDocParser\Ast\Node;
final class CallablePhpDocNodeVisitor extends \Rector\PhpDocParser\PhpDocParser\PhpDocNodeVisitor\AbstractPhpDocNodeVisitor
{
- /**
- * @var callable(Node, string|null): (int|null|Node)
- */
- private $callable;
/**
* @readonly
* @var string|null
*/
private $docContent;
+ /**
+ * @var callable(Node, string|null): (int|null|Node)
+ */
+ private $callable;
/**
* @param callable(Node $callable, string|null $docContent): (int|null|Node) $callable
*/
diff --git a/packages/PhpDocParser/PhpDocParser/ValueObject/Ast/PhpDoc/SimplePhpDocNode.php b/packages/PhpDocParser/PhpDocParser/ValueObject/Ast/PhpDoc/SimplePhpDocNode.php
deleted file mode 100644
index aad3e56bfd93..000000000000
--- a/packages/PhpDocParser/PhpDocParser/ValueObject/Ast/PhpDoc/SimplePhpDocNode.php
+++ /dev/null
@@ -1,33 +0,0 @@
-getParamTagValues() as $paramTagValueNode) {
- if ($paramTagValueNode->parameterName !== $desiredParamNameWithDollar) {
- continue;
- }
- return $paramTagValueNode;
- }
- return null;
- }
- public function getParamType(string $desiredParamName) : ?TypeNode
- {
- $paramTagValueNode = $this->getParam($desiredParamName);
- if (!$paramTagValueNode instanceof ParamTagValueNode) {
- return null;
- }
- return $paramTagValueNode->type;
- }
-}
diff --git a/packages/PostRector/Application/PostFileProcessor.php b/packages/PostRector/Application/PostFileProcessor.php
index 25280aa7126c..02121604c8e0 100644
--- a/packages/PostRector/Application/PostFileProcessor.php
+++ b/packages/PostRector/Application/PostFileProcessor.php
@@ -5,19 +5,18 @@
use PhpParser\Node\Stmt;
use PhpParser\NodeTraverser;
-use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\Logging\CurrentRectorProvider;
use Rector\Core\Provider\CurrentFileProvider;
use Rector\Core\ValueObject\Application\File;
use Rector\PostRector\Contract\Rector\PostRectorDependencyInterface;
use Rector\PostRector\Contract\Rector\PostRectorInterface;
+use Rector\PostRector\Rector\ClassRenamingPostRector;
+use Rector\PostRector\Rector\NameImportingPostRector;
+use Rector\PostRector\Rector\UnusedImportRemovingPostRector;
+use Rector\PostRector\Rector\UseAddingPostRector;
use Rector\Skipper\Skipper\Skipper;
final class PostFileProcessor
{
- /**
- * @var PostRectorInterface[]
- */
- private $postRectors = [];
/**
* @readonly
* @var \Rector\Skipper\Skipper\Skipper
@@ -34,14 +33,33 @@ final class PostFileProcessor
*/
private $currentRectorProvider;
/**
- * @param PostRectorInterface[] $postRectors
+ * @var PostRectorInterface[]
*/
- public function __construct(Skipper $skipper, CurrentFileProvider $currentFileProvider, CurrentRectorProvider $currentRectorProvider, array $postRectors)
+ private $postRectors = [];
+ public function __construct(
+ Skipper $skipper,
+ CurrentFileProvider $currentFileProvider,
+ CurrentRectorProvider $currentRectorProvider,
+ // set order here
+ UseAddingPostRector $useAddingPostRector,
+ NameImportingPostRector $nameImportingPostRector,
+ ClassRenamingPostRector $classRenamingPostRector,
+ UnusedImportRemovingPostRector $unusedImportRemovingPostRector
+ )
{
$this->skipper = $skipper;
$this->currentFileProvider = $currentFileProvider;
$this->currentRectorProvider = $currentRectorProvider;
- $this->postRectors = $this->sortByPriority($postRectors);
+ $this->postRectors = [
+ // priority: 650
+ $classRenamingPostRector,
+ // priority: 600
+ $nameImportingPostRector,
+ // priority: 500
+ $useAddingPostRector,
+ // priority: 100
+ $unusedImportRemovingPostRector,
+ ];
}
/**
* @param Stmt[] $stmts
@@ -60,23 +78,6 @@ public function traverse(array $stmts) : array
}
return $stmts;
}
- /**
- * @param PostRectorInterface[] $postRectors
- * @return PostRectorInterface[]
- */
- private function sortByPriority(array $postRectors) : array
- {
- $postRectorsByPriority = [];
- foreach ($postRectors as $postRector) {
- if (isset($postRectorsByPriority[$postRector->getPriority()])) {
- $errorMessage = \sprintf('There are multiple post rectors with the same priority: %d. Use different one for your new PostRector', $postRector->getPriority());
- throw new ShouldNotHappenException($errorMessage);
- }
- $postRectorsByPriority[$postRector->getPriority()] = $postRector;
- }
- \krsort($postRectorsByPriority);
- return $postRectorsByPriority;
- }
private function shouldSkipPostRector(PostRectorInterface $postRector) : bool
{
$file = $this->currentFileProvider->getFile();
diff --git a/packages/PostRector/Collector/NodesToAddCollector.php b/packages/PostRector/Collector/NodesToAddCollector.php
deleted file mode 100644
index 701daaabd03b..000000000000
--- a/packages/PostRector/Collector/NodesToAddCollector.php
+++ /dev/null
@@ -1,118 +0,0 @@
-
- */
- private $nodesToAddBefore = [];
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- /**
- * @readonly
- * @var \Rector\ChangesReporting\Collector\RectorChangeCollector
- */
- private $rectorChangeCollector;
- /**
- * @readonly
- * @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
- */
- private $nodePrinter;
- /**
- * @readonly
- * @var \Rector\Core\Application\ChangedNodeScopeRefresher
- */
- private $changedNodeScopeRefresher;
- public function __construct(BetterNodeFinder $betterNodeFinder, RectorChangeCollector $rectorChangeCollector, NodePrinterInterface $nodePrinter, ChangedNodeScopeRefresher $changedNodeScopeRefresher)
- {
- $this->betterNodeFinder = $betterNodeFinder;
- $this->rectorChangeCollector = $rectorChangeCollector;
- $this->nodePrinter = $nodePrinter;
- $this->changedNodeScopeRefresher = $changedNodeScopeRefresher;
- }
- public function isActive() : bool
- {
- return $this->nodesToAddBefore !== [];
- }
- /**
- * @api
- * @deprecated
- * @internal Return created nodes right in refactor() method to keep context instead.
- */
- public function addNodeBeforeNode(Node $addedNode, Node $positionNode) : void
- {
- if ($positionNode->getAttributes() === []) {
- $message = \sprintf('Switch arguments in "%s()" method', __METHOD__);
- throw new ShouldNotHappenException($message);
- }
- /** @var MutatingScope|null $currentScope */
- $currentScope = $positionNode->getAttribute(AttributeKey::SCOPE);
- $this->changedNodeScopeRefresher->refresh($addedNode, $currentScope);
- $position = $this->resolveNearestStmtPosition($positionNode);
- $this->nodesToAddBefore[$position][] = $this->wrapToExpression($addedNode);
- $this->rectorChangeCollector->notifyNodeFileInfo($positionNode);
- }
- /**
- * @return Stmt[]
- */
- public function getNodesToAddBeforeNode(Node $node) : array
- {
- $position = \spl_object_hash($node);
- return $this->nodesToAddBefore[$position] ?? [];
- }
- public function clearNodesToAddBefore(Node $node) : void
- {
- $objectHash = \spl_object_hash($node);
- unset($this->nodesToAddBefore[$objectHash]);
- }
- private function resolveNearestStmtPosition(Node $node) : string
- {
- if ($node instanceof Stmt) {
- return \spl_object_hash($node);
- }
- $currentStmt = $this->betterNodeFinder->resolveCurrentStatement($node);
- if ($currentStmt instanceof Stmt) {
- return \spl_object_hash($currentStmt);
- }
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentNode instanceof Return_) {
- return \spl_object_hash($parentNode);
- }
- $foundStmt = $this->betterNodeFinder->findParentType($node, Stmt::class);
- if (!$foundStmt instanceof Stmt) {
- $printedNode = $this->nodePrinter->print($node);
- $errorMessage = \sprintf('Could not find parent Stmt of "%s" node', $printedNode);
- throw new ShouldNotHappenException($errorMessage);
- }
- return \spl_object_hash($foundStmt);
- }
- /**
- * @param \PhpParser\Node\Expr|\PhpParser\Node\Stmt $node
- */
- private function wrapToExpression($node) : Stmt
- {
- return $node instanceof Stmt ? $node : new Expression($node);
- }
-}
diff --git a/packages/PostRector/Collector/NodesToRemoveCollector.php b/packages/PostRector/Collector/NodesToRemoveCollector.php
deleted file mode 100644
index debccbec6d33..000000000000
--- a/packages/PostRector/Collector/NodesToRemoveCollector.php
+++ /dev/null
@@ -1,144 +0,0 @@
-affectedFilesCollector = $affectedFilesCollector;
- $this->breakingRemovalGuard = $breakingRemovalGuard;
- $this->betterNodeFinder = $betterNodeFinder;
- $this->nodeComparator = $nodeComparator;
- $this->currentFileProvider = $currentFileProvider;
- }
- /**
- * @deprecated Use direct return of changes Stmt instead
- */
- public function addNodeToRemove(Node $node) : void
- {
- /** Node|null $parentNode */
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentNode instanceof Node && $this->isUsedInArg($node, $parentNode)) {
- return;
- }
- // chain call: "->method()->another()"
- $this->ensureIsNotPartOfChainMethodCall($node);
- if (!$node instanceof Expression && $parentNode instanceof Expression) {
- // only expressions can be removed
- $node = $parentNode;
- } else {
- $this->breakingRemovalGuard->ensureNodeCanBeRemove($node);
- }
- $file = $this->currentFileProvider->getFile();
- if ($file instanceof File) {
- $this->affectedFilesCollector->addFile($file);
- }
- /** @var Stmt $node */
- $this->nodesToRemove[] = $node;
- }
- public function isNodeRemoved(Node $node) : bool
- {
- return \in_array($node, $this->nodesToRemove, \true);
- }
- public function isActive() : bool
- {
- return $this->getCount() > 0;
- }
- public function getCount() : int
- {
- return \count($this->nodesToRemove);
- }
- /**
- * @return array
- */
- public function getNodesToRemove() : array
- {
- return $this->nodesToRemove;
- }
- public function unset(int $key) : void
- {
- unset($this->nodesToRemove[$key]);
- }
- private function isUsedInArg(Node $node, Node $parentNode) : bool
- {
- if (!$node instanceof Param) {
- return \false;
- }
- if (!$parentNode instanceof ClassMethod) {
- return \false;
- }
- $paramVariable = $node->var;
- if ($paramVariable instanceof Variable) {
- return (bool) $this->betterNodeFinder->findFirst((array) $parentNode->stmts, function (Node $node) use($paramVariable) : bool {
- if (!$this->nodeComparator->areNodesEqual($node, $paramVariable)) {
- return \false;
- }
- $hasArgParent = (bool) $this->betterNodeFinder->findParentType($node, Arg::class);
- if (!$hasArgParent) {
- return \false;
- }
- return !(bool) $this->betterNodeFinder->findParentType($node, StaticCall::class);
- });
- }
- return \false;
- }
- private function ensureIsNotPartOfChainMethodCall(Node $node) : void
- {
- if (!$node instanceof MethodCall) {
- return;
- }
- if (!$node->var instanceof MethodCall) {
- return;
- }
- throw new ShouldNotHappenException('Chain method calls cannot be removed this way. It would remove the whole tree of calls. Remove them manually by creating new parent node with no following method.');
- }
-}
diff --git a/packages/PostRector/Collector/PropertyToAddCollector.php b/packages/PostRector/Collector/PropertyToAddCollector.php
deleted file mode 100644
index 181b04e58f54..000000000000
--- a/packages/PostRector/Collector/PropertyToAddCollector.php
+++ /dev/null
@@ -1,43 +0,0 @@
-
- */
- private $propertiesByClass = [];
- /**
- * @readonly
- * @var \Rector\ChangesReporting\Collector\RectorChangeCollector
- */
- private $rectorChangeCollector;
- public function __construct(RectorChangeCollector $rectorChangeCollector)
- {
- $this->rectorChangeCollector = $rectorChangeCollector;
- }
- public function isActive() : bool
- {
- return $this->propertiesByClass !== [];
- }
- public function addPropertyToClass(Class_ $class, PropertyMetadata $propertyMetadata) : void
- {
- $uniqueHash = \spl_object_hash($class);
- $this->propertiesByClass[$uniqueHash][] = $propertyMetadata;
- $this->rectorChangeCollector->notifyNodeFileInfo($class);
- }
- /**
- * @return PropertyMetadata[]
- */
- public function getPropertiesByClass(Class_ $class) : array
- {
- $classHash = \spl_object_hash($class);
- return $this->propertiesByClass[$classHash] ?? [];
- }
-}
diff --git a/packages/PostRector/Collector/UseNodesToAddCollector.php b/packages/PostRector/Collector/UseNodesToAddCollector.php
index 084444f124c5..f603813af0ed 100644
--- a/packages/PostRector/Collector/UseNodesToAddCollector.php
+++ b/packages/PostRector/Collector/UseNodesToAddCollector.php
@@ -14,14 +14,6 @@
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
final class UseNodesToAddCollector implements NodeCollectorInterface
{
- /**
- * @var array
- */
- private $functionUseImportTypesInFilePath = [];
- /**
- * @var array
- */
- private $useImportTypesInFilePath = [];
/**
* @readonly
* @var \Rector\Core\Provider\CurrentFileProvider
@@ -32,6 +24,14 @@ final class UseNodesToAddCollector implements NodeCollectorInterface
* @var \Rector\Naming\Naming\UseImportsResolver
*/
private $useImportsResolver;
+ /**
+ * @var array
+ */
+ private $functionUseImportTypesInFilePath = [];
+ /**
+ * @var array
+ */
+ private $useImportTypesInFilePath = [];
public function __construct(CurrentFileProvider $currentFileProvider, UseImportsResolver $useImportsResolver)
{
$this->currentFileProvider = $currentFileProvider;
@@ -60,7 +60,7 @@ public function getUseImportTypesByNode(File $file, Node $node) : array
{
$filePath = $file->getFilePath();
$objectTypes = $this->useImportTypesInFilePath[$filePath] ?? [];
- $uses = $this->useImportsResolver->resolveForNode($node);
+ $uses = $this->useImportsResolver->resolve();
foreach ($uses as $use) {
$prefix = $this->useImportsResolver->resolvePrefix($use);
foreach ($use->uses as $useUse) {
diff --git a/packages/PostRector/Contract/Rector/PostRectorInterface.php b/packages/PostRector/Contract/Rector/PostRectorInterface.php
index d4d1aae0970f..8f58da3058e4 100644
--- a/packages/PostRector/Contract/Rector/PostRectorInterface.php
+++ b/packages/PostRector/Contract/Rector/PostRectorInterface.php
@@ -7,8 +7,4 @@
use Rector\Core\Contract\Rector\RectorInterface;
interface PostRectorInterface extends NodeVisitor, RectorInterface
{
- /**
- * Higher values are executed first
- */
- public function getPriority() : int;
}
diff --git a/packages/PostRector/Rector/ClassRenamingPostRector.php b/packages/PostRector/Rector/ClassRenamingPostRector.php
index 465a67ea539b..35d9c07df564 100644
--- a/packages/PostRector/Rector/ClassRenamingPostRector.php
+++ b/packages/PostRector/Rector/ClassRenamingPostRector.php
@@ -21,10 +21,6 @@
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
final class ClassRenamingPostRector extends \Rector\PostRector\Rector\AbstractPostRector implements PostRectorDependencyInterface
{
- /**
- * @var \Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace|\PhpParser\Node\Stmt\Namespace_|null
- */
- private $rootNode = null;
/**
* @readonly
* @var \Rector\Renaming\NodeManipulator\ClassRenamer
@@ -45,6 +41,10 @@ final class ClassRenamingPostRector extends \Rector\PostRector\Rector\AbstractPo
* @var \Rector\CodingStyle\Application\UseImportsRemover
*/
private $useImportsRemover;
+ /**
+ * @var \Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace|\PhpParser\Node\Stmt\Namespace_|null
+ */
+ private $rootNode = null;
public function __construct(ClassRenamer $classRenamer, RenamedClassesDataCollector $renamedClassesDataCollector, RectorConfigProvider $rectorConfigProvider, UseImportsRemover $useImportsRemover)
{
$this->classRenamer = $classRenamer;
@@ -52,11 +52,6 @@ public function __construct(ClassRenamer $classRenamer, RenamedClassesDataCollec
$this->rectorConfigProvider = $rectorConfigProvider;
$this->useImportsRemover = $useImportsRemover;
}
- public function getPriority() : int
- {
- // must be run before name importing, so new names are imported
- return 650;
- }
/**
* @param Stmt[] $nodes
* @return Stmt[]
diff --git a/packages/PostRector/Rector/NameImportingPostRector.php b/packages/PostRector/Rector/NameImportingPostRector.php
index cb7e05bf6040..94a1bf3abefe 100644
--- a/packages/PostRector/Rector/NameImportingPostRector.php
+++ b/packages/PostRector/Rector/NameImportingPostRector.php
@@ -108,11 +108,6 @@ public function enterNode(Node $node) : ?Node
}
return $node;
}
- public function getPriority() : int
- {
- // this must run after NodeRemovingPostRector, sine renamed use imports can block next import
- return 600;
- }
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Imports fully qualified names', [new CodeSample(<<<'CODE_SAMPLE'
@@ -147,7 +142,7 @@ private function processNodeName(Name $name, File $file) : ?Node
return null;
}
/** @var Use_[]|GroupUse[] $currentUses */
- $currentUses = $this->useImportsResolver->resolveForNode($name);
+ $currentUses = $this->useImportsResolver->resolve();
if ($this->shouldImportName($name, $currentUses)) {
$nameInUse = $this->resolveNameInUse($name, $currentUses);
if ($nameInUse instanceof FullyQualified) {
diff --git a/packages/PostRector/Rector/NodeAddingPostRector.php b/packages/PostRector/Rector/NodeAddingPostRector.php
deleted file mode 100644
index 7a5d9b6761bc..000000000000
--- a/packages/PostRector/Rector/NodeAddingPostRector.php
+++ /dev/null
@@ -1,76 +0,0 @@
-someCall();
- *
- * To:
- * - $this->someCall();
- * - $value = this->someNewCall(); // added expression
- */
-final class NodeAddingPostRector extends \Rector\PostRector\Rector\AbstractPostRector
-{
- /**
- * @readonly
- * @var \Rector\PostRector\Collector\NodesToAddCollector
- */
- private $nodesToAddCollector;
- public function __construct(NodesToAddCollector $nodesToAddCollector)
- {
- $this->nodesToAddCollector = $nodesToAddCollector;
- }
- public function getPriority() : int
- {
- return 1000;
- }
- /**
- * @return array|Node
- */
- public function leaveNode(Node $node)
- {
- $newNodes = [$node];
- $nodesToAddBefore = $this->nodesToAddCollector->getNodesToAddBeforeNode($node);
- if ($nodesToAddBefore !== []) {
- $this->nodesToAddCollector->clearNodesToAddBefore($node);
- $newNodes = \array_merge($nodesToAddBefore, $newNodes);
- }
- if ($newNodes === [$node]) {
- return $node;
- }
- return $newNodes;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Add nodes on weird positions', [new CodeSample(<<<'CODE_SAMPLE'
-class SomeClass
-{
- public function run($value)
- {
- return 1;
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-class SomeClass
-{
- public function run($value)
- {
- if ($value) {
- return 1;
- }
- }
-}
-CODE_SAMPLE
-)]);
- }
-}
diff --git a/packages/PostRector/Rector/NodeRemovingPostRector.php b/packages/PostRector/Rector/NodeRemovingPostRector.php
deleted file mode 100644
index 7b4dea407d2d..000000000000
--- a/packages/PostRector/Rector/NodeRemovingPostRector.php
+++ /dev/null
@@ -1,144 +0,0 @@
-nodeFactory = $nodeFactory;
- $this->nodeNameResolver = $nodeNameResolver;
- $this->nodesToRemoveCollector = $nodesToRemoveCollector;
- }
- public function getPriority() : int
- {
- return 800;
- }
- public function enterNode(Node $node) : ?Node
- {
- if (!$this->nodesToRemoveCollector->isActive()) {
- return null;
- }
- // special case for fluent methods
- foreach ($this->nodesToRemoveCollector->getNodesToRemove() as $key => $nodeToRemove) {
- if (!$node instanceof MethodCall) {
- continue;
- }
- if (!$nodeToRemove instanceof MethodCall) {
- continue;
- }
- // replace chain method call by non-chain method call
- if (!$this->isChainMethodCallNodeToBeRemoved($node, $nodeToRemove)) {
- continue;
- }
- $this->nodesToRemoveCollector->unset($key);
- $methodName = $this->nodeNameResolver->getName($node->name);
- /** @var MethodCall $nestedMethodCall */
- $nestedMethodCall = $node->var;
- /** @var string $methodName */
- return $this->nodeFactory->createMethodCall($nestedMethodCall->var, $methodName, $node->args);
- }
- if (!$node instanceof BinaryOp) {
- return null;
- }
- return $this->removePartOfBinaryOp($node);
- }
- /**
- * @return int|\PhpParser\Node
- */
- public function leaveNode(Node $node)
- {
- foreach ($this->nodesToRemoveCollector->getNodesToRemove() as $key => $nodeToRemove) {
- $nodeToRemoveParent = $nodeToRemove->getAttribute(AttributeKey::PARENT_NODE);
- if ($nodeToRemoveParent instanceof BinaryOp) {
- continue;
- }
- if ($node === $nodeToRemove) {
- $this->nodesToRemoveCollector->unset($key);
- return NodeTraverser::REMOVE_NODE;
- }
- }
- return $node;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Remove nodes from weird positions', [new CodeSample(<<<'CODE_SAMPLE'
-class SomeClass
-{
- public function run($value)
- {
- if ($value) {
- return 1;
- }
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-class SomeClass
-{
- public function run($value)
- {
- return 1;
- }
-}
-CODE_SAMPLE
-)]);
- }
- private function isChainMethodCallNodeToBeRemoved(MethodCall $mainMethodCall, MethodCall $toBeRemovedMethodCall) : bool
- {
- if (!$mainMethodCall->var instanceof MethodCall) {
- return \false;
- }
- if ($toBeRemovedMethodCall !== $mainMethodCall->var) {
- return \false;
- }
- $methodName = $this->nodeNameResolver->getName($mainMethodCall->name);
- return $methodName !== null;
- }
- private function removePartOfBinaryOp(BinaryOp $binaryOp) : ?Node
- {
- // handle left/right binary remove, e.g. "true && false" → remove false → "true"
- foreach ($this->nodesToRemoveCollector->getNodesToRemove() as $key => $nodeToRemove) {
- // remove node
- $nodeToRemoveParentNode = $nodeToRemove->getAttribute(AttributeKey::PARENT_NODE);
- if (!$nodeToRemoveParentNode instanceof BinaryOp) {
- continue;
- }
- if ($binaryOp->left === $nodeToRemove) {
- $this->nodesToRemoveCollector->unset($key);
- return $binaryOp->right;
- }
- if ($binaryOp->right === $nodeToRemove) {
- $this->nodesToRemoveCollector->unset($key);
- return $binaryOp->left;
- }
- }
- return null;
- }
-}
diff --git a/packages/PostRector/Rector/PropertyAddingPostRector.php b/packages/PostRector/Rector/PropertyAddingPostRector.php
deleted file mode 100644
index d796d02e2208..000000000000
--- a/packages/PostRector/Rector/PropertyAddingPostRector.php
+++ /dev/null
@@ -1,84 +0,0 @@
-classDependencyManipulator = $classDependencyManipulator;
- $this->propertyToAddCollector = $propertyToAddCollector;
- $this->classAnalyzer = $classAnalyzer;
- }
- public function getPriority() : int
- {
- return 900;
- }
- public function enterNode(Node $node) : ?Node
- {
- if (!$node instanceof Class_) {
- return null;
- }
- if ($this->classAnalyzer->isAnonymousClass($node)) {
- return null;
- }
- $this->addProperties($node);
- return $node;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Add dependency properties', [new CodeSample(<<<'CODE_SAMPLE'
-class SomeClass
-{
- public function run()
- {
- return $this->value;
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-class SomeClass
-{
- private $value;
- public function run()
- {
- return $this->value;
- }
-}
-CODE_SAMPLE
-)]);
- }
- private function addProperties(Class_ $class) : void
- {
- $propertiesMetadatas = $this->propertyToAddCollector->getPropertiesByClass($class);
- foreach ($propertiesMetadatas as $propertyMetadata) {
- $this->classDependencyManipulator->addConstructorDependency($class, $propertyMetadata);
- }
- }
-}
diff --git a/packages/PostRector/Rector/UnusedImportRemovingPostRector.php b/packages/PostRector/Rector/UnusedImportRemovingPostRector.php
index a539e9ad5256..78610eeba391 100644
--- a/packages/PostRector/Rector/UnusedImportRemovingPostRector.php
+++ b/packages/PostRector/Rector/UnusedImportRemovingPostRector.php
@@ -74,14 +74,6 @@ public function enterNode(Node $node) : ?Node
$node->stmts = \array_values($node->stmts);
return $node;
}
- /**
- * The higher, the later
- */
- public function getPriority() : int
- {
- // run this last
- return 100;
- }
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Removes unused import names', [new CodeSample(<<<'CODE_SAMPLE'
diff --git a/packages/PostRector/Rector/UseAddingPostRector.php b/packages/PostRector/Rector/UseAddingPostRector.php
index 643d4dafc2a2..0d2c5976428e 100644
--- a/packages/PostRector/Rector/UseAddingPostRector.php
+++ b/packages/PostRector/Rector/UseAddingPostRector.php
@@ -7,7 +7,6 @@
use PhpParser\Node\Stmt\Namespace_;
use Rector\CodingStyle\Application\UseImportsAdder;
use Rector\Core\Exception\ShouldNotHappenException;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
use Rector\Core\Provider\CurrentFileProvider;
use Rector\Core\ValueObject\Application\File;
@@ -18,11 +17,6 @@
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
final class UseAddingPostRector extends \Rector\PostRector\Rector\AbstractPostRector
{
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
/**
* @readonly
* @var \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory
@@ -43,9 +37,8 @@ final class UseAddingPostRector extends \Rector\PostRector\Rector\AbstractPostRe
* @var \Rector\Core\Provider\CurrentFileProvider
*/
private $currentFileProvider;
- public function __construct(BetterNodeFinder $betterNodeFinder, TypeFactory $typeFactory, UseImportsAdder $useImportsAdder, UseNodesToAddCollector $useNodesToAddCollector, CurrentFileProvider $currentFileProvider)
+ public function __construct(TypeFactory $typeFactory, UseImportsAdder $useImportsAdder, UseNodesToAddCollector $useNodesToAddCollector, CurrentFileProvider $currentFileProvider)
{
- $this->betterNodeFinder = $betterNodeFinder;
$this->typeFactory = $typeFactory;
$this->useImportsAdder = $useImportsAdder;
$this->useNodesToAddCollector = $useNodesToAddCollector;
@@ -61,6 +54,13 @@ public function beforeTraverse(array $nodes) : array
if ($nodes === []) {
return $nodes;
}
+ $rootNode = null;
+ foreach ($nodes as $node) {
+ if ($node instanceof FileWithoutNamespace || $node instanceof Namespace_) {
+ $rootNode = $node;
+ break;
+ }
+ }
$file = $this->currentFileProvider->getFile();
if (!$file instanceof File) {
throw new ShouldNotHappenException();
@@ -72,20 +72,13 @@ public function beforeTraverse(array $nodes) : array
}
/** @var FullyQualifiedObjectType[] $useImportTypes */
$useImportTypes = $this->typeFactory->uniquateTypes($useImportTypes);
- $firstNode = $nodes[0];
- if ($firstNode instanceof FileWithoutNamespace) {
- $nodes = $firstNode->stmts;
+ if ($rootNode instanceof FileWithoutNamespace) {
+ $nodes = $rootNode->stmts;
}
- $namespace = $this->betterNodeFinder->findFirstInstanceOf($nodes, Namespace_::class);
- if (!$firstNode instanceof FileWithoutNamespace && !$namespace instanceof Namespace_) {
+ if (!$rootNode instanceof FileWithoutNamespace && !$rootNode instanceof Namespace_) {
return $nodes;
}
- return $this->resolveNodesWithImportedUses($nodes, $useImportTypes, $functionUseImportTypes, $namespace);
- }
- public function getPriority() : int
- {
- // must be after name importing
- return 500;
+ return $this->resolveNodesWithImportedUses($nodes, $useImportTypes, $functionUseImportTypes, $rootNode);
}
public function getRuleDefinition() : RuleDefinition
{
@@ -114,8 +107,9 @@ public function run(AnotherClass $anotherClass)
* @param FullyQualifiedObjectType[] $useImportTypes
* @param FullyQualifiedObjectType[] $functionUseImportTypes
* @return Stmt[]
+ * @param \Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace|\PhpParser\Node\Stmt\Namespace_ $namespace
*/
- private function resolveNodesWithImportedUses(array $nodes, array $useImportTypes, array $functionUseImportTypes, ?Namespace_ $namespace) : array
+ private function resolveNodesWithImportedUses(array $nodes, array $useImportTypes, array $functionUseImportTypes, $namespace) : array
{
// A. has namespace? add under it
if ($namespace instanceof Namespace_) {
@@ -126,7 +120,7 @@ private function resolveNodesWithImportedUses(array $nodes, array $useImportType
// B. no namespace? add in the top
$useImportTypes = $this->filterOutNonNamespacedNames($useImportTypes);
// then add, to prevent adding + removing false positive of same short use
- return $this->useImportsAdder->addImportsToStmts($nodes, $useImportTypes, $functionUseImportTypes);
+ return $this->useImportsAdder->addImportsToStmts($namespace, $nodes, $useImportTypes, $functionUseImportTypes);
}
/**
* Prevents
diff --git a/packages/PostRector/ValueObject/PropertyMetadata.php b/packages/PostRector/ValueObject/PropertyMetadata.php
index ad7aaee0c720..5aee79a141fd 100644
--- a/packages/PostRector/ValueObject/PropertyMetadata.php
+++ b/packages/PostRector/ValueObject/PropertyMetadata.php
@@ -3,6 +3,7 @@
declare (strict_types=1);
namespace Rector\PostRector\ValueObject;
+use PhpParser\Node\Stmt\Class_;
use PHPStan\Type\Type;
final class PropertyMetadata
{
@@ -20,8 +21,8 @@ final class PropertyMetadata
* @readonly
* @var int
*/
- private $flags;
- public function __construct(string $name, ?Type $type, int $flags)
+ private $flags = Class_::MODIFIER_PRIVATE;
+ public function __construct(string $name, ?Type $type, int $flags = Class_::MODIFIER_PRIVATE)
{
$this->name = $name;
$this->type = $type;
diff --git a/packages/ReadWrite/Guard/VariableToConstantGuard.php b/packages/ReadWrite/Guard/VariableToConstantGuard.php
index 48a3e365e3b1..9598713abe1a 100644
--- a/packages/ReadWrite/Guard/VariableToConstantGuard.php
+++ b/packages/ReadWrite/Guard/VariableToConstantGuard.php
@@ -17,10 +17,6 @@
use Rector\NodeTypeResolver\PHPStan\ParametersAcceptorSelectorVariantsWrapper;
final class VariableToConstantGuard
{
- /**
- * @var array>
- */
- private $referencePositionsByFunctionName = [];
/**
* @readonly
* @var \Rector\NodeNameResolver\NodeNameResolver
@@ -31,6 +27,10 @@ final class VariableToConstantGuard
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @var array>
+ */
+ private $referencePositionsByFunctionName = [];
public function __construct(NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider)
{
$this->nodeNameResolver = $nodeNameResolver;
@@ -38,11 +38,11 @@ public function __construct(NodeNameResolver $nodeNameResolver, ReflectionProvid
}
public function isReadArg(Arg $arg) : bool
{
- $parentParentNode = $arg->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentParentNode instanceof FuncCall) {
+ $node = $arg->getAttribute(AttributeKey::PARENT_NODE);
+ if (!$node instanceof FuncCall) {
return \true;
}
- $functionNameString = $this->nodeNameResolver->getName($parentParentNode);
+ $functionNameString = $this->nodeNameResolver->getName($node);
if ($functionNameString === null) {
return \true;
}
@@ -56,16 +56,12 @@ public function isReadArg(Arg $arg) : bool
if (!$argScope instanceof Scope) {
return \true;
}
- $parentArg = $arg->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentArg instanceof CallLike) {
- return \true;
- }
- $referenceParametersPositions = $this->resolveFunctionReferencePositions($functionReflection, $parentArg, $argScope);
+ $referenceParametersPositions = $this->resolveFunctionReferencePositions($functionReflection, $node, $argScope);
if ($referenceParametersPositions === []) {
// no reference always only write
return \true;
}
- $argumentPosition = $this->getArgumentPosition($parentParentNode, $arg);
+ $argumentPosition = $this->getArgumentPosition($node, $arg);
return !\in_array($argumentPosition, $referenceParametersPositions, \true);
}
/**
diff --git a/packages/ReadWrite/NodeAnalyzer/ReadExprAnalyzer.php b/packages/ReadWrite/NodeAnalyzer/ReadExprAnalyzer.php
index 4f062876f037..c9a785675dcd 100644
--- a/packages/ReadWrite/NodeAnalyzer/ReadExprAnalyzer.php
+++ b/packages/ReadWrite/NodeAnalyzer/ReadExprAnalyzer.php
@@ -6,19 +6,17 @@
use PhpParser\Node\Expr;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\ReadWrite\Contract\ReadNodeAnalyzerInterface;
+use Rector\ReadWrite\ReadNodeAnalyzer\LocalPropertyFetchReadNodeAnalyzer;
+use Rector\ReadWrite\ReadNodeAnalyzer\VariableReadNodeAnalyzer;
final class ReadExprAnalyzer
{
/**
* @var ReadNodeAnalyzerInterface[]
- * @readonly
*/
- private $readNodeAnalyzers;
- /**
- * @param ReadNodeAnalyzerInterface[] $readNodeAnalyzers
- */
- public function __construct(array $readNodeAnalyzers)
+ private $readNodeAnalyzers = [];
+ public function __construct(VariableReadNodeAnalyzer $variableReadNodeAnalyzer, LocalPropertyFetchReadNodeAnalyzer $localPropertyFetchReadNodeAnalyzer)
{
- $this->readNodeAnalyzers = $readNodeAnalyzers;
+ $this->readNodeAnalyzers = [$variableReadNodeAnalyzer, $localPropertyFetchReadNodeAnalyzer];
}
/**
* Is the value read or used for read purpose (at least, not only)
diff --git a/packages/ReadWrite/NodeAnalyzer/ReadWritePropertyAnalyzer.php b/packages/ReadWrite/NodeAnalyzer/ReadWritePropertyAnalyzer.php
index ae8b647066b9..9ccf0b76021e 100644
--- a/packages/ReadWrite/NodeAnalyzer/ReadWritePropertyAnalyzer.php
+++ b/packages/ReadWrite/NodeAnalyzer/ReadWritePropertyAnalyzer.php
@@ -8,10 +8,8 @@
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\AssignOp;
use PhpParser\Node\Expr\FuncCall;
-use PhpParser\Node\Expr\Isset_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
-use PhpParser\Node\Stmt\Unset_;
use PHPStan\Analyser\Scope;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\NodeManipulator\AssignManipulator;
@@ -19,6 +17,9 @@
use Rector\DeadCode\SideEffect\PureFunctionDetector;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\ReadWrite\Contract\ParentNodeReadAnalyzerInterface;
+use Rector\ReadWrite\ParentNodeReadAnalyzer\ArgParentNodeReadAnalyzer;
+use Rector\ReadWrite\ParentNodeReadAnalyzer\ArrayDimFetchParentNodeReadAnalyzer;
+use Rector\ReadWrite\ParentNodeReadAnalyzer\IncDecParentNodeReadAnalyzer;
/**
* Possibly re-use the same logic from PHPStan rule:
* https://github.com/phpstan/phpstan-src/blob/8f16632f6ccb312159250bc06df5531fa4a1ff91/src/Rules/DeadCode/UnusedPrivatePropertyRule.php#L64-L116
@@ -47,19 +48,15 @@ final class ReadWritePropertyAnalyzer
private $pureFunctionDetector;
/**
* @var ParentNodeReadAnalyzerInterface[]
- * @readonly
- */
- private $parentNodeReadAnalyzers;
- /**
- * @param ParentNodeReadAnalyzerInterface[] $parentNodeReadAnalyzers
*/
- public function __construct(AssignManipulator $assignManipulator, \Rector\ReadWrite\NodeAnalyzer\ReadExprAnalyzer $readExprAnalyzer, BetterNodeFinder $betterNodeFinder, PureFunctionDetector $pureFunctionDetector, array $parentNodeReadAnalyzers)
+ private $parentNodeReadAnalyzers = [];
+ public function __construct(AssignManipulator $assignManipulator, \Rector\ReadWrite\NodeAnalyzer\ReadExprAnalyzer $readExprAnalyzer, BetterNodeFinder $betterNodeFinder, PureFunctionDetector $pureFunctionDetector, ArgParentNodeReadAnalyzer $argParentNodeReadAnalyzer, IncDecParentNodeReadAnalyzer $incDecParentNodeReadAnalyzer, ArrayDimFetchParentNodeReadAnalyzer $arrayDimFetchParentNodeReadAnalyzer)
{
$this->assignManipulator = $assignManipulator;
$this->readExprAnalyzer = $readExprAnalyzer;
$this->betterNodeFinder = $betterNodeFinder;
$this->pureFunctionDetector = $pureFunctionDetector;
- $this->parentNodeReadAnalyzers = $parentNodeReadAnalyzers;
+ $this->parentNodeReadAnalyzers = [$argParentNodeReadAnalyzer, $incDecParentNodeReadAnalyzer, $arrayDimFetchParentNodeReadAnalyzer];
}
/**
* @param \PhpParser\Node\Expr\PropertyFetch|\PhpParser\Node\Expr\StaticPropertyFetch $node
@@ -108,14 +105,13 @@ private function isArrayDimFetchInImpureFunction(ArrayDimFetch $arrayDimFetch, N
}
private function isNotInsideIssetUnset(ArrayDimFetch $arrayDimFetch) : bool
{
- return !(bool) $this->betterNodeFinder->findParentByTypes($arrayDimFetch, [Isset_::class, Unset_::class]);
+ if ($arrayDimFetch->getAttribute(AttributeKey::IS_ISSET_VAR) === \true) {
+ return \false;
+ }
+ return $arrayDimFetch->getAttribute(AttributeKey::IS_UNSET_VAR) !== \true;
}
private function isArrayDimFetchRead(ArrayDimFetch $arrayDimFetch) : bool
{
- $parentParentNode = $arrayDimFetch->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentParentNode instanceof Node) {
- throw new ShouldNotHappenException();
- }
if (!$this->assignManipulator->isLeftPartOfAssign($arrayDimFetch)) {
return \false;
}
diff --git a/packages/ReadWrite/ParentNodeReadAnalyzer/ArrayDimFetchParentNodeReadAnalyzer.php b/packages/ReadWrite/ParentNodeReadAnalyzer/ArrayDimFetchParentNodeReadAnalyzer.php
index 7d8144aee7b9..542e7e965f13 100644
--- a/packages/ReadWrite/ParentNodeReadAnalyzer/ArrayDimFetchParentNodeReadAnalyzer.php
+++ b/packages/ReadWrite/ParentNodeReadAnalyzer/ArrayDimFetchParentNodeReadAnalyzer.php
@@ -6,20 +6,10 @@
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrayDimFetch;
-use PhpParser\Node\Expr\Assign;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
+use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\ReadWrite\Contract\ParentNodeReadAnalyzerInterface;
final class ArrayDimFetchParentNodeReadAnalyzer implements ParentNodeReadAnalyzerInterface
{
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- public function __construct(BetterNodeFinder $betterNodeFinder)
- {
- $this->betterNodeFinder = $betterNodeFinder;
- }
public function isRead(Expr $expr, Node $parentNode) : bool
{
if (!$parentNode instanceof ArrayDimFetch) {
@@ -29,16 +19,6 @@ public function isRead(Expr $expr, Node $parentNode) : bool
return \false;
}
// is left part of assign
- return $this->isLeftPartOfAssign($expr);
- }
- private function isLeftPartOfAssign(Expr $expr) : bool
- {
- $parentAssign = $this->betterNodeFinder->findParentType($expr, Assign::class);
- if (!$parentAssign instanceof Assign) {
- return \true;
- }
- return !(bool) $this->betterNodeFinder->findFirst($parentAssign->var, static function (Node $node) use($expr) : bool {
- return $node === $expr;
- });
+ return $expr->getAttribute(AttributeKey::IS_ASSIGNED_TO) === \true;
}
}
diff --git a/packages/ReadWrite/ReadNodeAnalyzer/JustReadExprAnalyzer.php b/packages/ReadWrite/ReadNodeAnalyzer/JustReadExprAnalyzer.php
index 3ac57b05d054..b6e720b7e8a6 100644
--- a/packages/ReadWrite/ReadNodeAnalyzer/JustReadExprAnalyzer.php
+++ b/packages/ReadWrite/ReadNodeAnalyzer/JustReadExprAnalyzer.php
@@ -3,30 +3,23 @@
declare (strict_types=1);
namespace Rector\ReadWrite\ReadNodeAnalyzer;
-use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrayDimFetch;
-use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Stmt\Expression;
-use PhpParser\Node\Stmt\Return_;
use Rector\NodeTypeResolver\Node\AttributeKey;
final class JustReadExprAnalyzer
{
public function isReadContext(Expr $expr) : bool
{
- $parentNode = $expr->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentNode instanceof Return_) {
+ if ($expr->getAttribute(AttributeKey::IS_RETURN_EXPR) === \true) {
return \true;
}
- if ($parentNode instanceof Arg) {
+ if ($expr->getAttribute(AttributeKey::IS_ARG_VALUE) === \true) {
return \true;
}
+ $parentNode = $expr->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode instanceof ArrayDimFetch) {
- $parentParentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentParentNode instanceof Assign) {
- return \true;
- }
- return $parentParentNode->var !== $parentNode;
+ return $parentNode->getAttribute(AttributeKey::IS_BEING_ASSIGNED) !== \true;
}
// assume it's used by default
return !$parentNode instanceof Expression;
diff --git a/packages/ReadWrite/ReadNodeAnalyzer/LocalPropertyFetchReadNodeAnalyzer.php b/packages/ReadWrite/ReadNodeAnalyzer/LocalPropertyFetchReadNodeAnalyzer.php
index 55e1f6a0da61..2d4a95dce3d4 100644
--- a/packages/ReadWrite/ReadNodeAnalyzer/LocalPropertyFetchReadNodeAnalyzer.php
+++ b/packages/ReadWrite/ReadNodeAnalyzer/LocalPropertyFetchReadNodeAnalyzer.php
@@ -7,8 +7,10 @@
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Stmt\Class_;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
+use PHPStan\Reflection\ClassReflection;
+use Rector\Core\PhpParser\ClassLikeAstResolver;
use Rector\Core\PhpParser\NodeFinder\PropertyFetchFinder;
+use Rector\Core\Reflection\ReflectionResolver;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\ReadWrite\Contract\ReadNodeAnalyzerInterface;
/**
@@ -33,15 +35,21 @@ final class LocalPropertyFetchReadNodeAnalyzer implements ReadNodeAnalyzerInterf
private $nodeNameResolver;
/**
* @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
+ * @var \Rector\Core\Reflection\ReflectionResolver
*/
- private $betterNodeFinder;
- public function __construct(\Rector\ReadWrite\ReadNodeAnalyzer\JustReadExprAnalyzer $justReadExprAnalyzer, PropertyFetchFinder $propertyFetchFinder, NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder)
+ private $reflectionResolver;
+ /**
+ * @readonly
+ * @var \Rector\Core\PhpParser\ClassLikeAstResolver
+ */
+ private $classLikeAstResolver;
+ public function __construct(\Rector\ReadWrite\ReadNodeAnalyzer\JustReadExprAnalyzer $justReadExprAnalyzer, PropertyFetchFinder $propertyFetchFinder, NodeNameResolver $nodeNameResolver, ReflectionResolver $reflectionResolver, ClassLikeAstResolver $classLikeAstResolver)
{
$this->justReadExprAnalyzer = $justReadExprAnalyzer;
$this->propertyFetchFinder = $propertyFetchFinder;
$this->nodeNameResolver = $nodeNameResolver;
- $this->betterNodeFinder = $betterNodeFinder;
+ $this->reflectionResolver = $reflectionResolver;
+ $this->classLikeAstResolver = $classLikeAstResolver;
}
public function supports(Expr $expr) : bool
{
@@ -49,8 +57,8 @@ public function supports(Expr $expr) : bool
}
public function isRead(Expr $expr) : bool
{
- $class = $this->betterNodeFinder->findParentType($expr, Class_::class);
- if (!$class instanceof Class_) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($expr);
+ if (!$classReflection instanceof ClassReflection || !$classReflection->isClass()) {
// assume worse to keep node protected
return \true;
}
@@ -59,6 +67,8 @@ public function isRead(Expr $expr) : bool
// assume worse to keep node protected
return \true;
}
+ /** @var Class_ $class */
+ $class = $this->classLikeAstResolver->resolveClassFromClassReflection($classReflection);
$propertyFetches = $this->propertyFetchFinder->findLocalPropertyFetchesByName($class, $propertyName);
foreach ($propertyFetches as $propertyFetch) {
if ($this->justReadExprAnalyzer->isReadContext($propertyFetch)) {
diff --git a/packages/Set/ValueObject/SetList.php b/packages/Set/ValueObject/SetList.php
index ccf0e1faf5cc..417bc8c36ea8 100644
--- a/packages/Set/ValueObject/SetList.php
+++ b/packages/Set/ValueObject/SetList.php
@@ -9,10 +9,6 @@
*/
final class SetList implements SetListInterface
{
- /**
- * @var string
- */
- public const ACTION_INJECTION_TO_CONSTRUCTOR_INJECTION = __DIR__ . '/../../../config/set/action-injection-to-constructor-injection.php';
/**
* @var string
*/
@@ -25,6 +21,10 @@ final class SetList implements SetListInterface
* @var string
*/
public const DEAD_CODE = __DIR__ . '/../../../config/set/dead-code.php';
+ /**
+ * @var string
+ */
+ public const STRICT_BOOLEANS = __DIR__ . '/../../../config/set/strict-booleans.php';
/**
* @var string
*/
@@ -93,10 +93,6 @@ final class SetList implements SetListInterface
* @var string
*/
public const PRIVATIZATION = __DIR__ . '/../../../config/set/privatization.php';
- /**
- * @var string
- */
- public const PSR_4 = __DIR__ . '/../../../config/set/psr-4.php';
/**
* @var string
*/
diff --git a/packages/Skipper/Enum/AsteriskMatch.php b/packages/Skipper/Enum/AsteriskMatch.php
deleted file mode 100644
index 7a8ce2db45ed..000000000000
--- a/packages/Skipper/Enum/AsteriskMatch.php
+++ /dev/null
@@ -1,18 +0,0 @@
-
- */
- private $skippedClasses = [];
/**
* @readonly
* @var \Rector\Core\Configuration\Parameter\ParameterProvider
@@ -22,6 +18,10 @@ final class SkippedClassResolver
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @var array
+ */
+ private $skippedClasses = [];
public function __construct(ParameterProvider $parameterProvider, ReflectionProvider $reflectionProvider)
{
$this->parameterProvider = $parameterProvider;
diff --git a/packages/Skipper/SkipCriteriaResolver/SkippedPathsResolver.php b/packages/Skipper/SkipCriteriaResolver/SkippedPathsResolver.php
index 832dd764eac0..3183820d6f78 100644
--- a/packages/Skipper/SkipCriteriaResolver/SkippedPathsResolver.php
+++ b/packages/Skipper/SkipCriteriaResolver/SkippedPathsResolver.php
@@ -11,10 +11,6 @@
*/
final class SkippedPathsResolver
{
- /**
- * @var string[]
- */
- private $skippedPaths = [];
/**
* @readonly
* @var \Rector\Core\Configuration\Parameter\ParameterProvider
@@ -25,6 +21,10 @@ final class SkippedPathsResolver
* @var \Rector\Core\FileSystem\FilePathHelper
*/
private $filePathHelper;
+ /**
+ * @var string[]
+ */
+ private $skippedPaths = [];
public function __construct(ParameterProvider $parameterProvider, FilePathHelper $filePathHelper)
{
$this->parameterProvider = $parameterProvider;
diff --git a/packages/Skipper/SkipVoter/PathSkipVoter.php b/packages/Skipper/SkipVoter/PathSkipVoter.php
index ee84161f7ddc..6e61744151ba 100644
--- a/packages/Skipper/SkipVoter/PathSkipVoter.php
+++ b/packages/Skipper/SkipVoter/PathSkipVoter.php
@@ -8,10 +8,6 @@
use Rector\Skipper\SkipCriteriaResolver\SkippedPathsResolver;
final class PathSkipVoter implements SkipVoterInterface
{
- /**
- * @var array
- */
- private $skippedFiles = [];
/**
* @readonly
* @var \Rector\Skipper\Matcher\FileInfoMatcher
@@ -22,6 +18,10 @@ final class PathSkipVoter implements SkipVoterInterface
* @var \Rector\Skipper\SkipCriteriaResolver\SkippedPathsResolver
*/
private $skippedPathsResolver;
+ /**
+ * @var array
+ */
+ private $skippedFiles = [];
public function __construct(FileInfoMatcher $fileInfoMatcher, SkippedPathsResolver $skippedPathsResolver)
{
$this->fileInfoMatcher = $fileInfoMatcher;
diff --git a/packages/Skipper/Skipper/Skipper.php b/packages/Skipper/Skipper/Skipper.php
index 62527a561506..6c1203bf8e2e 100644
--- a/packages/Skipper/Skipper/Skipper.php
+++ b/packages/Skipper/Skipper/Skipper.php
@@ -4,6 +4,8 @@
namespace Rector\Skipper\Skipper;
use Rector\Skipper\Contract\SkipVoterInterface;
+use Rector\Skipper\SkipVoter\ClassSkipVoter;
+use Rector\Skipper\SkipVoter\PathSkipVoter;
/**
* @api
* @see \Rector\Tests\Skipper\Skipper\Skipper\SkipperTest
@@ -16,15 +18,11 @@ final class Skipper
private const FILE_ELEMENT = 'file_elements';
/**
* @var SkipVoterInterface[]
- * @readonly
*/
- private $skipVoters;
- /**
- * @param SkipVoterInterface[] $skipVoters
- */
- public function __construct(array $skipVoters)
+ private $skipVoters = [];
+ public function __construct(ClassSkipVoter $classSkipVoter, PathSkipVoter $pathSkipVoter)
{
- $this->skipVoters = $skipVoters;
+ $this->skipVoters = [$classSkipVoter, $pathSkipVoter];
}
/**
* @param string|object $element
diff --git a/packages/StaticTypeMapper/Mapper/PhpParserNodeMapper.php b/packages/StaticTypeMapper/Mapper/PhpParserNodeMapper.php
index 82879186860f..cf63224462c9 100644
--- a/packages/StaticTypeMapper/Mapper/PhpParserNodeMapper.php
+++ b/packages/StaticTypeMapper/Mapper/PhpParserNodeMapper.php
@@ -22,7 +22,7 @@ final class PhpParserNodeMapper
/**
* @param PhpParserNodeMapperInterface[] $phpParserNodeMappers
*/
- public function __construct(array $phpParserNodeMappers)
+ public function __construct(iterable $phpParserNodeMappers)
{
$this->phpParserNodeMappers = $phpParserNodeMappers;
}
diff --git a/packages/StaticTypeMapper/Naming/NameScopeFactory.php b/packages/StaticTypeMapper/Naming/NameScopeFactory.php
index 4f5a5f994e50..06314c605254 100644
--- a/packages/StaticTypeMapper/Naming/NameScopeFactory.php
+++ b/packages/StaticTypeMapper/Naming/NameScopeFactory.php
@@ -14,7 +14,8 @@
use PHPStan\Type\Generic\TemplateTypeMap;
use PHPStan\Type\Type;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
+use Rector\Core\PhpParser\ClassLikeAstResolver;
+use Rector\Core\Reflection\ReflectionResolver;
use Rector\Naming\Naming\UseImportsResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\StaticTypeMapper\StaticTypeMapper;
@@ -32,30 +33,35 @@ final class NameScopeFactory
* @var \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory
*/
private $phpDocInfoFactory;
- /**
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
/**
* @var \Rector\Naming\Naming\UseImportsResolver
*/
private $useImportsResolver;
+ /**
+ * @var \Rector\Core\Reflection\ReflectionResolver
+ */
+ private $reflectionResolver;
+ /**
+ * @var \Rector\Core\PhpParser\ClassLikeAstResolver
+ */
+ private $classLikeAstResolver;
// This is needed to avoid circular references
/**
* @required
*/
- public function autowire(PhpDocInfoFactory $phpDocInfoFactory, StaticTypeMapper $staticTypeMapper, BetterNodeFinder $betterNodeFinder, UseImportsResolver $useImportsResolver) : void
+ public function autowire(PhpDocInfoFactory $phpDocInfoFactory, StaticTypeMapper $staticTypeMapper, UseImportsResolver $useImportsResolver, ReflectionResolver $reflectionResolver, ClassLikeAstResolver $classLikeAstResolver) : void
{
$this->phpDocInfoFactory = $phpDocInfoFactory;
$this->staticTypeMapper = $staticTypeMapper;
- $this->betterNodeFinder = $betterNodeFinder;
$this->useImportsResolver = $useImportsResolver;
+ $this->reflectionResolver = $reflectionResolver;
+ $this->classLikeAstResolver = $classLikeAstResolver;
}
public function createNameScopeFromNodeWithoutTemplateTypes(Node $node) : NameScope
{
$scope = $node->getAttribute(AttributeKey::SCOPE);
$namespace = $scope instanceof Scope ? $scope->getNamespace() : null;
- $uses = $this->useImportsResolver->resolveForNode($node);
+ $uses = $this->useImportsResolver->resolve();
$usesAliasesToNames = $this->resolveUseNamesByAlias($uses);
if ($scope instanceof Scope && $scope->getClassReflection() instanceof ClassReflection) {
$classReflection = $scope->getClassReflection();
@@ -93,10 +99,13 @@ private function resolveUseNamesByAlias(array $useNodes) : array
private function templateTemplateTypeMap(Node $node) : TemplateTypeMap
{
$nodeTemplateTypes = $this->resolveTemplateTypesFromNode($node);
- $classLike = $this->betterNodeFinder->findParentType($node, ClassLike::class);
$classTemplateTypes = [];
- if ($classLike instanceof ClassLike) {
- $classTemplateTypes = $this->resolveTemplateTypesFromNode($classLike);
+ $classReflection = $this->reflectionResolver->resolveClassReflection($node);
+ if ($classReflection instanceof ClassReflection) {
+ $classLike = $this->classLikeAstResolver->resolveClassFromClassReflection($classReflection);
+ if ($classLike instanceof ClassLike) {
+ $classTemplateTypes = $this->resolveTemplateTypesFromNode($classLike);
+ }
}
$templateTypes = \array_merge($nodeTemplateTypes, $classTemplateTypes);
return new TemplateTypeMap($templateTypes);
diff --git a/packages/StaticTypeMapper/PhpDoc/PhpDocTypeMapper.php b/packages/StaticTypeMapper/PhpDoc/PhpDocTypeMapper.php
index 97b9319ea7ce..c5f335d40866 100644
--- a/packages/StaticTypeMapper/PhpDoc/PhpDocTypeMapper.php
+++ b/packages/StaticTypeMapper/PhpDoc/PhpDocTypeMapper.php
@@ -27,7 +27,7 @@ final class PhpDocTypeMapper
/**
* @param PhpDocTypeMapperInterface[] $phpDocTypeMappers
*/
- public function __construct(array $phpDocTypeMappers, TypeNodeResolver $typeNodeResolver)
+ public function __construct(iterable $phpDocTypeMappers, TypeNodeResolver $typeNodeResolver)
{
$this->phpDocTypeMappers = $phpDocTypeMappers;
$this->typeNodeResolver = $typeNodeResolver;
diff --git a/packages/StaticTypeMapper/PhpDocParser/IdentifierTypeMapper.php b/packages/StaticTypeMapper/PhpDocParser/IdentifierTypeMapper.php
index e36c87ee6bbb..ce0099418157 100644
--- a/packages/StaticTypeMapper/PhpDocParser/IdentifierTypeMapper.php
+++ b/packages/StaticTypeMapper/PhpDocParser/IdentifierTypeMapper.php
@@ -5,7 +5,6 @@
use RectorPrefix202306\Nette\Utils\Strings;
use PhpParser\Node;
-use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Analyser\NameScope;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\TypeNode;
@@ -22,8 +21,7 @@
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use Rector\Core\Enum\ObjectReference;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
-use Rector\NodeNameResolver\NodeNameResolver;
+use Rector\Core\Reflection\ReflectionResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\StaticTypeMapper\Contract\PhpDocParser\PhpDocTypeMapperInterface;
use Rector\StaticTypeMapper\Mapper\ScalarStringToTypeMapper;
@@ -48,26 +46,20 @@ final class IdentifierTypeMapper implements PhpDocTypeMapperInterface
private $scalarStringToTypeMapper;
/**
* @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- /**
- * @readonly
- * @var \Rector\NodeNameResolver\NodeNameResolver
+ * @var \PHPStan\Reflection\ReflectionProvider
*/
- private $nodeNameResolver;
+ private $reflectionProvider;
/**
* @readonly
- * @var \PHPStan\Reflection\ReflectionProvider
+ * @var \Rector\Core\Reflection\ReflectionResolver
*/
- private $reflectionProvider;
- public function __construct(ObjectTypeSpecifier $objectTypeSpecifier, ScalarStringToTypeMapper $scalarStringToTypeMapper, BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider)
+ private $reflectionResolver;
+ public function __construct(ObjectTypeSpecifier $objectTypeSpecifier, ScalarStringToTypeMapper $scalarStringToTypeMapper, ReflectionProvider $reflectionProvider, ReflectionResolver $reflectionResolver)
{
$this->objectTypeSpecifier = $objectTypeSpecifier;
$this->scalarStringToTypeMapper = $scalarStringToTypeMapper;
- $this->betterNodeFinder = $betterNodeFinder;
- $this->nodeNameResolver = $nodeNameResolver;
$this->reflectionProvider = $reflectionProvider;
+ $this->reflectionResolver = $reflectionResolver;
}
public function getNodeType() : string
{
@@ -159,17 +151,10 @@ private function mapStatic(Node $node)
}
private function resolveClassName(Node $node) : ?string
{
- $classLike = $node instanceof ClassLike ? $node : $this->betterNodeFinder->findParentType($node, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
- return null;
- }
- $className = $this->nodeNameResolver->getName($classLike);
- if (!\is_string($className)) {
- return null;
- }
- if (!$this->reflectionProvider->hasClass($className)) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($node);
+ if (!$classReflection instanceof ClassReflection) {
return null;
}
- return $className;
+ return $classReflection->getName();
}
}
diff --git a/packages/StaticTypeMapper/PhpDocParser/NullableTypeMapper.php b/packages/StaticTypeMapper/PhpDocParser/NullableTypeMapper.php
index 5cbaabce2944..c57b73162ff7 100644
--- a/packages/StaticTypeMapper/PhpDocParser/NullableTypeMapper.php
+++ b/packages/StaticTypeMapper/PhpDocParser/NullableTypeMapper.php
@@ -45,8 +45,7 @@ public function mapToPHPStanType(TypeNode $typeNode, Node $node, NameScope $name
if ($typeNode->type instanceof IdentifierTypeNode) {
$type = $this->identifierTypeMapper->mapToPHPStanType($typeNode->type, $node, $nameScope);
if ($type instanceof UnionType) {
- $item1Unpacked = $type->getTypes();
- return new UnionType(\array_merge([new NullType()], $item1Unpacked));
+ return new UnionType(\array_merge([new NullType()], $type->getTypes()));
}
return new UnionType([new NullType(), $type]);
}
diff --git a/packages/StaticTypeMapper/PhpDocParser/UnionTypeMapper.php b/packages/StaticTypeMapper/PhpDocParser/UnionTypeMapper.php
index ceb3cb9a1a56..114281276440 100644
--- a/packages/StaticTypeMapper/PhpDocParser/UnionTypeMapper.php
+++ b/packages/StaticTypeMapper/PhpDocParser/UnionTypeMapper.php
@@ -17,15 +17,15 @@
*/
final class UnionTypeMapper implements PhpDocTypeMapperInterface
{
- /**
- * @var \Rector\StaticTypeMapper\PhpDoc\PhpDocTypeMapper
- */
- private $phpDocTypeMapper;
/**
* @readonly
* @var \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory
*/
private $typeFactory;
+ /**
+ * @var \Rector\StaticTypeMapper\PhpDoc\PhpDocTypeMapper
+ */
+ private $phpDocTypeMapper;
public function __construct(TypeFactory $typeFactory)
{
$this->typeFactory = $typeFactory;
diff --git a/packages/StaticTypeMapper/PhpParser/FullyQualifiedNodeMapper.php b/packages/StaticTypeMapper/PhpParser/FullyQualifiedNodeMapper.php
index 7c447516de90..ed28f7c0c799 100644
--- a/packages/StaticTypeMapper/PhpParser/FullyQualifiedNodeMapper.php
+++ b/packages/StaticTypeMapper/PhpParser/FullyQualifiedNodeMapper.php
@@ -67,11 +67,10 @@ private function isParamTyped(FullyQualified $fullyQualified, ?Node $node) : boo
if (!$node instanceof NullableType) {
return \false;
}
- $parentOfParent = $node->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentOfParent instanceof Param) {
- return \false;
+ if ($node->getAttribute(AttributeKey::IS_PARAM_TYPE) === \true) {
+ return $node->type === $fullyQualified;
}
- return $node->type === $fullyQualified;
+ return \false;
}
private function resolvePossibleAliasedObjectType(FullyQualified $fullyQualified) : ?AliasedObjectType
{
diff --git a/packages/StaticTypeMapper/PhpParser/NameNodeMapper.php b/packages/StaticTypeMapper/PhpParser/NameNodeMapper.php
index 6f923333dc0a..76b8e000f84a 100644
--- a/packages/StaticTypeMapper/PhpParser/NameNodeMapper.php
+++ b/packages/StaticTypeMapper/PhpParser/NameNodeMapper.php
@@ -5,7 +5,6 @@
use PhpParser\Node;
use PhpParser\Node\Name;
-use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ArrayType;
@@ -21,8 +20,7 @@
use PHPStan\Type\Type;
use Rector\Core\Configuration\RenamedClassesDataCollector;
use Rector\Core\Enum\ObjectReference;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
-use Rector\NodeNameResolver\NodeNameResolver;
+use Rector\Core\Reflection\ReflectionResolver;
use Rector\StaticTypeMapper\Contract\PhpParser\PhpParserNodeMapperInterface;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
use Rector\StaticTypeMapper\ValueObject\Type\ParentObjectWithoutClassType;
@@ -45,20 +43,14 @@ final class NameNodeMapper implements PhpParserNodeMapperInterface
private $reflectionProvider;
/**
* @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
+ * @var \Rector\Core\Reflection\ReflectionResolver
*/
- private $betterNodeFinder;
- /**
- * @readonly
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
- public function __construct(RenamedClassesDataCollector $renamedClassesDataCollector, ReflectionProvider $reflectionProvider, BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver)
+ private $reflectionResolver;
+ public function __construct(RenamedClassesDataCollector $renamedClassesDataCollector, ReflectionProvider $reflectionProvider, ReflectionResolver $reflectionResolver)
{
$this->renamedClassesDataCollector = $renamedClassesDataCollector;
$this->reflectionProvider = $reflectionProvider;
- $this->betterNodeFinder = $betterNodeFinder;
- $this->nodeNameResolver = $nodeNameResolver;
+ $this->reflectionResolver = $reflectionResolver;
}
public function getNodeType() : string
{
@@ -92,12 +84,10 @@ private function isExistingClass(string $name) : bool
*/
private function createClassReferenceType(Name $name, string $reference)
{
- $classLike = $this->betterNodeFinder->findParentType($name, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($name);
+ if (!$classReflection instanceof ClassReflection) {
return new MixedType();
}
- $className = (string) $this->nodeNameResolver->getName($classLike);
- $classReflection = $this->reflectionProvider->getClass($className);
if ($reference === ObjectReference::STATIC) {
return new StaticType($classReflection);
}
diff --git a/packages/StaticTypeMapper/PhpParser/NullableTypeNodeMapper.php b/packages/StaticTypeMapper/PhpParser/NullableTypeNodeMapper.php
index 03cc69628468..0b98e36b1e96 100644
--- a/packages/StaticTypeMapper/PhpParser/NullableTypeNodeMapper.php
+++ b/packages/StaticTypeMapper/PhpParser/NullableTypeNodeMapper.php
@@ -16,15 +16,15 @@
*/
final class NullableTypeNodeMapper implements PhpParserNodeMapperInterface
{
- /**
- * @var \Rector\StaticTypeMapper\Mapper\PhpParserNodeMapper
- */
- private $phpParserNodeMapper;
/**
* @readonly
* @var \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory
*/
private $typeFactory;
+ /**
+ * @var \Rector\StaticTypeMapper\Mapper\PhpParserNodeMapper
+ */
+ private $phpParserNodeMapper;
public function __construct(TypeFactory $typeFactory)
{
$this->typeFactory = $typeFactory;
diff --git a/packages/StaticTypeMapper/PhpParser/UnionTypeNodeMapper.php b/packages/StaticTypeMapper/PhpParser/UnionTypeNodeMapper.php
index f3adfa192d6a..1706005b6b96 100644
--- a/packages/StaticTypeMapper/PhpParser/UnionTypeNodeMapper.php
+++ b/packages/StaticTypeMapper/PhpParser/UnionTypeNodeMapper.php
@@ -15,15 +15,15 @@
*/
final class UnionTypeNodeMapper implements PhpParserNodeMapperInterface
{
- /**
- * @var \Rector\StaticTypeMapper\Mapper\PhpParserNodeMapper
- */
- private $phpParserNodeMapper;
/**
* @readonly
* @var \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory
*/
private $typeFactory;
+ /**
+ * @var \Rector\StaticTypeMapper\Mapper\PhpParserNodeMapper
+ */
+ private $phpParserNodeMapper;
public function __construct(TypeFactory $typeFactory)
{
$this->typeFactory = $typeFactory;
diff --git a/packages/StaticTypeMapper/StaticTypeMapper.php b/packages/StaticTypeMapper/StaticTypeMapper.php
index 2746d82ef714..8a8d3e642c0e 100644
--- a/packages/StaticTypeMapper/StaticTypeMapper.php
+++ b/packages/StaticTypeMapper/StaticTypeMapper.php
@@ -7,8 +7,6 @@
use PhpParser\Node\ComplexType;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
-use PhpParser\Node\Param;
-use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\UnionType;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
@@ -21,7 +19,6 @@
use PHPStan\Type\Type;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\NodeNameResolver\NodeNameResolver;
-use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\PHPStanStaticTypeMapper\PHPStanStaticTypeMapper;
use Rector\StaticTypeMapper\Mapper\PhpParserNodeMapper;
@@ -33,10 +30,6 @@
*/
final class StaticTypeMapper
{
- /**
- * @var array
- */
- private const STANDALONE_MAPS = ['false' => 'bool'];
/**
* @readonly
* @var \Rector\StaticTypeMapper\Naming\NameScopeFactory
@@ -62,6 +55,10 @@ final class StaticTypeMapper
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
+ /**
+ * @var array
+ */
+ private const STANDALONE_MAPS = ['false' => 'bool'];
public function __construct(NameScopeFactory $nameScopeFactory, PHPStanStaticTypeMapper $phpStanStaticTypeMapper, PhpDocTypeMapper $phpDocTypeMapper, PhpParserNodeMapper $phpParserNodeMapper, NodeNameResolver $nodeNameResolver)
{
$this->nameScopeFactory = $nameScopeFactory;
@@ -70,12 +67,9 @@ public function __construct(NameScopeFactory $nameScopeFactory, PHPStanStaticTyp
$this->phpParserNodeMapper = $phpParserNodeMapper;
$this->nodeNameResolver = $nodeNameResolver;
}
- /**
- * @param TypeKind::* $typeKind
- */
- public function mapPHPStanTypeToPHPStanPhpDocTypeNode(Type $phpStanType, string $typeKind) : TypeNode
+ public function mapPHPStanTypeToPHPStanPhpDocTypeNode(Type $phpStanType) : TypeNode
{
- return $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($phpStanType, $typeKind);
+ return $this->phpStanStaticTypeMapper->mapToPHPStanPhpDocTypeNode($phpStanType);
}
/**
* @param TypeKind::* $typeKind
@@ -122,13 +116,6 @@ public function mapPHPStanPhpDocTypeToPHPStanType(PhpDocTagValueNode $phpDocTagV
}
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);
}
diff --git a/packages/StaticTypeMapper/ValueObject/Type/AliasedObjectType.php b/packages/StaticTypeMapper/ValueObject/Type/AliasedObjectType.php
index 64eca1eb83ef..0a243c350ee4 100644
--- a/packages/StaticTypeMapper/ValueObject/Type/AliasedObjectType.php
+++ b/packages/StaticTypeMapper/ValueObject/Type/AliasedObjectType.php
@@ -32,6 +32,7 @@ public function getFullyQualifiedName() : string
public function getUseNode() : Use_
{
$name = new Name($this->fullyQualifiedClass);
+ $name->setAttribute(AttributeKey::IS_USEUSE_NAME, \true);
$useUse = new UseUse($name, $this->getClassName());
return new Use_([$useUse]);
}
@@ -49,8 +50,8 @@ public function areShortNamesEqual($comparedObjectType) : bool
public function getFunctionUseNode() : Use_
{
$name = new Name($this->fullyQualifiedClass);
+ $name->setAttribute(AttributeKey::IS_USEUSE_NAME, \true);
$useUse = new UseUse($name, $this->getClassName());
- $name->setAttribute(AttributeKey::PARENT_NODE, $useUse);
$use = new Use_([$useUse]);
$use->type = Use_::TYPE_FUNCTION;
return $use;
diff --git a/packages/StaticTypeMapper/ValueObject/Type/FullyQualifiedObjectType.php b/packages/StaticTypeMapper/ValueObject/Type/FullyQualifiedObjectType.php
index 3df35c4af686..364c6a9cf89a 100644
--- a/packages/StaticTypeMapper/ValueObject/Type/FullyQualifiedObjectType.php
+++ b/packages/StaticTypeMapper/ValueObject/Type/FullyQualifiedObjectType.php
@@ -45,15 +45,15 @@ public function getShortNameNode() : Name
public function getUseNode() : Use_
{
$name = new Name($this->getClassName());
+ $name->setAttribute(AttributeKey::IS_USEUSE_NAME, \true);
$useUse = new UseUse($name);
- $name->setAttribute(AttributeKey::PARENT_NODE, $useUse);
return new Use_([$useUse]);
}
public function getFunctionUseNode() : Use_
{
$name = new Name($this->getClassName());
+ $name->setAttribute(AttributeKey::IS_USEUSE_NAME, \true);
$useUse = new UseUse($name, null);
- $name->setAttribute(AttributeKey::PARENT_NODE, $useUse);
$use = new Use_([$useUse]);
$use->type = Use_::TYPE_FUNCTION;
return $use;
diff --git a/packages/Testing/PHPUnit/AbstractLazyTestCase.php b/packages/Testing/PHPUnit/AbstractLazyTestCase.php
new file mode 100644
index 000000000000..041ba1463fc1
--- /dev/null
+++ b/packages/Testing/PHPUnit/AbstractLazyTestCase.php
@@ -0,0 +1,20 @@
+ $class
+ * @return TType
+ */
+ protected function make(string $class) : object
+ {
+ $container = new Container();
+ return $container->make($class);
+ }
+}
diff --git a/packages/Testing/PHPUnit/AbstractRectorTestCase.php b/packages/Testing/PHPUnit/AbstractRectorTestCase.php
index 950a6c37e155..ac81ead3ec9c 100644
--- a/packages/Testing/PHPUnit/AbstractRectorTestCase.php
+++ b/packages/Testing/PHPUnit/AbstractRectorTestCase.php
@@ -10,7 +10,6 @@
use PHPUnit\Framework\ExpectationFailedException;
use RectorPrefix202306\Psr\Container\ContainerInterface;
use Rector\Core\Application\ApplicationFileProcessor;
-use Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector;
use Rector\Core\Autoloading\AdditionalAutoloader;
use Rector\Core\Autoloading\BootstrapFilesIncluder;
use Rector\Core\Configuration\ConfigurationFactory;
@@ -23,14 +22,8 @@
use Rector\Testing\Fixture\FixtureFileFinder;
use Rector\Testing\Fixture\FixtureFileUpdater;
use Rector\Testing\Fixture\FixtureSplitter;
-use Rector\Testing\PHPUnit\Behavior\MovingFilesTrait;
abstract class AbstractRectorTestCase extends \Rector\Testing\PHPUnit\AbstractTestCase implements RectorTestInterface
{
- use MovingFilesTrait;
- /**
- * @var \Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector
- */
- protected $removedAndAddedFilesCollector;
/**
* @var \Psr\Container\ContainerInterface|null
*/
@@ -61,9 +54,6 @@ protected function setUp() : void
$this->applicationFileProcessor = $this->getService(ApplicationFileProcessor::class);
$this->parameterProvider = $this->getService(ParameterProvider::class);
$this->dynamicSourceLocatorProvider = $this->getService(DynamicSourceLocatorProvider::class);
- // restore added and removed files to 0
- $this->removedAndAddedFilesCollector = $this->getService(RemovedAndAddedFilesCollector::class);
- $this->removedAndAddedFilesCollector->reset();
/** @var AdditionalAutoloader $additionalAutoloader */
$additionalAutoloader = $this->getService(AdditionalAutoloader::class);
$additionalAutoloader->autoloadPaths();
@@ -79,7 +69,7 @@ protected function tearDown() : void
FileSystem::delete($this->inputFilePath);
}
// free memory and trigger gc to reduce memory peak consumption on windows
- unset($this->applicationFileProcessor, $this->parameterProvider, $this->dynamicSourceLocatorProvider, $this->removedAndAddedFilesCollector);
+ unset($this->applicationFileProcessor, $this->parameterProvider, $this->dynamicSourceLocatorProvider);
\gc_collect_cycles();
}
/**
@@ -133,10 +123,6 @@ private function doTestFileMatchesExpectedContent(string $originalFilePath, stri
{
$this->parameterProvider->changeParameter(Option::SOURCE, [$originalFilePath]);
$changedContent = $this->processFilePath($originalFilePath, $inputFileContents);
- // file is removed, we cannot compare it
- if ($this->removedAndAddedFilesCollector->isFileRemoved($originalFilePath)) {
- return;
- }
$fixtureFilename = \basename($fixtureFilePath);
$failureMessage = \sprintf('Failed on fixture file "%s"', $fixtureFilename);
try {
diff --git a/packages/Testing/PHPUnit/Behavior/MovingFilesTrait.php b/packages/Testing/PHPUnit/Behavior/MovingFilesTrait.php
deleted file mode 100644
index d3134328e504..000000000000
--- a/packages/Testing/PHPUnit/Behavior/MovingFilesTrait.php
+++ /dev/null
@@ -1,46 +0,0 @@
-resolveAddedFilePathsWithContents();
- $wasFound = \false;
- foreach ($addedFilePathsWithContents as $addedFilePathsWithContent) {
- if ($addedFilePathsWithContent->getFilePath() !== $expectedFilePath) {
- continue;
- }
- $this->assertSame($expectedFileContents, $addedFilePathsWithContent->getFileContent());
- $wasFound = \true;
- }
- if ($wasFound === \false) {
- $this->fail(\sprintf('File "%s" was not added', $expectedFilePath));
- }
- }
- /**
- * @return AddedFileWithContent[]
- */
- private function resolveAddedFilePathsWithContents() : array
- {
- $addedFilePathsWithContents = $this->removedAndAddedFilesCollector->getAddedFilesWithContent();
- $nodesWithFileDestinationPrinter = $this->getService(NodesWithFileDestinationPrinter::class);
- $addedFilesWithNodes = $this->removedAndAddedFilesCollector->getAddedFilesWithNodes();
- if ($addedFilesWithNodes === []) {
- return $addedFilePathsWithContents;
- }
- foreach ($addedFilesWithNodes as $addedFileWithNodes) {
- $fileContent = $nodesWithFileDestinationPrinter->printNodesWithFileDestination($addedFileWithNodes);
- $addedFilePathsWithContents[] = new AddedFileWithContent($addedFileWithNodes->getFilePath(), $fileContent);
- }
- return $addedFilePathsWithContents;
- }
-}
diff --git a/packages/Testing/TestingParser/TestingParser.php b/packages/Testing/TestingParser/TestingParser.php
index d4cf714fa9a6..9465b9a6d6f9 100644
--- a/packages/Testing/TestingParser/TestingParser.php
+++ b/packages/Testing/TestingParser/TestingParser.php
@@ -8,6 +8,7 @@
use Rector\Core\Configuration\Option;
use Rector\Core\Configuration\Parameter\ParameterProvider;
use Rector\Core\PhpParser\Parser\RectorParser;
+use Rector\Core\Provider\CurrentFileProvider;
use Rector\Core\ValueObject\Application\File;
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
/**
@@ -30,17 +31,25 @@ final class TestingParser
* @var \Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator
*/
private $nodeScopeAndMetadataDecorator;
- public function __construct(ParameterProvider $parameterProvider, RectorParser $rectorParser, NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator)
+ /**
+ * @readonly
+ * @var \Rector\Core\Provider\CurrentFileProvider
+ */
+ private $currentFileProvider;
+ public function __construct(ParameterProvider $parameterProvider, RectorParser $rectorParser, NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator, CurrentFileProvider $currentFileProvider)
{
$this->parameterProvider = $parameterProvider;
$this->rectorParser = $rectorParser;
$this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator;
+ $this->currentFileProvider = $currentFileProvider;
}
public function parseFilePathToFile(string $filePath) : File
{
$file = new File($filePath, FileSystem::read($filePath));
$stmts = $this->rectorParser->parseFile($filePath);
+ $stmts = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($file, $stmts);
$file->hydrateStmtsAndTokens($stmts, $stmts, []);
+ $this->currentFileProvider->setFile($file);
return $file;
}
/**
@@ -49,8 +58,11 @@ public function parseFilePathToFile(string $filePath) : File
public function parseFileToDecoratedNodes(string $filePath) : array
{
$this->parameterProvider->changeParameter(Option::SOURCE, [$filePath]);
- $nodes = $this->rectorParser->parseFile($filePath);
+ $stmts = $this->rectorParser->parseFile($filePath);
$file = new File($filePath, FileSystem::read($filePath));
- return $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($file, $nodes);
+ $stmts = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($file, $stmts);
+ $file->hydrateStmtsAndTokens($stmts, $stmts, []);
+ $this->currentFileProvider->setFile($file);
+ return $stmts;
}
}
diff --git a/packages/VendorLocker/NodeVendorLocker/ClassMethodReturnTypeOverrideGuard.php b/packages/VendorLocker/NodeVendorLocker/ClassMethodReturnTypeOverrideGuard.php
index 73408f4667bf..e678d3199881 100644
--- a/packages/VendorLocker/NodeVendorLocker/ClassMethodReturnTypeOverrideGuard.php
+++ b/packages/VendorLocker/NodeVendorLocker/ClassMethodReturnTypeOverrideGuard.php
@@ -19,16 +19,11 @@
use Rector\Core\Reflection\ReflectionResolver;
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
use Rector\NodeNameResolver\NodeNameResolver;
-use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PHPStan\ParametersAcceptorSelectorVariantsWrapper;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
use Rector\VendorLocker\ParentClassMethodTypeOverrideGuard;
final class ClassMethodReturnTypeOverrideGuard
{
- /**
- * @var array>
- */
- private const CHAOTIC_CLASS_METHOD_NAMES = ['PhpParser\\NodeVisitor' => ['enterNode', 'leaveNode', 'beforeTraverse', 'afterTraverse']];
/**
* @readonly
* @var \Rector\NodeNameResolver\NodeNameResolver
@@ -74,6 +69,10 @@ final class ClassMethodReturnTypeOverrideGuard
* @var \Rector\Core\FileSystem\FilePathHelper
*/
private $filePathHelper;
+ /**
+ * @var array>
+ */
+ private const CHAOTIC_CLASS_METHOD_NAMES = ['PhpParser\\NodeVisitor' => ['enterNode', 'leaveNode', 'beforeTraverse', 'afterTraverse']];
public function __construct(NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider, FamilyRelationsAnalyzer $familyRelationsAnalyzer, BetterNodeFinder $betterNodeFinder, AstResolver $astResolver, ReflectionResolver $reflectionResolver, ReturnTypeInferer $returnTypeInferer, ParentClassMethodTypeOverrideGuard $parentClassMethodTypeOverrideGuard, FilePathHelper $filePathHelper)
{
$this->nodeNameResolver = $nodeNameResolver;
@@ -86,7 +85,7 @@ public function __construct(NodeNameResolver $nodeNameResolver, ReflectionProvid
$this->parentClassMethodTypeOverrideGuard = $parentClassMethodTypeOverrideGuard;
$this->filePathHelper = $filePathHelper;
}
- public function shouldSkipClassMethod(ClassMethod $classMethod) : bool
+ public function shouldSkipClassMethod(ClassMethod $classMethod, Scope $scope) : bool
{
// 1. skip magic methods
if ($classMethod->isMagic()) {
@@ -106,7 +105,7 @@ public function shouldSkipClassMethod(ClassMethod $classMethod) : bool
if ($classReflection->isInterface()) {
return \true;
}
- if (!$this->isReturnTypeChangeAllowed($classMethod)) {
+ if (!$this->isReturnTypeChangeAllowed($classMethod, $scope)) {
return \true;
}
$childrenClassReflections = $this->familyRelationsAnalyzer->getChildrenOfClassReflection($classReflection);
@@ -121,7 +120,7 @@ public function shouldSkipClassMethod(ClassMethod $classMethod) : bool
}
return $this->hasClassMethodExprReturn($classMethod);
}
- private function isReturnTypeChangeAllowed(ClassMethod $classMethod) : bool
+ private function isReturnTypeChangeAllowed(ClassMethod $classMethod, Scope $scope) : bool
{
// make sure return type is not protected by parent contract
$parentClassMethodReflection = $this->parentClassMethodTypeOverrideGuard->getParentClassMethod($classMethod);
@@ -129,10 +128,6 @@ private function isReturnTypeChangeAllowed(ClassMethod $classMethod) : bool
if (!$parentClassMethodReflection instanceof MethodReflection) {
return \true;
}
- $scope = $classMethod->getAttribute(AttributeKey::SCOPE);
- if (!$scope instanceof Scope) {
- return \false;
- }
$parametersAcceptor = ParametersAcceptorSelectorVariantsWrapper::select($parentClassMethodReflection, $classMethod, $scope);
if ($parametersAcceptor instanceof FunctionVariantWithPhpDocs && !$parametersAcceptor->getNativeReturnType() instanceof MixedType) {
return \false;
diff --git a/packages/VersionBonding/PhpVersionedFilter.php b/packages/VersionBonding/PhpVersionedFilter.php
index 64d4d9c32b11..fdf128cfb14a 100644
--- a/packages/VersionBonding/PhpVersionedFilter.php
+++ b/packages/VersionBonding/PhpVersionedFilter.php
@@ -3,7 +3,7 @@
declare (strict_types=1);
namespace Rector\VersionBonding;
-use Rector\Core\Contract\Rector\RectorInterface;
+use Rector\Core\Contract\Rector\PhpRectorInterface;
use Rector\Core\Php\PhpVersionProvider;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
final class PhpVersionedFilter
@@ -18,11 +18,10 @@ public function __construct(PhpVersionProvider $phpVersionProvider)
$this->phpVersionProvider = $phpVersionProvider;
}
/**
- * @template T as RectorInterface
- * @param array $rectors
- * @return array
+ * @param array $rectors
+ * @return array
*/
- public function filter(array $rectors) : array
+ public function filter(iterable $rectors) : array
{
$minProjectPhpVersion = $this->phpVersionProvider->provide();
$activeRectors = [];
diff --git a/preload.php b/preload.php
index c38d339f2e02..d1eaa8d3fdb4 100644
--- a/preload.php
+++ b/preload.php
@@ -278,6 +278,11 @@
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php';
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php';
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php';
+require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php';
+require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php';
+require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php';
+require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php';
+require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php';
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php';
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php';
require_once __DIR__ . '/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php';
diff --git a/rules/Arguments/NodeAnalyzer/ArgumentAddingScope.php b/rules/Arguments/NodeAnalyzer/ArgumentAddingScope.php
index 961276209fbf..54738cd631cc 100644
--- a/rules/Arguments/NodeAnalyzer/ArgumentAddingScope.php
+++ b/rules/Arguments/NodeAnalyzer/ArgumentAddingScope.php
@@ -11,6 +11,11 @@
use Rector\NodeNameResolver\NodeNameResolver;
final class ArgumentAddingScope
{
+ /**
+ * @readonly
+ * @var \Rector\NodeNameResolver\NodeNameResolver
+ */
+ private $nodeNameResolver;
/**
* @api
* @var string
@@ -26,11 +31,6 @@ final class ArgumentAddingScope
* @var string
*/
public const SCOPE_CLASS_METHOD = 'class_method';
- /**
- * @readonly
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
public function __construct(NodeNameResolver $nodeNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
diff --git a/rules/Arguments/Rector/ClassMethod/ArgumentAdderRector.php b/rules/Arguments/Rector/ClassMethod/ArgumentAdderRector.php
index ceb628de23a1..a8adabb7fd78 100644
--- a/rules/Arguments/Rector/ClassMethod/ArgumentAdderRector.php
+++ b/rules/Arguments/Rector/ClassMethod/ArgumentAdderRector.php
@@ -20,11 +20,11 @@
use Rector\Arguments\NodeAnalyzer\ArgumentAddingScope;
use Rector\Arguments\NodeAnalyzer\ChangedArgumentsDetector;
use Rector\Arguments\ValueObject\ArgumentAdder;
-use Rector\Core\Contract\PhpParser\NodePrinterInterface;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Enum\ObjectReference;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\AstResolver;
+use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Rector\AbstractRector;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
@@ -35,14 +35,6 @@
*/
final class ArgumentAdderRector extends AbstractRector implements ConfigurableRectorInterface
{
- /**
- * @var ArgumentAdder[]
- */
- private $addedArguments = [];
- /**
- * @var bool
- */
- private $haveArgumentsChanged = \false;
/**
* @readonly
* @var \Rector\Arguments\NodeAnalyzer\ArgumentAddingScope
@@ -60,15 +52,23 @@ final class ArgumentAdderRector extends AbstractRector implements ConfigurableRe
private $astResolver;
/**
* @readonly
- * @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
+ * @var \Rector\Core\PhpParser\Printer\BetterStandardPrinter
+ */
+ private $betterStandardPrinter;
+ /**
+ * @var ArgumentAdder[]
+ */
+ private $addedArguments = [];
+ /**
+ * @var bool
*/
- private $nodePrinter;
- public function __construct(ArgumentAddingScope $argumentAddingScope, ChangedArgumentsDetector $changedArgumentsDetector, AstResolver $astResolver, NodePrinterInterface $nodePrinter)
+ private $hasChanged = \false;
+ public function __construct(ArgumentAddingScope $argumentAddingScope, ChangedArgumentsDetector $changedArgumentsDetector, AstResolver $astResolver, BetterStandardPrinter $betterStandardPrinter)
{
$this->argumentAddingScope = $argumentAddingScope;
$this->changedArgumentsDetector = $changedArgumentsDetector;
$this->astResolver = $astResolver;
- $this->nodePrinter = $nodePrinter;
+ $this->betterStandardPrinter = $betterStandardPrinter;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -101,25 +101,23 @@ public function someMethod($value = true)
*/
public function getNodeTypes() : array
{
- return [MethodCall::class, StaticCall::class, ClassMethod::class];
+ return [MethodCall::class, StaticCall::class, Class_::class];
}
/**
- * @param MethodCall|StaticCall|ClassMethod $node
- * @return \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall|\PhpParser\Node\Stmt\ClassMethod|null
+ * @param MethodCall|StaticCall|Class_ $node
+ * @return \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall|\PhpParser\Node\Stmt\Class_|null
*/
public function refactor(Node $node)
{
- $this->haveArgumentsChanged = \false;
- foreach ($this->addedArguments as $addedArgument) {
- if (!$this->isName($node->name, $addedArgument->getMethod())) {
- continue;
+ $this->hasChanged = \false;
+ if ($node instanceof MethodCall || $node instanceof StaticCall) {
+ $this->refactorCall($node);
+ } else {
+ foreach ($node->getMethods() as $classMethod) {
+ $this->refactorClassMethod($node, $classMethod);
}
- if (!$this->isObjectTypeMatch($node, $addedArgument->getObjectType())) {
- continue;
- }
- $this->processPositionWithDefaultValues($node, $addedArgument);
}
- if ($this->haveArgumentsChanged) {
+ if ($this->hasChanged) {
return $node;
}
return null;
@@ -133,21 +131,14 @@ public function configure(array $configuration) : void
$this->addedArguments = $configuration;
}
/**
- * @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall|\PhpParser\Node\Stmt\ClassMethod $node
+ * @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall $call
*/
- private function isObjectTypeMatch($node, ObjectType $objectType) : bool
+ private function isObjectTypeMatch($call, ObjectType $objectType) : bool
{
- if ($node instanceof MethodCall) {
- return $this->isObjectType($node->var, $objectType);
- }
- if ($node instanceof StaticCall) {
- return $this->isObjectType($node->class, $objectType);
+ if ($call instanceof MethodCall) {
+ return $this->isObjectType($call->var, $objectType);
}
- $classLike = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$classLike instanceof Class_) {
- return \false;
- }
- return $this->isObjectType($classLike, $objectType);
+ return $this->isObjectType($call->class, $objectType);
}
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall $node
@@ -181,7 +172,7 @@ private function processMethodCall(MethodCall $methodCall, $defaultValue, int $p
}
$this->fillGapBetweenWithDefaultValue($methodCall, $position);
$methodCall->args[$position] = $arg;
- $this->haveArgumentsChanged = \true;
+ $this->hasChanged = \true;
}
/**
* @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall $node
@@ -204,7 +195,7 @@ private function fillGapBetweenWithDefaultValue($node, int $position) : void
if (!$param->default instanceof Expr) {
throw new ShouldNotHappenException('Previous position does not have default value');
}
- $default = $this->nodePrinter->print($param->default);
+ $default = $this->betterStandardPrinter->print($param->default);
$node->args[$index] = new Arg(new ConstFetch(new Name($default)));
}
}
@@ -238,8 +229,21 @@ private function shouldSkipParameter($node, ArgumentAdder $argumentAdder) : bool
if (isset($node->args[$position])) {
return \true;
}
- // is correct scope?
- return !$this->argumentAddingScope->isInCorrectScope($node, $argumentAdder);
+ // Check if default value is the same
+ $classMethod = $this->astResolver->resolveClassMethodFromCall($node);
+ if (!$classMethod instanceof ClassMethod) {
+ // is correct scope?
+ return !$this->argumentAddingScope->isInCorrectScope($node, $argumentAdder);
+ }
+ if (!isset($classMethod->params[$position])) {
+ // is correct scope?
+ return !$this->argumentAddingScope->isInCorrectScope($node, $argumentAdder);
+ }
+ if ($this->changedArgumentsDetector->isDefaultValueChanged($classMethod->params[$position], $argumentAdder->getArgumentDefaultValue())) {
+ // is correct scope?
+ return !$this->argumentAddingScope->isInCorrectScope($node, $argumentAdder);
+ }
+ return \true;
}
/**
* @param mixed $defaultValue
@@ -255,7 +259,7 @@ private function addClassMethodParam(ClassMethod $classMethod, ArgumentAdder $ar
$param->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($type, TypeKind::PARAM);
}
$classMethod->params[$position] = $param;
- $this->haveArgumentsChanged = \true;
+ $this->hasChanged = \true;
}
private function processStaticCall(StaticCall $staticCall, int $position, ArgumentAdder $argumentAdder) : void
{
@@ -271,6 +275,33 @@ private function processStaticCall(StaticCall $staticCall, int $position, Argume
}
$this->fillGapBetweenWithDefaultValue($staticCall, $position);
$staticCall->args[$position] = new Arg(new Variable($argumentName));
- $this->haveArgumentsChanged = \true;
+ $this->hasChanged = \true;
+ }
+ /**
+ * @param \PhpParser\Node\Expr\StaticCall|\PhpParser\Node\Expr\MethodCall $call
+ */
+ private function refactorCall($call) : void
+ {
+ foreach ($this->addedArguments as $addedArgument) {
+ if (!$this->isName($call->name, $addedArgument->getMethod())) {
+ continue;
+ }
+ if (!$this->isObjectTypeMatch($call, $addedArgument->getObjectType())) {
+ continue;
+ }
+ $this->processPositionWithDefaultValues($call, $addedArgument);
+ }
+ }
+ private function refactorClassMethod(Class_ $class, ClassMethod $classMethod) : void
+ {
+ foreach ($this->addedArguments as $addedArgument) {
+ if (!$this->isName($classMethod, $addedArgument->getMethod())) {
+ continue;
+ }
+ if (!$this->isObjectType($class, $addedArgument->getObjectType())) {
+ continue;
+ }
+ $this->processPositionWithDefaultValues($classMethod, $addedArgument);
+ }
}
}
diff --git a/rules/Arguments/Rector/ClassMethod/ReplaceArgumentDefaultValueRector.php b/rules/Arguments/Rector/ClassMethod/ReplaceArgumentDefaultValueRector.php
index f523d9c1e0ec..f348c5b2f127 100644
--- a/rules/Arguments/Rector/ClassMethod/ReplaceArgumentDefaultValueRector.php
+++ b/rules/Arguments/Rector/ClassMethod/ReplaceArgumentDefaultValueRector.php
@@ -15,19 +15,20 @@
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use RectorPrefix202306\Webmozart\Assert\Assert;
/**
+ * @api used in rector-symfony
* @see \Rector\Tests\Arguments\Rector\ClassMethod\ReplaceArgumentDefaultValueRector\ReplaceArgumentDefaultValueRectorTest
*/
final class ReplaceArgumentDefaultValueRector extends AbstractRector implements ConfigurableRectorInterface
{
- /**
- * @var ReplaceArgumentDefaultValue[]
- */
- private $replacedArguments = [];
/**
* @readonly
* @var \Rector\Arguments\ArgumentDefaultValueReplacer
*/
private $argumentDefaultValueReplacer;
+ /**
+ * @var ReplaceArgumentDefaultValue[]
+ */
+ private $replacedArguments = [];
public function __construct(ArgumentDefaultValueReplacer $argumentDefaultValueReplacer)
{
$this->argumentDefaultValueReplacer = $argumentDefaultValueReplacer;
diff --git a/rules/Arguments/Rector/FuncCall/FunctionArgumentDefaultValueReplacerRector.php b/rules/Arguments/Rector/FuncCall/FunctionArgumentDefaultValueReplacerRector.php
index 32860da584a9..45443ee4213e 100644
--- a/rules/Arguments/Rector/FuncCall/FunctionArgumentDefaultValueReplacerRector.php
+++ b/rules/Arguments/Rector/FuncCall/FunctionArgumentDefaultValueReplacerRector.php
@@ -20,15 +20,15 @@
*/
final class FunctionArgumentDefaultValueReplacerRector extends AbstractRector implements ConfigurableRectorInterface
{
- /**
- * @var ReplaceFuncCallArgumentDefaultValue[]
- */
- private $replacedArguments = [];
/**
* @readonly
* @var \Rector\Arguments\ArgumentDefaultValueReplacer
*/
private $argumentDefaultValueReplacer;
+ /**
+ * @var ReplaceFuncCallArgumentDefaultValue[]
+ */
+ private $replacedArguments = [];
public function __construct(ArgumentDefaultValueReplacer $argumentDefaultValueReplacer)
{
$this->argumentDefaultValueReplacer = $argumentDefaultValueReplacer;
diff --git a/rules/Arguments/Rector/MethodCall/RemoveMethodCallParamRector.php b/rules/Arguments/Rector/MethodCall/RemoveMethodCallParamRector.php
index 632a06946d18..ee96c49dba90 100644
--- a/rules/Arguments/Rector/MethodCall/RemoveMethodCallParamRector.php
+++ b/rules/Arguments/Rector/MethodCall/RemoveMethodCallParamRector.php
@@ -56,6 +56,9 @@ public function getNodeTypes() : array
public function refactor(Node $node) : ?Node
{
$hasChanged = \false;
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
foreach ($this->removeMethodCallParams as $removeMethodCallParam) {
if (!$this->isName($node->name, $removeMethodCallParam->getMethodName())) {
continue;
diff --git a/rules/Arguments/ValueObject/RemoveMethodCallParam.php b/rules/Arguments/ValueObject/RemoveMethodCallParam.php
index dc3e09282043..a1c337a4f16d 100644
--- a/rules/Arguments/ValueObject/RemoveMethodCallParam.php
+++ b/rules/Arguments/ValueObject/RemoveMethodCallParam.php
@@ -4,6 +4,7 @@
namespace Rector\Arguments\ValueObject;
use PHPStan\Type\ObjectType;
+use Rector\Core\Validation\RectorAssert;
final class RemoveMethodCallParam
{
/**
@@ -26,6 +27,8 @@ public function __construct(string $class, string $methodName, int $paramPositio
$this->class = $class;
$this->methodName = $methodName;
$this->paramPosition = $paramPosition;
+ RectorAssert::className($class);
+ RectorAssert::methodName($methodName);
}
public function getObjectType() : ObjectType
{
diff --git a/rules/Arguments/ValueObject/ReplaceArgumentDefaultValue.php b/rules/Arguments/ValueObject/ReplaceArgumentDefaultValue.php
index 7791728a7860..e93effa0d268 100644
--- a/rules/Arguments/ValueObject/ReplaceArgumentDefaultValue.php
+++ b/rules/Arguments/ValueObject/ReplaceArgumentDefaultValue.php
@@ -8,10 +8,6 @@
use Rector\Core\Validation\RectorAssert;
final class ReplaceArgumentDefaultValue implements ReplaceArgumentDefaultValueInterface
{
- /**
- * @var string
- */
- public const ANY_VALUE_BEFORE = '*ANY_VALUE_BEFORE*';
/**
* @readonly
* @var string
@@ -37,6 +33,10 @@ final class ReplaceArgumentDefaultValue implements ReplaceArgumentDefaultValueIn
* @var mixed
*/
private $valueAfter;
+ /**
+ * @var string
+ */
+ public const ANY_VALUE_BEFORE = '*ANY_VALUE_BEFORE*';
/**
* @param int<0, max> $position
* @param mixed $valueBefore
diff --git a/rules/CodeQuality/NodeAnalyzer/ConstructorPropertyDefaultExprResolver.php b/rules/CodeQuality/NodeAnalyzer/ConstructorPropertyDefaultExprResolver.php
deleted file mode 100644
index 427744fafe2d..000000000000
--- a/rules/CodeQuality/NodeAnalyzer/ConstructorPropertyDefaultExprResolver.php
+++ /dev/null
@@ -1,68 +0,0 @@
-nodeNameResolver = $nodeNameResolver;
- $this->exprAnalyzer = $exprAnalyzer;
- }
- /**
- * @return DefaultPropertyExprAssign[]
- */
- public function resolve(ClassMethod $classMethod) : array
- {
- $stmts = $classMethod->getStmts();
- if ($stmts === null) {
- return [];
- }
- $defaultPropertyExprAssigns = [];
- foreach ($stmts as $stmt) {
- if (!$stmt instanceof Expression) {
- break;
- }
- $nestedStmt = $stmt->expr;
- if (!$nestedStmt instanceof Assign) {
- continue;
- }
- $assign = $nestedStmt;
- if (!$assign->var instanceof PropertyFetch) {
- continue;
- }
- $propertyFetch = $assign->var;
- if (!$this->nodeNameResolver->isName($propertyFetch->var, 'this')) {
- continue;
- }
- $propertyName = $this->nodeNameResolver->getName($propertyFetch->name);
- if (!\is_string($propertyName)) {
- continue;
- }
- $expr = $assign->expr;
- if ($this->exprAnalyzer->isDynamicExpr($expr)) {
- continue;
- }
- $defaultPropertyExprAssigns[] = new DefaultPropertyExprAssign($stmt, $propertyName, $expr);
- }
- return $defaultPropertyExprAssigns;
- }
-}
diff --git a/rules/CodeQuality/NodeAnalyzer/LocalPropertyAnalyzer.php b/rules/CodeQuality/NodeAnalyzer/LocalPropertyAnalyzer.php
index 64b60dc3c512..00b6c563dc61 100644
--- a/rules/CodeQuality/NodeAnalyzer/LocalPropertyAnalyzer.php
+++ b/rules/CodeQuality/NodeAnalyzer/LocalPropertyAnalyzer.php
@@ -12,24 +12,20 @@
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\NodeTraverser;
+use PHPStan\Analyser\Scope;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use Rector\CodeQuality\TypeResolver\ArrayDimFetchTypeResolver;
use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeNameResolver\NodeNameResolver;
+use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser;
final class LocalPropertyAnalyzer
{
- /**
- * @var string
- */
- private const LARAVEL_COLLECTION_CLASS = 'Illuminate\\Support\\Collection';
/**
* @readonly
* @var \Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser
@@ -40,11 +36,6 @@ final class LocalPropertyAnalyzer
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
/**
* @readonly
* @var \Rector\CodeQuality\TypeResolver\ArrayDimFetchTypeResolver
@@ -65,11 +56,14 @@ final class LocalPropertyAnalyzer
* @var \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory
*/
private $typeFactory;
- public function __construct(SimpleCallableNodeTraverser $simpleCallableNodeTraverser, NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder, ArrayDimFetchTypeResolver $arrayDimFetchTypeResolver, NodeTypeResolver $nodeTypeResolver, PropertyFetchAnalyzer $propertyFetchAnalyzer, TypeFactory $typeFactory)
+ /**
+ * @var string
+ */
+ private const LARAVEL_COLLECTION_CLASS = 'Illuminate\\Support\\Collection';
+ public function __construct(SimpleCallableNodeTraverser $simpleCallableNodeTraverser, NodeNameResolver $nodeNameResolver, ArrayDimFetchTypeResolver $arrayDimFetchTypeResolver, NodeTypeResolver $nodeTypeResolver, PropertyFetchAnalyzer $propertyFetchAnalyzer, TypeFactory $typeFactory)
{
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
$this->nodeNameResolver = $nodeNameResolver;
- $this->betterNodeFinder = $betterNodeFinder;
$this->arrayDimFetchTypeResolver = $arrayDimFetchTypeResolver;
$this->nodeTypeResolver = $nodeTypeResolver;
$this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
@@ -114,7 +108,13 @@ private function shouldSkip(Node $node) : bool
return \true;
}
// skip closure call
- return $node instanceof MethodCall && $node->var instanceof Closure;
+ if ($node instanceof MethodCall && $node->var instanceof Closure) {
+ return \true;
+ }
+ if ($node instanceof StaticCall) {
+ return $this->nodeNameResolver->isName($node->class, self::LARAVEL_COLLECTION_CLASS);
+ }
+ return \false;
}
private function resolvePropertyName(Node $node) : ?string
{
@@ -131,17 +131,10 @@ private function resolvePropertyName(Node $node) : ?string
}
private function shouldSkipPropertyFetch(PropertyFetch $propertyFetch) : bool
{
- // special Laravel collection scope
- if ($this->shouldSkipForLaravelCollection($propertyFetch)) {
- return \true;
- }
if ($this->isPartOfClosureBind($propertyFetch)) {
return \true;
}
- if ($propertyFetch->name instanceof Variable) {
- return \true;
- }
- return $this->isPartOfClosureBindTo($propertyFetch);
+ return $propertyFetch->name instanceof Variable;
}
/**
* @param array $propertyNameToTypes
@@ -156,38 +149,16 @@ private function normalizeToSingleType(array $propertyNameToTypes) : array
}
return $propertyNameToType;
}
- private function shouldSkipForLaravelCollection(PropertyFetch $propertyFetch) : bool
- {
- $staticCallOrClassMethod = $this->betterNodeFinder->findParentByTypes($propertyFetch, [ClassMethod::class, StaticCall::class]);
- if (!$staticCallOrClassMethod instanceof StaticCall) {
- return \false;
- }
- return $this->nodeNameResolver->isName($staticCallOrClassMethod->class, self::LARAVEL_COLLECTION_CLASS);
- }
/**
* Local property is actually not local one, but belongs to passed object
* See https://ocramius.github.io/blog/accessing-private-php-class-members-without-reflection/
*/
private function isPartOfClosureBind(PropertyFetch $propertyFetch) : bool
{
- $parentStaticCall = $this->betterNodeFinder->findParentType($propertyFetch, StaticCall::class);
- if (!$parentStaticCall instanceof StaticCall) {
- return \false;
- }
- if (!$this->nodeNameResolver->isName($parentStaticCall->class, 'Closure')) {
- return \true;
- }
- return $this->nodeNameResolver->isName($parentStaticCall->name, 'bind');
- }
- private function isPartOfClosureBindTo(PropertyFetch $propertyFetch) : bool
- {
- $parentMethodCall = $this->betterNodeFinder->findParentType($propertyFetch, MethodCall::class);
- if (!$parentMethodCall instanceof MethodCall) {
- return \false;
- }
- if (!$parentMethodCall->var instanceof Closure) {
+ $scope = $propertyFetch->getAttribute(AttributeKey::SCOPE);
+ if (!$scope instanceof Scope) {
return \false;
}
- return $this->nodeNameResolver->isName($parentMethodCall->name, 'bindTo');
+ return $scope->isInClosureBind();
}
}
diff --git a/rules/CodeQuality/NodeFactory/PropertyTypeDecorator.php b/rules/CodeQuality/NodeFactory/PropertyTypeDecorator.php
index 917fe572e220..e6185ec269aa 100644
--- a/rules/CodeQuality/NodeFactory/PropertyTypeDecorator.php
+++ b/rules/CodeQuality/NodeFactory/PropertyTypeDecorator.php
@@ -37,6 +37,6 @@ public function decorateProperty(Property $property, Type $propertyType) : void
$propertyType = $this->typeNormalizer->generalizeConstantBoolTypes($propertyType);
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
$phpDocInfo->makeMultiLined();
- $this->phpDocTypeChanger->changeVarType($phpDocInfo, $propertyType);
+ $this->phpDocTypeChanger->changeVarType($property, $phpDocInfo, $propertyType);
}
}
diff --git a/rules/CodeQuality/NodeManipulator/ExprBoolCaster.php b/rules/CodeQuality/NodeManipulator/ExprBoolCaster.php
index da6f944b4db1..7c3436e52b44 100644
--- a/rules/CodeQuality/NodeManipulator/ExprBoolCaster.php
+++ b/rules/CodeQuality/NodeManipulator/ExprBoolCaster.php
@@ -8,6 +8,8 @@
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
use PhpParser\Node\Expr\BooleanNot;
use PhpParser\Node\Expr\Cast\Bool_;
+use PHPStan\Type\Type;
+use PHPStan\Type\TypeCombinator;
use PHPStan\Type\UnionType;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\NodeTypeResolver\NodeTypeResolver;
@@ -44,13 +46,13 @@ public function __construct(NodeTypeResolver $nodeTypeResolver, TypeUnwrapper $t
}
public function boolCastOrNullCompareIfNeeded(Expr $expr) : Expr
{
- if (!$this->nodeTypeResolver->isNullableType($expr)) {
- if (!$this->isBoolCastNeeded($expr)) {
+ $exprStaticType = $this->nodeTypeResolver->getType($expr);
+ if (!TypeCombinator::containsNull($exprStaticType)) {
+ if (!$this->isBoolCastNeeded($expr, $exprStaticType)) {
return $expr;
}
return new Bool_($expr);
}
- $exprStaticType = $this->nodeTypeResolver->getType($expr);
// if we remove null type, still has to be trueable
if ($exprStaticType instanceof UnionType) {
$unionTypeWithoutNullType = $this->typeUnwrapper->removeNullTypeFromUnionType($exprStaticType);
@@ -60,17 +62,16 @@ public function boolCastOrNullCompareIfNeeded(Expr $expr) : Expr
} elseif ($this->staticTypeAnalyzer->isAlwaysTruableType($exprStaticType)) {
return new NotIdentical($expr, $this->nodeFactory->createNull());
}
- if (!$this->isBoolCastNeeded($expr)) {
+ if (!$this->isBoolCastNeeded($expr, $exprStaticType)) {
return $expr;
}
return new Bool_($expr);
}
- private function isBoolCastNeeded(Expr $expr) : bool
+ private function isBoolCastNeeded(Expr $expr, Type $exprType) : bool
{
if ($expr instanceof BooleanNot) {
return \false;
}
- $exprType = $this->nodeTypeResolver->getType($expr);
if ($exprType->isBoolean()->yes()) {
return \false;
}
diff --git a/rules/CodeQuality/NodeTypeGroup.php b/rules/CodeQuality/NodeTypeGroup.php
deleted file mode 100644
index 431d1bfe59c3..000000000000
--- a/rules/CodeQuality/NodeTypeGroup.php
+++ /dev/null
@@ -1,29 +0,0 @@
->
- * @api
- */
- public const STMTS_AWARE = [ClassMethod::class, Function_::class, If_::class, Else_::class, ElseIf_::class, Do_::class, Foreach_::class, TryCatch::class, While_::class, For_::class, Closure::class, Finally_::class, Case_::class, Catch_::class];
-}
diff --git a/rules/CodeQuality/Rector/Array_/CallableThisArrayToAnonymousFunctionRector.php b/rules/CodeQuality/Rector/Array_/CallableThisArrayToAnonymousFunctionRector.php
index 1b9c86a38dd3..e0e34345f25e 100644
--- a/rules/CodeQuality/Rector/Array_/CallableThisArrayToAnonymousFunctionRector.php
+++ b/rules/CodeQuality/Rector/Array_/CallableThisArrayToAnonymousFunctionRector.php
@@ -96,6 +96,9 @@ public function getNodeTypes() : array
*/
public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
+ if ($this->shouldSkipTwigExtension($scope)) {
+ return null;
+ }
$arrayCallable = $this->arrayCallableMethodMatcher->match($node, $scope);
if (!$arrayCallable instanceof ArrayCallable) {
return null;
@@ -106,4 +109,12 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
}
return $this->anonymousFunctionFactory->createFromPhpMethodReflection($phpMethodReflection, $arrayCallable->getCallerExpr());
}
+ private function shouldSkipTwigExtension(Scope $scope) : bool
+ {
+ if (!$scope->isInClass()) {
+ return \false;
+ }
+ $classReflection = $scope->getClassReflection();
+ return $classReflection->isSubclassOf('Twig\\Extension\\ExtensionInterface');
+ }
}
diff --git a/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php b/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php
index 1de34dbf2fc5..03af1962be38 100644
--- a/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php
+++ b/rules/CodeQuality/Rector/Catch_/ThrowWithPreviousExceptionRector.php
@@ -28,15 +28,15 @@
*/
final class ThrowWithPreviousExceptionRector extends AbstractRector
{
- /**
- * @var int
- */
- private const DEFAULT_EXCEPTION_ARGUMENT_POSITION = 2;
/**
* @readonly
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @var int
+ */
+ private const DEFAULT_EXCEPTION_ARGUMENT_POSITION = 2;
public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
@@ -113,6 +113,9 @@ private function refactorThrow(Throw_ $throw, Variable $catchedThrowableVariable
if ($exceptionArgumentPosition === null) {
return null;
}
+ if ($new->isFirstClassCallable()) {
+ return null;
+ }
// exception is bundled
if (isset($new->getArgs()[$exceptionArgumentPosition])) {
return null;
diff --git a/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php b/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php
index 2d6a5f243599..17eb393ed2c2 100644
--- a/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php
+++ b/rules/CodeQuality/Rector/ClassConstFetch/ConvertStaticPrivateConstantToSelfRector.php
@@ -8,50 +8,24 @@
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassMethod;
-use PHPStan\Reflection\ClassReflection;
-use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
-use Rector\Core\Reflection\ReflectionResolver;
-use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
-use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
+use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\CodeQuality\Rector\ClassConstFetch\ConvertStaticPrivateConstantToSelfRector\ConvertStaticPrivateConstantToSelfRectorTest
+ *
* @see https://3v4l.org/8Y0ba
* @see https://phpstan.org/r/11d4c850-1a40-4fae-b665-291f96104d11
*/
-final class ConvertStaticPrivateConstantToSelfRector extends AbstractRector implements AllowEmptyConfigurableRectorInterface
+final class ConvertStaticPrivateConstantToSelfRector extends AbstractRector
{
- /**
- * @api
- * @var string
- */
- public const ENABLE_FOR_NON_FINAL_CLASSES = 'enable_for_non_final_classes';
- /**
- * @var bool
- */
- private $enableForNonFinalClasses = \false;
- /**
- * @readonly
- * @var \Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer
- */
- private $familyRelationsAnalyzer;
- /**
- * @readonly
- * @var \Rector\Core\Reflection\ReflectionResolver
- */
- private $reflectionResolver;
- public function __construct(FamilyRelationsAnalyzer $familyRelationsAnalyzer, ReflectionResolver $reflectionResolver)
- {
- $this->familyRelationsAnalyzer = $familyRelationsAnalyzer;
- $this->reflectionResolver = $reflectionResolver;
- }
public function getRuleDefinition() : RuleDefinition
{
- return new RuleDefinition('Replaces static::* access to private constants with self::*', [new ConfiguredCodeSample(<<<'CODE_SAMPLE'
-final class Foo {
+ return new RuleDefinition('Replaces static::* access to private constants with self::*', [new CodeSample(<<<'CODE_SAMPLE'
+final class Foo
+{
private const BAR = 'bar';
+
public function run()
{
$bar = static::BAR;
@@ -59,45 +33,54 @@ public function run()
}
CODE_SAMPLE
, <<<'CODE_SAMPLE'
-final class Foo {
+final class Foo
+{
private const BAR = 'bar';
+
public function run()
{
$bar = self::BAR;
}
}
CODE_SAMPLE
-, [self::ENABLE_FOR_NON_FINAL_CLASSES => \false])]);
+)]);
}
+ /**
+ * @return array>
+ */
public function getNodeTypes() : array
{
- return [ClassConstFetch::class];
- }
- public function configure(array $configuration) : void
- {
- $this->enableForNonFinalClasses = $configuration[self::ENABLE_FOR_NON_FINAL_CLASSES] ?? (bool) \current($configuration);
+ return [Class_::class];
}
/**
- * @param ClassConstFetch $node
+ * @param Class_ $node
*/
- public function refactor(Node $node) : ?ClassConstFetch
+ public function refactor(Node $node) : ?Class_
{
- $class = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$class instanceof Class_) {
+ if ($node->getConstants() === []) {
return null;
}
- if ($this->shouldBeSkipped($class, $node)) {
- return null;
+ $class = $node;
+ $hasChanged = \false;
+ $this->traverseNodesWithCallable($class, function (Node $node) use($class, &$hasChanged) : ?Node {
+ if (!$node instanceof ClassConstFetch) {
+ return null;
+ }
+ if ($this->shouldBeSkipped($class, $node)) {
+ return null;
+ }
+ $hasChanged = \true;
+ $node->class = new Name('self');
+ return $node;
+ });
+ if ($hasChanged) {
+ return $node;
}
- $node->class = new Name('self');
- return $node;
+ return null;
}
private function isUsingStatic(ClassConstFetch $classConstFetch) : bool
{
- if (!$classConstFetch->class instanceof Name) {
- return \false;
- }
- return $classConstFetch->class->toString() === 'static';
+ return $this->isName($classConstFetch->class, 'static');
}
private function isPrivateConstant(ClassConstFetch $classConstFetch, Class_ $class) : bool
{
@@ -113,47 +96,12 @@ private function isPrivateConstant(ClassConstFetch $classConstFetch, Class_ $cla
}
return \false;
}
- private function isUsedInPrivateMethod(ClassConstFetch $classConstFetch) : bool
- {
- $classMethod = $this->betterNodeFinder->findParentType($classConstFetch, ClassMethod::class);
- if (!$classMethod instanceof ClassMethod) {
- return \false;
- }
- return $classMethod->flags === Class_::MODIFIER_PRIVATE;
- }
private function shouldBeSkipped(Class_ $class, ClassConstFetch $classConstFetch) : bool
{
if (!$this->isUsingStatic($classConstFetch)) {
return \true;
}
- if (!$this->isPrivateConstant($classConstFetch, $class)) {
- return \true;
- }
- if ($this->isUsedInPrivateMethod($classConstFetch)) {
- return \false;
- }
- if ($this->enableForNonFinalClasses) {
- return $this->isOverwrittenInChildClass($classConstFetch);
- }
- return !$class->isFinal();
- }
- private function isOverwrittenInChildClass(ClassConstFetch $classConstFetch) : bool
- {
- $constantName = $this->getConstantName($classConstFetch);
- if ($constantName === null) {
- return \false;
- }
- $classReflection = $this->reflectionResolver->resolveClassReflection($classConstFetch);
- if (!$classReflection instanceof ClassReflection) {
- return \false;
- }
- $childrenClassReflections = $this->familyRelationsAnalyzer->getChildrenOfClassReflection($classReflection);
- foreach ($childrenClassReflections as $childClassReflection) {
- if ($childClassReflection->hasConstant($constantName)) {
- return \true;
- }
- }
- return \false;
+ return !$this->isPrivateConstant($classConstFetch, $class);
}
private function getConstantName(ClassConstFetch $classConstFetch) : ?string
{
diff --git a/rules/CodeQuality/Rector/ClassMethod/InlineArrayReturnAssignRector.php b/rules/CodeQuality/Rector/ClassMethod/InlineArrayReturnAssignRector.php
index e4799f8bf6ec..43fca3ebd7ad 100644
--- a/rules/CodeQuality/Rector/ClassMethod/InlineArrayReturnAssignRector.php
+++ b/rules/CodeQuality/Rector/ClassMethod/InlineArrayReturnAssignRector.php
@@ -5,6 +5,7 @@
use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
+use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Variable;
@@ -76,6 +77,9 @@ public function refactor(Node $node) : ?Node
if (!$variable instanceof Variable) {
return null;
}
+ if (!$this->areAssignExclusiveToDimFetch($stmts)) {
+ return null;
+ }
$lastStmt = \array_pop($stmts);
if (!$lastStmt instanceof Stmt) {
return null;
@@ -131,4 +135,32 @@ private function createArray(array $keysAndExprs) : Array_
}
return new Array_($arrayItems);
}
+ /**
+ * Only:
+ * $items['...'] = $result;
+ *
+ * @param Stmt[] $stmts
+ */
+ private function areAssignExclusiveToDimFetch(array $stmts) : bool
+ {
+ \end($stmts);
+ $lastKey = \key($stmts);
+ foreach ($stmts as $key => $stmt) {
+ if ($key === $lastKey) {
+ // skip last item
+ continue;
+ }
+ if (!$stmt instanceof Expression) {
+ return \false;
+ }
+ if (!$stmt->expr instanceof Assign) {
+ return \false;
+ }
+ $assign = $stmt->expr;
+ if (!$assign->var instanceof ArrayDimFetch) {
+ return \false;
+ }
+ }
+ return \true;
+ }
}
diff --git a/rules/RemovingStatic/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php b/rules/CodeQuality/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php
similarity index 50%
rename from rules/RemovingStatic/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php
rename to rules/CodeQuality/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php
index ec8b717f35f8..fa6fe2c240a6 100644
--- a/rules/RemovingStatic/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php
+++ b/rules/CodeQuality/Rector/ClassMethod/LocallyCalledStaticMethodToNonStaticRector.php
@@ -1,16 +1,16 @@
isPrivate()) {
- return null;
+ $hasChanged = \false;
+ foreach ($node->getMethods() as $classMethod) {
+ if (!$classMethod->isPrivate()) {
+ continue;
}
- return $this->refactorClassMethod($node);
+ $changedClassMethod = $this->refactorClassMethod($node, $classMethod);
+ if ($changedClassMethod instanceof ClassMethod) {
+ $hasChanged = \true;
+ }
+ }
+ if ($hasChanged) {
+ return $node;
}
- return $this->refactorStaticCall($node);
+ return null;
}
- private function refactorClassMethod(ClassMethod $classMethod) : ?ClassMethod
+ private function refactorClassMethod(Class_ $class, ClassMethod $classMethod) : ?ClassMethod
{
if (!$classMethod->isStatic()) {
return null;
@@ -105,47 +112,58 @@ private function refactorClassMethod(ClassMethod $classMethod) : ?ClassMethod
if ($this->classMethodVisibilityGuard->isClassMethodVisibilityGuardedByParent($classMethod, $classReflection)) {
return null;
}
+ if ($this->isClassMethodCalledInAnotherStaticClassMethod($class, $classMethod)) {
+ return null;
+ }
+ // replace all the calls
+ $classMethodName = $this->getName($classMethod);
+ $this->traverseNodesWithCallable($class, function (Node $node) use($classMethodName) : ?MethodCall {
+ if (!$node instanceof StaticCall) {
+ return null;
+ }
+ if (!$this->isName($node->class, 'self')) {
+ return null;
+ }
+ if (!$this->isName($node->name, $classMethodName)) {
+ return null;
+ }
+ return new MethodCall(new Variable('this'), $classMethodName, $node->args);
+ });
// change static calls to non-static ones, but only if in non-static method!!!
$this->visibilityManipulator->makeNonStatic($classMethod);
return $classMethod;
}
- private function refactorStaticCall(StaticCall $staticCall) : ?MethodCall
+ /**
+ * If the static class method is called in another static class method,
+ * we should keep it to avoid calling $this in static
+ */
+ private function isClassMethodCalledInAnotherStaticClassMethod(Class_ $class, ClassMethod $classMethod) : bool
{
- $classLike = $this->betterNodeFinder->findParentType($staticCall, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
- return null;
- }
- /** @var ClassMethod[] $classMethods */
- $classMethods = $this->betterNodeFinder->findInstanceOf($classLike, ClassMethod::class);
- foreach ($classMethods as $classMethod) {
- if (!$this->isClassMethodMatchingStaticCall($classMethod, $staticCall)) {
+ $currentClassMethodName = $this->getName($classMethod);
+ $isInsideStaticClassMethod = \false;
+ // check if called stati call somewhere in class, but only in static methods
+ foreach ($class->getMethods() as $checkedClassMethod) {
+ // not a problem
+ if (!$checkedClassMethod->isStatic()) {
continue;
}
- if ($this->isInStaticClassMethod($staticCall)) {
- continue;
+ $this->traverseNodesWithCallable($checkedClassMethod, function (Node $node) use($currentClassMethodName, &$isInsideStaticClassMethod) : ?int {
+ if (!$node instanceof StaticCall) {
+ return null;
+ }
+ if (!$this->isName($node->class, 'self')) {
+ return null;
+ }
+ if (!$this->isName($node->name, $currentClassMethodName)) {
+ return null;
+ }
+ $isInsideStaticClassMethod = \true;
+ return NodeTraverser::STOP_TRAVERSAL;
+ });
+ if ($isInsideStaticClassMethod) {
+ return $isInsideStaticClassMethod;
}
- $thisVariable = new Variable('this');
- return new MethodCall($thisVariable, $staticCall->name, $staticCall->args);
- }
- return null;
- }
- private function isInStaticClassMethod(StaticCall $staticCall) : bool
- {
- $locationClassMethod = $this->betterNodeFinder->findParentType($staticCall, ClassMethod::class);
- if (!$locationClassMethod instanceof ClassMethod) {
- return \false;
- }
- return $locationClassMethod->isStatic();
- }
- private function isClassMethodMatchingStaticCall(ClassMethod $classMethod, StaticCall $staticCall) : bool
- {
- $classLike = $this->betterNodeFinder->findParentType($classMethod, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
- return \false;
}
- $className = (string) $this->nodeNameResolver->getName($classLike);
- $objectType = new ObjectType($className);
- $callerType = $this->nodeTypeResolver->getType($staticCall->class);
- return $objectType->equals($callerType);
+ return \false;
}
}
diff --git a/rules/CodeQuality/Rector/ClassMethod/NarrowUnionTypeDocRector.php b/rules/CodeQuality/Rector/ClassMethod/NarrowUnionTypeDocRector.php
deleted file mode 100644
index 6d3b55b1c9f2..000000000000
--- a/rules/CodeQuality/Rector/ClassMethod/NarrowUnionTypeDocRector.php
+++ /dev/null
@@ -1,57 +0,0 @@
->
- */
- public function getNodeTypes() : array
- {
- return [ClassMethod::class];
- }
- /**
- * @param ClassMethod $node
- */
- public function refactor(Node $node) : ?Node
- {
- $errorMessage = \sprintf('Rule "%s" is deprecated, as we moved from docblocks for type declarations. Use strict type rules instead', self::class);
- \trigger_error($errorMessage, \E_USER_WARNING);
- \sleep(3);
- return null;
- }
-}
diff --git a/rules/CodeQuality/Rector/ClassMethod/OptionalParametersAfterRequiredRector.php b/rules/CodeQuality/Rector/ClassMethod/OptionalParametersAfterRequiredRector.php
index ae7e00e172db..172e0b02417a 100644
--- a/rules/CodeQuality/Rector/ClassMethod/OptionalParametersAfterRequiredRector.php
+++ b/rules/CodeQuality/Rector/ClassMethod/OptionalParametersAfterRequiredRector.php
@@ -114,6 +114,9 @@ private function refactorNew(New_ $new, Scope $scope) : ?New_
if ($new->args === []) {
return null;
}
+ if ($new->isFirstClassCallable()) {
+ return null;
+ }
$methodReflection = $this->reflectionResolver->resolveMethodReflectionFromNew($new);
if (!$methodReflection instanceof MethodReflection) {
return null;
@@ -131,6 +134,9 @@ private function refactorNew(New_ $new, Scope $scope) : ?New_
*/
private function refactorMethodCall($methodCall, Scope $scope)
{
+ if ($methodCall->isFirstClassCallable()) {
+ return null;
+ }
$methodReflection = $this->reflectionResolver->resolveFunctionLikeReflectionFromCall($methodCall);
if (!$methodReflection instanceof MethodReflection) {
return null;
diff --git a/rules/CodeQuality/Rector/ClassMethod/ReturnTypeFromStrictScalarReturnExprRector.php b/rules/CodeQuality/Rector/ClassMethod/ReturnTypeFromStrictScalarReturnExprRector.php
index ddec41fe2c1a..0f2f38c883fa 100644
--- a/rules/CodeQuality/Rector/ClassMethod/ReturnTypeFromStrictScalarReturnExprRector.php
+++ b/rules/CodeQuality/Rector/ClassMethod/ReturnTypeFromStrictScalarReturnExprRector.php
@@ -7,8 +7,9 @@
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
+use PHPStan\Analyser\Scope;
use PHPStan\Type\Type;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersion;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\TypeDeclaration\NodeAnalyzer\ReturnTypeAnalyzer\StrictScalarReturnTypeAnalyzer;
@@ -19,7 +20,7 @@
/**
* @see \Rector\Tests\CodeQuality\Rector\ClassMethod\ReturnTypeFromStrictScalarReturnExprRector\ReturnTypeFromStrictScalarReturnExprRectorTest
*/
-final class ReturnTypeFromStrictScalarReturnExprRector extends AbstractRector implements MinPhpVersionInterface
+final class ReturnTypeFromStrictScalarReturnExprRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -76,12 +77,12 @@ public function getNodeTypes() : array
/**
* @param ClassMethod|Function_|Closure $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
if ($node->returnType !== null) {
return null;
}
- $scalarReturnType = $this->strictScalarReturnTypeAnalyzer->matchAlwaysScalarReturnType($node);
+ $scalarReturnType = $this->strictScalarReturnTypeAnalyzer->matchAlwaysScalarReturnType($node, $scope);
if (!$scalarReturnType instanceof Type) {
return null;
}
@@ -89,7 +90,7 @@ public function refactor(Node $node) : ?Node
if (!$returnTypeNode instanceof Node) {
return null;
}
- if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node)) {
+ if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
return null;
}
$node->returnType = $returnTypeNode;
diff --git a/rules/CodeQuality/Rector/Class_/CompleteDynamicPropertiesRector.php b/rules/CodeQuality/Rector/Class_/CompleteDynamicPropertiesRector.php
index a3ff4c97f36d..ba13cb212b1b 100644
--- a/rules/CodeQuality/Rector/Class_/CompleteDynamicPropertiesRector.php
+++ b/rules/CodeQuality/Rector/Class_/CompleteDynamicPropertiesRector.php
@@ -180,7 +180,7 @@ private function filterOutExistingProperties(Class_ $class, ClassReflection $cla
if ($classReflection->hasProperty($propertyToComplete)) {
continue;
}
- $propertyMetadata = new PropertyMetadata($propertyToComplete, new ObjectType($className), Class_::MODIFIER_PRIVATE);
+ $propertyMetadata = new PropertyMetadata($propertyToComplete, new ObjectType($className));
$hasClassContextProperty = $this->propertyPresenceChecker->hasClassContextProperty($class, $propertyMetadata);
if ($hasClassContextProperty) {
continue;
diff --git a/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php b/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php
index 4fbe0c3cfd4b..b18528fdc3b3 100644
--- a/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php
+++ b/rules/CodeQuality/Rector/Class_/InlineConstructorDefaultToPropertyRector.php
@@ -4,10 +4,14 @@
namespace Rector\CodeQuality\Rector\Class_;
use PhpParser\Node;
+use PhpParser\Node\Expr\Assign;
+use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\PropertyProperty;
-use Rector\CodeQuality\NodeAnalyzer\ConstructorPropertyDefaultExprResolver;
+use PhpParser\Node\Stmt\Expression;
+use PhpParser\Node\Stmt\If_;
+use PhpParser\Node\Stmt\Property;
+use Rector\Core\NodeAnalyzer\ExprAnalyzer;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\MethodName;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -19,12 +23,12 @@ final class InlineConstructorDefaultToPropertyRector extends AbstractRector
{
/**
* @readonly
- * @var \Rector\CodeQuality\NodeAnalyzer\ConstructorPropertyDefaultExprResolver
+ * @var \Rector\Core\NodeAnalyzer\ExprAnalyzer
*/
- private $constructorPropertyDefaultExprResolver;
- public function __construct(ConstructorPropertyDefaultExprResolver $constructorPropertyDefaultExprResolver)
+ private $exprAnalyzer;
+ public function __construct(ExprAnalyzer $exprAnalyzer)
{
- $this->constructorPropertyDefaultExprResolver = $constructorPropertyDefaultExprResolver;
+ $this->exprAnalyzer = $exprAnalyzer;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -63,25 +67,51 @@ public function getNodeTypes() : array
*/
public function refactor(Node $node) : ?Node
{
+ $hasChanged = \false;
$constructClassMethod = $node->getMethod(MethodName::CONSTRUCT);
if (!$constructClassMethod instanceof ClassMethod) {
return null;
}
- // resolve property defaults
- $defaultPropertyExprAssigns = $this->constructorPropertyDefaultExprResolver->resolve($constructClassMethod);
- if ($defaultPropertyExprAssigns === []) {
+ if ($constructClassMethod->stmts === null) {
return null;
}
- $hasChanged = \false;
- $propertyProperties = $this->getNonReadonlyPropertyProperty($node);
- foreach ($defaultPropertyExprAssigns as $defaultPropertyExprAssign) {
- foreach ($propertyProperties as $propertyProperty) {
- if (!$this->isName($propertyProperty, $defaultPropertyExprAssign->getPropertyName())) {
+ foreach ($constructClassMethod->stmts as $key => $stmt) {
+ // code that is possibly breaking flow
+ if ($stmt instanceof If_) {
+ return null;
+ }
+ if (!$stmt instanceof Expression) {
+ continue;
+ }
+ if (!$stmt->expr instanceof Assign) {
+ continue;
+ }
+ $assign = $stmt->expr;
+ $propertyName = $this->matchAssignedLocalPropertyName($assign);
+ if (!\is_string($propertyName)) {
+ continue;
+ }
+ $defaultExpr = $assign->expr;
+ if ($this->exprAnalyzer->isDynamicExpr($defaultExpr)) {
+ continue;
+ }
+ foreach ($node->stmts as $classStmt) {
+ if (!$classStmt instanceof Property) {
continue;
}
- $propertyProperty->default = $defaultPropertyExprAssign->getDefaultExpr();
- $hasChanged = \true;
- $this->removeNode($defaultPropertyExprAssign->getAssignExpression());
+ // readonly property cannot have default value
+ if ($classStmt->isReadonly()) {
+ continue;
+ }
+ foreach ($classStmt->props as $propertyProperty) {
+ if (!$this->isName($propertyProperty, $propertyName)) {
+ continue;
+ }
+ $propertyProperty->default = $defaultExpr;
+ // remove assign
+ unset($constructClassMethod->stmts[$key]);
+ $hasChanged = \true;
+ }
}
}
if (!$hasChanged) {
@@ -89,18 +119,19 @@ public function refactor(Node $node) : ?Node
}
return $node;
}
- /**
- * @return PropertyProperty[]
- */
- private function getNonReadonlyPropertyProperty(Class_ $class) : array
+ private function matchAssignedLocalPropertyName(Assign $assign) : ?string
{
- $propertyProperties = [];
- foreach ($class->getProperties() as $property) {
- if ($property->isReadonly()) {
- continue;
- }
- $propertyProperties = \array_merge($propertyProperties, $property->props);
+ if (!$assign->var instanceof PropertyFetch) {
+ return null;
+ }
+ $propertyFetch = $assign->var;
+ if (!$this->nodeNameResolver->isName($propertyFetch->var, 'this')) {
+ return null;
+ }
+ $propertyName = $this->nodeNameResolver->getName($propertyFetch->name);
+ if (!\is_string($propertyName)) {
+ return null;
}
- return $propertyProperties;
+ return $propertyName;
}
}
diff --git a/rules/CodeQuality/Rector/Foreach_/ForeachItemsAssignToEmptyArrayToAssignRector.php b/rules/CodeQuality/Rector/Foreach_/ForeachItemsAssignToEmptyArrayToAssignRector.php
index f9fbd1816be2..c7a357437fb4 100644
--- a/rules/CodeQuality/Rector/Foreach_/ForeachItemsAssignToEmptyArrayToAssignRector.php
+++ b/rules/CodeQuality/Rector/Foreach_/ForeachItemsAssignToEmptyArrayToAssignRector.php
@@ -5,22 +5,22 @@
use PhpParser\Node;
use PhpParser\Node\Expr;
+use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Foreach_;
-use PHPStan\Analyser\Scope;
+use PhpParser\NodeTraverser;
use Rector\CodeQuality\NodeAnalyzer\ForeachAnalyzer;
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
-use Rector\Core\Rector\AbstractScopeAwareRector;
-use Rector\NodeNestingScope\ValueObject\ControlStructure;
+use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\CodeQuality\Rector\Foreach_\ForeachItemsAssignToEmptyArrayToAssignRector\ForeachItemsAssignToEmptyArrayToAssignRectorTest
*/
-final class ForeachItemsAssignToEmptyArrayToAssignRector extends AbstractScopeAwareRector
+final class ForeachItemsAssignToEmptyArrayToAssignRector extends AbstractRector
{
/**
* @readonly
@@ -69,7 +69,7 @@ public function getNodeTypes() : array
/**
* @param StmtsAwareInterface $node
*/
- public function refactorWithScope(Node $node, Scope $scope) : ?Node
+ public function refactor(Node $node) : ?Node
{
if ($node->stmts === null) {
return null;
@@ -81,6 +81,9 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
$emptyArrayVariables[] = $variableName;
}
if (!$stmt instanceof Foreach_) {
+ if ($this->isAppend($stmt, $emptyArrayVariables)) {
+ return null;
+ }
continue;
}
if ($this->shouldSkip($stmt, $emptyArrayVariables)) {
@@ -96,6 +99,23 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
}
return null;
}
+ /**
+ * @param string[] $emptyArrayVariables
+ */
+ private function isAppend(Stmt $stmt, array $emptyArrayVariables) : bool
+ {
+ $isAppend = \false;
+ $this->traverseNodesWithCallable($stmt, function (Node $subNode) use($emptyArrayVariables, &$isAppend) : ?int {
+ if ($subNode instanceof Assign && $subNode->var instanceof ArrayDimFetch) {
+ $isAppend = $this->isNames($subNode->var->var, $emptyArrayVariables);
+ if ($isAppend) {
+ return NodeTraverser::STOP_TRAVERSAL;
+ }
+ }
+ return null;
+ });
+ return $isAppend;
+ }
/**
* @param string[] $emptyArrayVariables
*/
@@ -110,16 +130,8 @@ private function shouldSkip(Foreach_ $foreach, array $emptyArrayVariables) : boo
if (!$foreachedExprType->isArray()->yes()) {
return \true;
}
- if ($this->shouldSkipAsPartOfOtherLoop($foreach)) {
- return \true;
- }
return !$this->isNames($assignVariableExpr, $emptyArrayVariables);
}
- private function shouldSkipAsPartOfOtherLoop(Foreach_ $foreach) : bool
- {
- $foreachParent = $this->betterNodeFinder->findParentByTypes($foreach, ControlStructure::LOOP_NODES);
- return $foreachParent instanceof Node;
- }
private function matchEmptyArrayVariableAssign(Stmt $stmt) : ?string
{
if (!$stmt instanceof Expression) {
diff --git a/rules/CodeQuality/Rector/FuncCall/ArrayKeysAndInArrayToArrayKeyExistsRector.php b/rules/CodeQuality/Rector/FuncCall/ArrayKeysAndInArrayToArrayKeyExistsRector.php
deleted file mode 100644
index bc3bef830a10..000000000000
--- a/rules/CodeQuality/Rector/FuncCall/ArrayKeysAndInArrayToArrayKeyExistsRector.php
+++ /dev/null
@@ -1,113 +0,0 @@
->
- */
- public function getNodeTypes() : array
- {
- return [FuncCall::class];
- }
- /**
- * @param FuncCall $node
- */
- public function refactor(Node $node) : ?Node
- {
- if (!$this->nodeNameResolver->isName($node, 'in_array')) {
- return null;
- }
- if ($node->isFirstClassCallable()) {
- return null;
- }
- $args = $node->getArgs();
- $secondArg = $args[1];
- $arrayVariable = $secondArg->value;
- $previousAssignArraysKeysFuncCall = $this->findPreviousAssignToArrayKeys($node, $arrayVariable);
- if ($previousAssignArraysKeysFuncCall instanceof Assign) {
- /** @var FuncCall $arrayKeysFuncCall */
- $arrayKeysFuncCall = $previousAssignArraysKeysFuncCall->expr;
- $this->removeNode($previousAssignArraysKeysFuncCall);
- return $this->createArrayKeyExists($node, $arrayKeysFuncCall);
- }
- if ($arrayVariable instanceof FuncCall && $this->isName($arrayVariable, 'array_keys')) {
- $arrayKeysFuncCallArgs = $arrayVariable->getArgs();
- if (\count($arrayKeysFuncCallArgs) > 1) {
- return null;
- }
- // unwrap array func call
- $secondArg->value = $arrayKeysFuncCallArgs[0]->value;
- $node->name = new Name('array_key_exists');
- unset($node->args[2]);
- return $node;
- }
- return null;
- }
- private function createArrayKeyExists(FuncCall $inArrayFuncCall, FuncCall $arrayKeysFuncCall) : ?FuncCall
- {
- if (!isset($inArrayFuncCall->getArgs()[0])) {
- return null;
- }
- if (!isset($arrayKeysFuncCall->getArgs()[0])) {
- return null;
- }
- $arguments = [$inArrayFuncCall->getArgs()[0], $arrayKeysFuncCall->getArgs()[0]];
- return new FuncCall(new Name('array_key_exists'), $arguments);
- }
- /**
- * @return null|\PhpParser\Node|\PhpParser\Node\FunctionLike
- */
- private function findPreviousAssignToArrayKeys(FuncCall $funcCall, Expr $expr)
- {
- return $this->betterNodeFinder->findFirstPrevious($funcCall, function (Node $node) use($expr) : bool {
- // breaking out of scope
- if ($node instanceof FunctionLike) {
- return \true;
- }
- if (!$node instanceof Assign) {
- return !(bool) $this->betterNodeFinder->findFirst($node, function (Node $subNode) use($expr) : bool {
- return $this->nodeComparator->areNodesEqual($expr, $subNode);
- });
- }
- if (!$this->nodeComparator->areNodesEqual($expr, $node->var)) {
- return \false;
- }
- if (!$node->expr instanceof FuncCall) {
- return \false;
- }
- return $this->nodeNameResolver->isName($node->expr, 'array_keys');
- });
- }
-}
diff --git a/rules/CodeQuality/Rector/FuncCall/BoolvalToTypeCastRector.php b/rules/CodeQuality/Rector/FuncCall/BoolvalToTypeCastRector.php
index cdc4948ab82b..452f90452c41 100644
--- a/rules/CodeQuality/Rector/FuncCall/BoolvalToTypeCastRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/BoolvalToTypeCastRector.php
@@ -48,6 +48,9 @@ public function getNodeTypes() : array
*/
public function refactor(Node $node) : ?Node
{
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (!$this->isName($node, 'boolval')) {
return null;
}
diff --git a/rules/CodeQuality/Rector/FuncCall/CallUserFuncWithArrowFunctionToInlineRector.php b/rules/CodeQuality/Rector/FuncCall/CallUserFuncWithArrowFunctionToInlineRector.php
index b5f4c73acb57..e3bee3c59092 100644
--- a/rules/CodeQuality/Rector/FuncCall/CallUserFuncWithArrowFunctionToInlineRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/CallUserFuncWithArrowFunctionToInlineRector.php
@@ -62,6 +62,9 @@ public function getNodeTypes() : array
*/
public function refactor(Node $node) : ?Node
{
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (!$this->isName($node, 'call_user_func')) {
return null;
}
diff --git a/rules/CodeQuality/Rector/FuncCall/FloatvalToTypeCastRector.php b/rules/CodeQuality/Rector/FuncCall/FloatvalToTypeCastRector.php
index eafd834e5bc8..88d05cc5a8bd 100644
--- a/rules/CodeQuality/Rector/FuncCall/FloatvalToTypeCastRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/FloatvalToTypeCastRector.php
@@ -62,9 +62,9 @@ public function refactor(Node $node) : ?Node
if (!\in_array($methodName, self::VAL_FUNCTION_NAMES, \true)) {
return null;
}
- // if (! isset($node->getArgs[0])) {
- // return null;
- // }
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
$firstArg = $node->getArgs()[0];
$double = new Double($firstArg->value);
$double->setAttribute(AttributeKey::KIND, Double::KIND_FLOAT);
diff --git a/rules/CodeQuality/Rector/FuncCall/IntvalToTypeCastRector.php b/rules/CodeQuality/Rector/FuncCall/IntvalToTypeCastRector.php
index 83a47accd303..6204a6e46f25 100644
--- a/rules/CodeQuality/Rector/FuncCall/IntvalToTypeCastRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/IntvalToTypeCastRector.php
@@ -61,6 +61,9 @@ public function refactor(Node $node) : ?Node
return null;
}
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($node->getArgs()[0])) {
return null;
}
diff --git a/rules/CodeQuality/Rector/FuncCall/IsAWithStringWithThirdArgumentRector.php b/rules/CodeQuality/Rector/FuncCall/IsAWithStringWithThirdArgumentRector.php
index 93b7bd8f6acf..6f02b524f52e 100644
--- a/rules/CodeQuality/Rector/FuncCall/IsAWithStringWithThirdArgumentRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/IsAWithStringWithThirdArgumentRector.php
@@ -51,6 +51,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'is_a')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (isset($node->getArgs()[2])) {
return null;
}
diff --git a/rules/CodeQuality/Rector/FuncCall/RemoveSoleValueSprintfRector.php b/rules/CodeQuality/Rector/FuncCall/RemoveSoleValueSprintfRector.php
index faae1519df3d..6b57e7321390 100644
--- a/rules/CodeQuality/Rector/FuncCall/RemoveSoleValueSprintfRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/RemoveSoleValueSprintfRector.php
@@ -53,6 +53,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'sprintf')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (\count($node->getArgs()) !== 2) {
return null;
}
diff --git a/rules/CodeQuality/Rector/FuncCall/SetTypeToCastRector.php b/rules/CodeQuality/Rector/FuncCall/SetTypeToCastRector.php
index 68b79a6d5157..34050c65ebe3 100644
--- a/rules/CodeQuality/Rector/FuncCall/SetTypeToCastRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/SetTypeToCastRector.php
@@ -32,6 +32,10 @@ final class SetTypeToCastRector extends AbstractRector
* @var array>
*/
private const TYPE_TO_CAST = ['array' => Array_::class, 'bool' => Bool_::class, 'boolean' => Bool_::class, 'double' => Double::class, 'float' => Double::class, 'int' => Int_::class, 'integer' => Int_::class, 'object' => Object_::class, 'string' => String_::class];
+ /**
+ * @var string
+ */
+ private const IS_ARG_VALUE_ITEM_SET_TYPE = 'is_arg_value_item_set_type';
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Changes settype() to (type) where possible', [new CodeSample(<<<'CODE_SAMPLE'
@@ -72,7 +76,7 @@ public function refactor(Node $node)
{
if ($node instanceof Arg || $node instanceof ArrayItem) {
if ($this->isSetTypeFuncCall($node->value)) {
- return NodeTraverser::STOP_TRAVERSAL;
+ $node->value->setAttribute(self::IS_ARG_VALUE_ITEM_SET_TYPE, \true);
}
return null;
}
@@ -101,6 +105,9 @@ private function refactorFuncCall(FuncCall $funcCall, bool $isStandaloneExpressi
if ($funcCall->isFirstClassCallable()) {
return null;
}
+ if ($funcCall->getAttribute(self::IS_ARG_VALUE_ITEM_SET_TYPE) === \true) {
+ return null;
+ }
$typeValue = $this->valueResolver->getValue($funcCall->getArgs()[1]->value);
if (!\is_string($typeValue)) {
return null;
diff --git a/rules/CodeQuality/Rector/FuncCall/SimplifyFuncGetArgsCountRector.php b/rules/CodeQuality/Rector/FuncCall/SimplifyFuncGetArgsCountRector.php
index 0b82b9b7d00a..22b559554b90 100644
--- a/rules/CodeQuality/Rector/FuncCall/SimplifyFuncGetArgsCountRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/SimplifyFuncGetArgsCountRector.php
@@ -32,6 +32,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'count')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
$firstArg = $node->getArgs()[0];
if (!$firstArg->value instanceof FuncCall) {
return null;
diff --git a/rules/CodeQuality/Rector/FuncCall/SimplifyInArrayValuesRector.php b/rules/CodeQuality/Rector/FuncCall/SimplifyInArrayValuesRector.php
index 1c7109a3af19..4e1c230f2a9a 100644
--- a/rules/CodeQuality/Rector/FuncCall/SimplifyInArrayValuesRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/SimplifyInArrayValuesRector.php
@@ -33,6 +33,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'in_array')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($node->args[1])) {
return null;
}
diff --git a/rules/CodeQuality/Rector/FuncCall/SimplifyRegexPatternRector.php b/rules/CodeQuality/Rector/FuncCall/SimplifyRegexPatternRector.php
index 9366d900d0c0..62efe3ba7871 100644
--- a/rules/CodeQuality/Rector/FuncCall/SimplifyRegexPatternRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/SimplifyRegexPatternRector.php
@@ -5,10 +5,9 @@
use RectorPrefix202306\Nette\Utils\Strings;
use PhpParser\Node;
-use PhpParser\Node\Expr\FuncCall;
-use PhpParser\Node\Expr\StaticCall;
-use Rector\Core\Php\Regex\RegexPatternArgumentManipulator;
+use PhpParser\Node\Scalar\String_;
use Rector\Core\Rector\AbstractRector;
+use Rector\NodeNameResolver\Regex\RegexPatternDetector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
@@ -19,17 +18,17 @@
final class SimplifyRegexPatternRector extends AbstractRector
{
/**
- * @var array
+ * @readonly
+ * @var \Rector\NodeNameResolver\Regex\RegexPatternDetector
*/
- private const COMPLEX_PATTERN_TO_SIMPLE = ['[0-9]' => '\\d', '[a-zA-Z0-9_]' => '\\w', '[A-Za-z0-9_]' => '\\w', '[0-9a-zA-Z_]' => '\\w', '[0-9A-Za-z_]' => '\\w', '[\\r\\n\\t\\f\\v ]' => '\\s'];
+ private $regexPatternDetector;
/**
- * @readonly
- * @var \Rector\Core\Php\Regex\RegexPatternArgumentManipulator
+ * @var array
*/
- private $regexPatternArgumentManipulator;
- public function __construct(RegexPatternArgumentManipulator $regexPatternArgumentManipulator)
+ private const COMPLEX_PATTERN_TO_SIMPLE = ['[0-9]' => '\\d', '[a-zA-Z0-9_]' => '\\w', '[A-Za-z0-9_]' => '\\w', '[0-9a-zA-Z_]' => '\\w', '[0-9A-Za-z_]' => '\\w', '[\\r\\n\\t\\f\\v ]' => '\\s'];
+ public function __construct(RegexPatternDetector $regexPatternDetector)
{
- $this->regexPatternArgumentManipulator = $regexPatternArgumentManipulator;
+ $this->regexPatternDetector = $regexPatternDetector;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -58,30 +57,23 @@ public function run($value)
*/
public function getNodeTypes() : array
{
- return [FuncCall::class, StaticCall::class];
+ return [String_::class];
}
/**
- * @param FuncCall|StaticCall $node
+ * @param String_ $node
*/
public function refactor(Node $node) : ?Node
{
- $patterns = $this->regexPatternArgumentManipulator->matchCallArgumentWithRegexPattern($node);
- if ($patterns === []) {
+ if (!$this->regexPatternDetector->isRegexPattern($node->value)) {
return null;
}
- $hasChanged = \false;
- foreach ($patterns as $pattern) {
- foreach (self::COMPLEX_PATTERN_TO_SIMPLE as $complexPattern => $simple) {
- $originalValue = $pattern->value;
- $simplifiedValue = Strings::replace($pattern->value, '#' . \preg_quote($complexPattern, '#') . '#', $simple);
- if ($originalValue === $simplifiedValue) {
- continue;
- }
- $pattern->value = $simplifiedValue;
- $hasChanged = \true;
+ foreach (self::COMPLEX_PATTERN_TO_SIMPLE as $complexPattern => $simple) {
+ $originalValue = $node->value;
+ $simplifiedValue = Strings::replace($node->value, '#' . \preg_quote($complexPattern, '#') . '#', $simple);
+ if ($originalValue === $simplifiedValue) {
+ continue;
}
- }
- if ($hasChanged) {
+ $node->value = $simplifiedValue;
return $node;
}
return null;
diff --git a/rules/CodeQuality/Rector/FuncCall/SimplifyStrposLowerRector.php b/rules/CodeQuality/Rector/FuncCall/SimplifyStrposLowerRector.php
index 3902a69c4339..5b43733397b5 100644
--- a/rules/CodeQuality/Rector/FuncCall/SimplifyStrposLowerRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/SimplifyStrposLowerRector.php
@@ -33,6 +33,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'strpos')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($node->getArgs()[0])) {
return null;
}
diff --git a/rules/CodeQuality/Rector/FuncCall/SingleInArrayToCompareRector.php b/rules/CodeQuality/Rector/FuncCall/SingleInArrayToCompareRector.php
index 875e4baaa547..a81bf73b848e 100644
--- a/rules/CodeQuality/Rector/FuncCall/SingleInArrayToCompareRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/SingleInArrayToCompareRector.php
@@ -59,6 +59,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'in_array')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($node->args[1])) {
return null;
}
diff --git a/rules/CodeQuality/Rector/FuncCall/StrvalToTypeCastRector.php b/rules/CodeQuality/Rector/FuncCall/StrvalToTypeCastRector.php
index 3527cb9c797c..645219d57cf8 100644
--- a/rules/CodeQuality/Rector/FuncCall/StrvalToTypeCastRector.php
+++ b/rules/CodeQuality/Rector/FuncCall/StrvalToTypeCastRector.php
@@ -51,6 +51,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'strval')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($node->getArgs()[0])) {
return null;
}
diff --git a/rules/CodeQuality/Rector/FunctionLike/RemoveAlwaysTrueConditionSetInConstructorRector.php b/rules/CodeQuality/Rector/FunctionLike/RemoveAlwaysTrueConditionSetInConstructorRector.php
deleted file mode 100644
index 6fd68c718275..000000000000
--- a/rules/CodeQuality/Rector/FunctionLike/RemoveAlwaysTrueConditionSetInConstructorRector.php
+++ /dev/null
@@ -1,210 +0,0 @@
-staticTypeAnalyzer = $staticTypeAnalyzer;
- $this->typeFactory = $typeFactory;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('If conditions is always true, perform the content right away', [new CodeSample(<<<'CODE_SAMPLE'
-final class SomeClass
-{
- private $value;
-
- public function __construct(stdClass $value)
- {
- $this->value = $value;
- }
-
- public function go()
- {
- if ($this->value) {
- return 'yes';
- }
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-final class SomeClass
-{
- private $value;
-
- public function __construct(stdClass $value)
- {
- $this->value = $value;
- }
-
- public function go()
- {
- return 'yes';
- }
-}
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [If_::class];
- }
- /**
- * @param If_ $node
- * @return null|If_|Stmt[]
- */
- public function refactor(Node $node)
- {
- $ifStmt = $this->matchTruableIf($node);
- if (!$ifStmt instanceof If_) {
- return null;
- }
- if ($ifStmt->stmts === []) {
- $this->removeNode($ifStmt);
- return $ifStmt;
- }
- return $ifStmt->stmts;
- }
- private function matchTruableIf(If_ $if) : ?\PhpParser\Node\Stmt\If_
- {
- // just one if
- if ($if->elseifs !== []) {
- return null;
- }
- // there is some else
- if ($if->else instanceof Else_) {
- return null;
- }
- // only property fetch, because of constructor set
- if (!$if->cond instanceof PropertyFetch) {
- return null;
- }
- $propertyFetchType = $this->resolvePropertyFetchType($if->cond);
- if (!$this->staticTypeAnalyzer->isAlwaysTruableType($propertyFetchType)) {
- return null;
- }
- return $if;
- }
- private function resolvePropertyFetchType(PropertyFetch $propertyFetch) : Type
- {
- $classLike = $this->betterNodeFinder->findParentType($propertyFetch, Class_::class);
- if (!$classLike instanceof Class_) {
- return new MixedType();
- }
- $propertyName = $this->getName($propertyFetch);
- if ($propertyName === null) {
- return new MixedType();
- }
- $property = $classLike->getProperty($propertyName);
- if (!$property instanceof Property) {
- return new MixedType();
- }
- // anything but private can be changed from outer scope
- if (!$property->isPrivate()) {
- return new MixedType();
- }
- // set in constructor + changed in class
- $propertyType = $this->resolvePropertyTypeAfterConstructor($classLike, $propertyName);
- $resolvedTypes = [$propertyType];
- $defaultValue = $property->props[0]->default;
- if ($defaultValue instanceof Expr) {
- $resolvedTypes[] = $this->getType($defaultValue);
- }
- $resolveAssignedType = $this->resolveAssignedTypeInStmtsByPropertyName($classLike->stmts, $propertyName);
- if ($resolveAssignedType instanceof Type) {
- $resolvedTypes[] = $resolveAssignedType;
- }
- return $this->typeFactory->createMixedPassedOrUnionTypeAndKeepConstant($resolvedTypes);
- }
- private function resolvePropertyTypeAfterConstructor(Class_ $class, string $propertyName) : Type
- {
- $propertyTypeFromConstructor = null;
- $constructClassMethod = $class->getMethod(MethodName::CONSTRUCT);
- if ($constructClassMethod instanceof ClassMethod) {
- $propertyTypeFromConstructor = $this->resolveAssignedTypeInStmtsByPropertyName((array) $constructClassMethod->stmts, $propertyName);
- }
- if ($propertyTypeFromConstructor instanceof Type) {
- return $propertyTypeFromConstructor;
- }
- // undefined property is null by default
- return new NullType();
- }
- /**
- * @param Stmt[] $stmts
- */
- private function resolveAssignedTypeInStmtsByPropertyName(array $stmts, string $propertyName) : ?Type
- {
- $resolvedTypes = [];
- $this->traverseNodesWithCallable($stmts, function (Node $node) use($propertyName, &$resolvedTypes) : ?int {
- if ($node instanceof ClassMethod && $this->isName($node, MethodName::CONSTRUCT)) {
- return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
- }
- if (!$this->isPropertyFetchAssignOfPropertyName($node, $propertyName)) {
- return null;
- }
- if (!$node instanceof Assign) {
- return null;
- }
- $resolvedTypes[] = $this->getType($node->expr);
- return null;
- });
- if ($resolvedTypes === []) {
- return null;
- }
- return $this->typeFactory->createMixedPassedOrUnionTypeAndKeepConstant($resolvedTypes);
- }
- /**
- * E.g. $this->{value} = x
- */
- private function isPropertyFetchAssignOfPropertyName(Node $node, string $propertyName) : bool
- {
- if (!$node instanceof Assign) {
- return \false;
- }
- if (!$node->var instanceof PropertyFetch) {
- return \false;
- }
- return $this->isName($node->var, $propertyName);
- }
-}
diff --git a/rules/CodeQuality/Rector/Identical/GetClassToInstanceOfRector.php b/rules/CodeQuality/Rector/Identical/GetClassToInstanceOfRector.php
index 3fb3547085e3..de4aaf62c12a 100644
--- a/rules/CodeQuality/Rector/Identical/GetClassToInstanceOfRector.php
+++ b/rules/CodeQuality/Rector/Identical/GetClassToInstanceOfRector.php
@@ -24,15 +24,15 @@
*/
final class GetClassToInstanceOfRector extends AbstractRector
{
- /**
- * @var string[]
- */
- private const NO_NAMESPACED_CLASSNAMES = ['self', 'static'];
/**
* @readonly
* @var \Rector\Core\NodeManipulator\BinaryOpManipulator
*/
private $binaryOpManipulator;
+ /**
+ * @var string[]
+ */
+ private const NO_NAMESPACED_CLASSNAMES = ['self', 'static'];
public function __construct(BinaryOpManipulator $binaryOpManipulator)
{
$this->binaryOpManipulator = $binaryOpManipulator;
@@ -65,6 +65,9 @@ public function refactor(Node $node) : ?Node
$firstExpr = $twoNodeMatch->getFirstExpr();
/** @var FuncCall $secondExpr */
$secondExpr = $twoNodeMatch->getSecondExpr();
+ if ($secondExpr->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($secondExpr->getArgs()[0])) {
return null;
}
diff --git a/rules/CodeQuality/Rector/If_/ConsecutiveNullCompareReturnsToNullCoalesceQueueRector.php b/rules/CodeQuality/Rector/If_/ConsecutiveNullCompareReturnsToNullCoalesceQueueRector.php
index 2d4ecb997fd8..74d6ef8ecd5f 100644
--- a/rules/CodeQuality/Rector/If_/ConsecutiveNullCompareReturnsToNullCoalesceQueueRector.php
+++ b/rules/CodeQuality/Rector/If_/ConsecutiveNullCompareReturnsToNullCoalesceQueueRector.php
@@ -6,9 +6,11 @@
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\BinaryOp\Coalesce;
+use PhpParser\Node\Expr\Throw_ as ExprThrow_;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Return_;
+use PhpParser\Node\Stmt\Throw_;
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
use Rector\Core\NodeManipulator\IfManipulator;
use Rector\Core\Rector\AbstractRector;
@@ -85,6 +87,9 @@ public function refactor(Node $node) : ?Node
if (!$comparedExpr instanceof Expr) {
continue;
}
+ if (!isset($node->stmts[$key + 1])) {
+ return null;
+ }
$coalescingExprs[] = $comparedExpr;
$ifKeys[] = $key;
}
@@ -93,17 +98,35 @@ public function refactor(Node $node) : ?Node
return null;
}
// remove last return null
+ $appendExpr = null;
+ $hasChanged = \false;
+ $originalStmts = $node->stmts;
foreach ($node->stmts as $key => $stmt) {
if (\in_array($key, $ifKeys, \true)) {
unset($node->stmts[$key]);
+ $hasChanged = \true;
continue;
}
- if (!$this->isReturnNull($stmt)) {
+ if (!$hasChanged) {
+ continue;
+ }
+ if ($stmt instanceof Throw_) {
+ unset($node->stmts[$key]);
+ $appendExpr = new ExprThrow_($stmt->expr);
continue;
}
+ if (!$this->isReturnNull($stmt)) {
+ if ($stmt instanceof Return_ && $stmt->expr instanceof Expr) {
+ unset($node->stmts[$key]);
+ $appendExpr = $stmt->expr;
+ continue;
+ }
+ $node->stmts = $originalStmts;
+ return $node;
+ }
unset($node->stmts[$key]);
}
- $node->stmts[] = $this->createCealesceReturn($coalescingExprs);
+ $node->stmts[] = $this->createCealesceReturn($coalescingExprs, $appendExpr);
return $node;
}
public function provideMinPhpVersion() : int
@@ -123,7 +146,7 @@ private function isReturnNull(Stmt $stmt) : bool
/**
* @param Expr[] $coalescingExprs
*/
- private function createCealesceReturn(array $coalescingExprs) : Return_
+ private function createCealesceReturn(array $coalescingExprs, ?Expr $appendExpr) : Return_
{
/** @var Expr $leftExpr */
$leftExpr = \array_shift($coalescingExprs);
@@ -133,6 +156,9 @@ private function createCealesceReturn(array $coalescingExprs) : Return_
foreach ($coalescingExprs as $coalescingExpr) {
$coalesce = new Coalesce($coalesce, $coalescingExpr);
}
+ if ($appendExpr instanceof Expr) {
+ return new Return_(new Coalesce($coalesce, $appendExpr));
+ }
return new Return_($coalesce);
}
}
diff --git a/rules/CodeQuality/Rector/If_/ExplicitBoolCompareRector.php b/rules/CodeQuality/Rector/If_/ExplicitBoolCompareRector.php
index 37fb0c081a6e..7486a5548f3e 100644
--- a/rules/CodeQuality/Rector/If_/ExplicitBoolCompareRector.php
+++ b/rules/CodeQuality/Rector/If_/ExplicitBoolCompareRector.php
@@ -142,6 +142,9 @@ private function resolveNewConditionNode(Expr $expr, bool $isNegated) : ?BinaryO
*/
private function resolveCount(bool $isNegated, FuncCall $funcCall)
{
+ if ($funcCall->isFirstClassCallable()) {
+ return null;
+ }
$countedType = $this->getType($funcCall->getArgs()[0]->value);
if ($countedType->isArray()->yes()) {
return null;
diff --git a/rules/CodeQuality/Rector/If_/SimplifyIfElseToTernaryRector.php b/rules/CodeQuality/Rector/If_/SimplifyIfElseToTernaryRector.php
index 0c2fa5979644..bf229b4a6b24 100644
--- a/rules/CodeQuality/Rector/If_/SimplifyIfElseToTernaryRector.php
+++ b/rules/CodeQuality/Rector/If_/SimplifyIfElseToTernaryRector.php
@@ -12,7 +12,7 @@
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\If_;
-use Rector\Core\Contract\PhpParser\NodePrinterInterface;
+use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@@ -22,17 +22,17 @@
final class SimplifyIfElseToTernaryRector extends AbstractRector
{
/**
- * @var int
+ * @readonly
+ * @var \Rector\Core\PhpParser\Printer\BetterStandardPrinter
*/
- private const LINE_LENGTH_LIMIT = 120;
+ private $betterStandardPrinter;
/**
- * @readonly
- * @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
+ * @var int
*/
- private $nodePrinter;
- public function __construct(NodePrinterInterface $nodePrinter)
+ private const LINE_LENGTH_LIMIT = 120;
+ public function __construct(BetterStandardPrinter $betterStandardPrinter)
{
- $this->nodePrinter = $nodePrinter;
+ $this->betterStandardPrinter = $betterStandardPrinter;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -162,7 +162,7 @@ private function haveNestedTernary(array $nodes) : bool
}
private function isNodeTooLong(Assign $assign) : bool
{
- $assignContent = $this->nodePrinter->print($assign);
+ $assignContent = $this->betterStandardPrinter->print($assign);
return Strings::length($assignContent) > self::LINE_LENGTH_LIMIT;
}
}
diff --git a/rules/CodeQuality/Rector/If_/SimplifyIfReturnBoolRector.php b/rules/CodeQuality/Rector/If_/SimplifyIfReturnBoolRector.php
index 73aeb562e37c..ed96f67f64cc 100644
--- a/rules/CodeQuality/Rector/If_/SimplifyIfReturnBoolRector.php
+++ b/rules/CodeQuality/Rector/If_/SimplifyIfReturnBoolRector.php
@@ -14,7 +14,7 @@
use Rector\BetterPhpDocParser\Comment\CommentsMerger;
use Rector\CodeQuality\NodeManipulator\ExprBoolCaster;
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
-use Rector\Core\Contract\PhpParser\NodePrinterInterface;
+use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@@ -35,14 +35,14 @@ final class SimplifyIfReturnBoolRector extends AbstractRector
private $exprBoolCaster;
/**
* @readonly
- * @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
+ * @var \Rector\Core\PhpParser\Printer\BetterStandardPrinter
*/
- private $nodePrinter;
- public function __construct(CommentsMerger $commentsMerger, ExprBoolCaster $exprBoolCaster, NodePrinterInterface $nodePrinter)
+ private $betterStandardPrinter;
+ public function __construct(CommentsMerger $commentsMerger, ExprBoolCaster $exprBoolCaster, BetterStandardPrinter $betterStandardPrinter)
{
$this->commentsMerger = $commentsMerger;
$this->exprBoolCaster = $exprBoolCaster;
- $this->nodePrinter = $nodePrinter;
+ $this->betterStandardPrinter = $betterStandardPrinter;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -129,7 +129,7 @@ private function shouldSkipIfAndReturn(If_ $if, Return_ $return) : bool
if (!$this->valueResolver->isFalse($returnedExpr)) {
return !$this->valueResolver->isTrueOrFalse($return->expr);
}
- $condString = $this->nodePrinter->print($if->cond);
+ $condString = $this->betterStandardPrinter->print($if->cond);
if (\strpos($condString, '!=') === \false) {
return !$this->valueResolver->isTrueOrFalse($return->expr);
}
diff --git a/rules/CodeQuality/Rector/New_/NewStaticToNewSelfRector.php b/rules/CodeQuality/Rector/New_/NewStaticToNewSelfRector.php
index c5009d34eab1..a931d4641a76 100644
--- a/rules/CodeQuality/Rector/New_/NewStaticToNewSelfRector.php
+++ b/rules/CodeQuality/Rector/New_/NewStaticToNewSelfRector.php
@@ -21,7 +21,7 @@ final class NewStaticToNewSelfRector extends AbstractRector
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Change unsafe new static() to new self()', [new CodeSample(<<<'CODE_SAMPLE'
-class SomeClass
+final class SomeClass
{
public function build()
{
@@ -30,7 +30,7 @@ public function build()
}
CODE_SAMPLE
, <<<'CODE_SAMPLE'
-class SomeClass
+final class SomeClass
{
public function build()
{
@@ -45,24 +45,31 @@ public function build()
*/
public function getNodeTypes() : array
{
- return [New_::class];
+ return [Class_::class];
}
/**
- * @param New_ $node
+ * @param Class_ $node
*/
public function refactor(Node $node) : ?Node
{
- $class = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$class instanceof Class_) {
+ if (!$node->isFinal()) {
return null;
}
- if (!$class->isFinal()) {
- return null;
- }
- if (!$this->isName($node->class, ObjectReference::STATIC)) {
- return null;
+ $hasChanged = \false;
+ $this->traverseNodesWithCallable($node, function (Node $node) use(&$hasChanged) : ?New_ {
+ if (!$node instanceof New_) {
+ return null;
+ }
+ if (!$this->isName($node->class, ObjectReference::STATIC)) {
+ return null;
+ }
+ $hasChanged = \true;
+ $node->class = new Name(ObjectReference::SELF);
+ return $node;
+ });
+ if ($hasChanged) {
+ return $node;
}
- $node->class = new Name(ObjectReference::SELF);
- return $node;
+ return null;
}
}
diff --git a/rules/CodeQuality/ValueObject/DefaultPropertyExprAssign.php b/rules/CodeQuality/ValueObject/DefaultPropertyExprAssign.php
deleted file mode 100644
index ac54352f84a4..000000000000
--- a/rules/CodeQuality/ValueObject/DefaultPropertyExprAssign.php
+++ /dev/null
@@ -1,43 +0,0 @@
-assignExpression = $assignExpression;
- $this->propertyName = $propertyName;
- $this->defaultExpr = $defaultExpr;
- }
- public function getAssignExpression() : Expression
- {
- return $this->assignExpression;
- }
- public function getPropertyName() : string
- {
- return $this->propertyName;
- }
- public function getDefaultExpr() : Expr
- {
- return $this->defaultExpr;
- }
-}
diff --git a/rules/CodingStyle/Application/UseImportsAdder.php b/rules/CodingStyle/Application/UseImportsAdder.php
index 920db6f5b2bb..a0013e4cdda5 100644
--- a/rules/CodingStyle/Application/UseImportsAdder.php
+++ b/rules/CodingStyle/Application/UseImportsAdder.php
@@ -12,6 +12,7 @@
use PhpParser\Node\Stmt\Use_;
use PHPStan\Type\ObjectType;
use Rector\CodingStyle\ClassNameImport\UsedImportsResolver;
+use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType;
@@ -39,7 +40,7 @@ public function __construct(UsedImportsResolver $usedImportsResolver, TypeFactor
* @param array $functionUseImportTypes
* @return Stmt[]
*/
- public function addImportsToStmts(array $stmts, array $useImportTypes, array $functionUseImportTypes) : array
+ public function addImportsToStmts(FileWithoutNamespace $fileWithoutNamespace, array $stmts, array $useImportTypes, array $functionUseImportTypes) : array
{
$existingUseImportTypes = $this->usedImportsResolver->resolveForStmts($stmts);
$existingFunctionUseImports = $this->usedImportsResolver->resolveFunctionImportsForStmts($stmts);
@@ -60,12 +61,16 @@ public function addImportsToStmts(array $stmts, array $useImportTypes, array $fu
}
$this->mirrorUseComments($stmts, $newUses, $key + 1);
\array_splice($stmts, $key + 1, 0, $nodesToAdd);
- return $stmts;
+ $fileWithoutNamespace->stmts = $stmts;
+ $fileWithoutNamespace->stmts = \array_values($fileWithoutNamespace->stmts);
+ return $fileWithoutNamespace->stmts;
}
}
$this->mirrorUseComments($stmts, $newUses);
// make use stmts first
- return \array_merge($newUses, $stmts);
+ $fileWithoutNamespace->stmts = \array_merge($newUses, $stmts);
+ $fileWithoutNamespace->stmts = \array_values($fileWithoutNamespace->stmts);
+ return $fileWithoutNamespace->stmts;
}
/**
* @param FullyQualifiedObjectType[] $useImportTypes
@@ -85,6 +90,7 @@ public function addImportsToNamespace(Namespace_ $namespace, array $useImportTyp
}
$this->mirrorUseComments($namespace->stmts, $newUses);
$namespace->stmts = \array_merge($newUses, $namespace->stmts);
+ $namespace->stmts = \array_values($namespace->stmts);
}
/**
* @param Stmt[] $stmts
diff --git a/rules/CodingStyle/ClassNameImport/AliasUsesResolver.php b/rules/CodingStyle/ClassNameImport/AliasUsesResolver.php
index cd08e2a81a00..178e2f98ce33 100644
--- a/rules/CodingStyle/ClassNameImport/AliasUsesResolver.php
+++ b/rules/CodingStyle/ClassNameImport/AliasUsesResolver.php
@@ -8,7 +8,6 @@
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\UseUse;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
final class AliasUsesResolver
{
/**
@@ -16,28 +15,27 @@ final class AliasUsesResolver
* @var \Rector\CodingStyle\ClassNameImport\UseImportsTraverser
*/
private $useImportsTraverser;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- public function __construct(\Rector\CodingStyle\ClassNameImport\UseImportsTraverser $useImportsTraverser, BetterNodeFinder $betterNodeFinder)
+ public function __construct(\Rector\CodingStyle\ClassNameImport\UseImportsTraverser $useImportsTraverser)
{
$this->useImportsTraverser = $useImportsTraverser;
- $this->betterNodeFinder = $betterNodeFinder;
}
/**
+ * @param Stmt[] $stmts
* @return string[]
*/
- public function resolveFromNode(Node $node) : array
+ public function resolveFromNode(Node $node, array $stmts) : array
{
if (!$node instanceof Namespace_) {
- $node = $this->betterNodeFinder->findParentType($node, Namespace_::class);
- }
- if ($node instanceof Namespace_) {
- return $this->resolveFromStmts($node->stmts);
+ /** @var Namespace_[] $namespaces */
+ $namespaces = \array_filter($stmts, static function (Stmt $stmt) : bool {
+ return $stmt instanceof Namespace_;
+ });
+ if (\count($namespaces) !== 1) {
+ return [];
+ }
+ $node = \current($namespaces);
}
- return [];
+ return $this->resolveFromStmts($node->stmts);
}
/**
* @param Stmt[] $stmts
diff --git a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/AliasClassNameImportSkipVoter.php b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/AliasClassNameImportSkipVoter.php
index 180e28df7a85..00f5751cdac4 100644
--- a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/AliasClassNameImportSkipVoter.php
+++ b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/AliasClassNameImportSkipVoter.php
@@ -30,7 +30,7 @@ public function __construct(AliasUsesResolver $aliasUsesResolver)
}
public function shouldSkip(File $file, FullyQualifiedObjectType $fullyQualifiedObjectType, Node $node) : bool
{
- $aliasedUses = $this->aliasUsesResolver->resolveFromNode($node);
+ $aliasedUses = $this->aliasUsesResolver->resolveFromNode($node, $file->getNewStmts());
$shortNameLowered = $fullyQualifiedObjectType->getShortNameLowered();
foreach ($aliasedUses as $aliasedUse) {
$aliasedUseLowered = \strtolower($aliasedUse);
diff --git a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php
index ba112e7b54df..a1cb989e8670 100644
--- a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php
+++ b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipVoter/ClassLikeNameClassNameImportSkipVoter.php
@@ -30,7 +30,7 @@ public function __construct(ShortNameResolver $shortNameResolver)
}
public function shouldSkip(File $file, FullyQualifiedObjectType $fullyQualifiedObjectType, Node $node) : bool
{
- $classLikeNames = $this->shortNameResolver->resolveShortClassLikeNamesForNode($node);
+ $classLikeNames = $this->shortNameResolver->resolveShortClassLikeNames($file);
if ($classLikeNames === []) {
return \false;
}
diff --git a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipper.php b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipper.php
index e99e22527593..38f91736d68e 100644
--- a/rules/CodingStyle/ClassNameImport/ClassNameImportSkipper.php
+++ b/rules/CodingStyle/ClassNameImport/ClassNameImportSkipper.php
@@ -33,7 +33,7 @@ final class ClassNameImportSkipper
/**
* @param ClassNameImportSkipVoterInterface[] $classNameImportSkipVoters
*/
- public function __construct(array $classNameImportSkipVoters, RenamedClassesDataCollector $renamedClassesDataCollector, UseImportsResolver $useImportsResolver)
+ public function __construct(iterable $classNameImportSkipVoters, RenamedClassesDataCollector $renamedClassesDataCollector, UseImportsResolver $useImportsResolver)
{
$this->classNameImportSkipVoters = $classNameImportSkipVoters;
$this->renamedClassesDataCollector = $renamedClassesDataCollector;
diff --git a/rules/CodingStyle/ClassNameImport/ShortNameResolver.php b/rules/CodingStyle/ClassNameImport/ShortNameResolver.php
index 6aab7b0564ba..b8066a673ad5 100644
--- a/rules/CodingStyle/ClassNameImport/ShortNameResolver.php
+++ b/rules/CodingStyle/ClassNameImport/ShortNameResolver.php
@@ -31,19 +31,6 @@
*/
final class ShortNameResolver
{
- /**
- * @var string
- * @see https://regex101.com/r/KphLd2/1
- */
- private const BIG_LETTER_START_REGEX = '#^[A-Z]#';
- /**
- * @var array
- */
- private $shortNamesByFilePath = [];
- /**
- * @var \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory
- */
- private $phpDocInfoFactory;
/**
* @readonly
* @var \Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser
@@ -69,6 +56,19 @@ final class ShortNameResolver
* @var \Rector\CodingStyle\NodeAnalyzer\UseImportNameMatcher
*/
private $useImportNameMatcher;
+ /**
+ * @var string
+ * @see https://regex101.com/r/KphLd2/1
+ */
+ private const BIG_LETTER_START_REGEX = '#^[A-Z]#';
+ /**
+ * @var array
+ */
+ private $shortNamesByFilePath = [];
+ /**
+ * @var \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory
+ */
+ private $phpDocInfoFactory;
public function __construct(SimpleCallableNodeTraverser $simpleCallableNodeTraverser, NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider, BetterNodeFinder $betterNodeFinder, UseImportNameMatcher $useImportNameMatcher)
{
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
@@ -102,13 +102,18 @@ public function resolveFromFile(File $file) : array
* Collects all "class ", "trait " and "interface "
* @return string[]
*/
- public function resolveShortClassLikeNamesForNode(Node $node) : array
+ public function resolveShortClassLikeNames(File $file) : array
{
- $namespace = $this->betterNodeFinder->findParentType($node, Namespace_::class);
- if (!$namespace instanceof Namespace_) {
- // only handle namespace nodes
+ $newStmts = $file->getNewStmts();
+ /** @var Namespace_[] $namespaces */
+ $namespaces = \array_filter($newStmts, static function (Stmt $stmt) : bool {
+ return $stmt instanceof Namespace_;
+ });
+ if (\count($namespaces) !== 1) {
+ // only handle single namespace nodes
return [];
}
+ $namespace = \current($namespaces);
/** @var ClassLike[] $classLikes */
$classLikes = $this->betterNodeFinder->findInstanceOf($namespace, ClassLike::class);
$shortClassLikeNames = [];
diff --git a/rules/CodingStyle/ClassNameImport/UsedImportsResolver.php b/rules/CodingStyle/ClassNameImport/UsedImportsResolver.php
index 628ba28a5d29..d16f55fe11c8 100644
--- a/rules/CodingStyle/ClassNameImport/UsedImportsResolver.php
+++ b/rules/CodingStyle/ClassNameImport/UsedImportsResolver.php
@@ -10,6 +10,8 @@
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\UseUse;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
+use Rector\Core\Provider\CurrentFileProvider;
+use Rector\Core\ValueObject\Application\File;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\StaticTypeMapper\ValueObject\Type\AliasedObjectType;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
@@ -30,18 +32,24 @@ final class UsedImportsResolver
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
- public function __construct(BetterNodeFinder $betterNodeFinder, \Rector\CodingStyle\ClassNameImport\UseImportsTraverser $useImportsTraverser, NodeNameResolver $nodeNameResolver)
+ /**
+ * @readonly
+ * @var \Rector\Core\Provider\CurrentFileProvider
+ */
+ private $currentFileProvider;
+ public function __construct(BetterNodeFinder $betterNodeFinder, \Rector\CodingStyle\ClassNameImport\UseImportsTraverser $useImportsTraverser, NodeNameResolver $nodeNameResolver, CurrentFileProvider $currentFileProvider)
{
$this->betterNodeFinder = $betterNodeFinder;
$this->useImportsTraverser = $useImportsTraverser;
$this->nodeNameResolver = $nodeNameResolver;
+ $this->currentFileProvider = $currentFileProvider;
}
/**
* @return array
*/
public function resolveForNode(Node $node) : array
{
- $namespace = $node instanceof Namespace_ ? $node : $this->betterNodeFinder->findParentType($node, Namespace_::class);
+ $namespace = $this->resolveCurrentNamespaceForNode($node);
if ($namespace instanceof Namespace_) {
return $this->resolveForNamespace($namespace);
}
@@ -83,6 +91,24 @@ public function resolveFunctionImportsForStmts(array $stmts) : array
});
return $usedFunctionImports;
}
+ private function resolveCurrentNamespaceForNode(Node $node) : ?Namespace_
+ {
+ if ($node instanceof Namespace_) {
+ return $node;
+ }
+ $file = $this->currentFileProvider->getFile();
+ if (!$file instanceof File) {
+ return null;
+ }
+ $stmts = $file->getNewStmts();
+ $namespaces = \array_filter($stmts, static function (Stmt $stmt) : bool {
+ return $stmt instanceof Namespace_;
+ });
+ if (\count($namespaces) !== 1) {
+ return null;
+ }
+ return \current($namespaces);
+ }
/**
* @return array
*/
diff --git a/rules/CodingStyle/Enum/PreferenceSelfThis.php b/rules/CodingStyle/Enum/PreferenceSelfThis.php
deleted file mode 100644
index 7a5dbe14f46a..000000000000
--- a/rules/CodingStyle/Enum/PreferenceSelfThis.php
+++ /dev/null
@@ -1,18 +0,0 @@
-aliasUsesResolver = $aliasUsesResolver;
$this->classNameImportSkipper = $classNameImportSkipper;
$this->parameterProvider = $parameterProvider;
$this->staticTypeMapper = $staticTypeMapper;
$this->useNodesToAddCollector = $useNodesToAddCollector;
- $this->reflectionProvider = $reflectionProvider;
}
/**
* @param Use_[]|GroupUse[] $uses
@@ -141,25 +129,18 @@ private function importNameAndCollectNewUseStatement(File $file, Name $name, Ful
*/
private function isNamespaceOrUseImportName(Name $name) : bool
{
- $parentNode = $name->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentNode instanceof Namespace_) {
+ if ($name->getAttribute(AttributeKey::IS_NAMESPACE_NAME) === \true) {
return \true;
}
- return $parentNode instanceof UseUse;
+ return $name->getAttribute(AttributeKey::IS_USEUSE_NAME) === \true;
}
private function isFunctionOrConstantImportWithSingleName(Name $name) : bool
{
- $parentNode = $name->getAttribute(AttributeKey::PARENT_NODE);
- $fullName = $name->toString();
- $autoImportNames = $this->parameterProvider->provideBoolParameter(Option::AUTO_IMPORT_NAMES);
- if ($autoImportNames && !$parentNode instanceof Node && \strpos($fullName, '\\') === \false && $this->reflectionProvider->hasFunction(new Name($fullName), null)) {
- return \true;
- }
- if ($parentNode instanceof ConstFetch) {
- return \count($name->parts) === 1;
+ if ($name->getAttribute(AttributeKey::IS_CONSTFETCH_NAME) === \true) {
+ return \count($name->getParts()) === 1;
}
- if ($parentNode instanceof FuncCall) {
- return \count($name->parts) === 1;
+ if ($name->getAttribute(AttributeKey::IS_FUNCCALL_NAME) === \true) {
+ return \count($name->getParts()) === 1;
}
return \false;
}
@@ -168,8 +149,7 @@ private function addUseImport(File $file, Name $name, FullyQualifiedObjectType $
if ($this->useNodesToAddCollector->hasImport($file, $name, $fullyQualifiedObjectType)) {
return;
}
- $parentNode = $name->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentNode instanceof FuncCall) {
+ if ($name->getAttribute(AttributeKey::IS_FUNCCALL_NAME) === \true) {
$this->useNodesToAddCollector->addFunctionUseImport($fullyQualifiedObjectType);
} else {
$this->useNodesToAddCollector->addUseImport($fullyQualifiedObjectType);
diff --git a/rules/CodingStyle/NodeAnalyzer/UseImportNameMatcher.php b/rules/CodingStyle/NodeAnalyzer/UseImportNameMatcher.php
index 30b6e4f08089..cc6ce03191c0 100644
--- a/rules/CodingStyle/NodeAnalyzer/UseImportNameMatcher.php
+++ b/rules/CodingStyle/NodeAnalyzer/UseImportNameMatcher.php
@@ -16,13 +16,6 @@
use Rector\NodeTypeResolver\Node\AttributeKey;
final class UseImportNameMatcher
{
- /**
- * @var string
- *
- * @see https://regex101.com/r/ZxFSlc/1 for last name, eg: Entity and UniqueEntity
- * @see https://regex101.com/r/OLO0Un/1 for inside namespace, eg: ORM for ORM\Id or ORM\Column
- */
- private const SHORT_NAME_REGEX = '#^%s(\\\\[\\w]+)?$#i';
/**
* @readonly
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
@@ -33,6 +26,13 @@ final class UseImportNameMatcher
* @var \Rector\Naming\Naming\UseImportsResolver
*/
private $useImportsResolver;
+ /**
+ * @var string
+ *
+ * @see https://regex101.com/r/ZxFSlc/1 for last name, eg: Entity and UniqueEntity
+ * @see https://regex101.com/r/OLO0Un/1 for inside namespace, eg: ORM for ORM\Id or ORM\Column
+ */
+ private const SHORT_NAME_REGEX = '#^%s(\\\\[\\w]+)?$#i';
public function __construct(BetterNodeFinder $betterNodeFinder, UseImportsResolver $useImportsResolver)
{
$this->betterNodeFinder = $betterNodeFinder;
diff --git a/rules/CodingStyle/Rector/Catch_/CatchExceptionNameMatchingTypeRector.php b/rules/CodingStyle/Rector/Catch_/CatchExceptionNameMatchingTypeRector.php
index 1e6be237fc68..c2cae1fa75d9 100644
--- a/rules/CodingStyle/Rector/Catch_/CatchExceptionNameMatchingTypeRector.php
+++ b/rules/CodingStyle/Rector/Catch_/CatchExceptionNameMatchingTypeRector.php
@@ -29,11 +29,6 @@
*/
final class CatchExceptionNameMatchingTypeRector extends AbstractRector
{
- /**
- * @var string
- * @see https://regex101.com/r/xmfMAX/1
- */
- private const STARTS_WITH_ABBREVIATION_REGEX = '#^([A-Za-z]+?)([A-Z]{1}[a-z]{1})([A-Za-z]*)#';
/**
* @readonly
* @var \Rector\Naming\Naming\PropertyNaming
@@ -44,6 +39,11 @@ final class CatchExceptionNameMatchingTypeRector extends AbstractRector
* @var \Rector\Naming\Naming\AliasNameResolver
*/
private $aliasNameResolver;
+ /**
+ * @var string
+ * @see https://regex101.com/r/xmfMAX/1
+ */
+ private const STARTS_WITH_ABBREVIATION_REGEX = '#^([A-Za-z]+?)([A-Z]{1}[a-z]{1})([A-Za-z]*)#';
public function __construct(PropertyNaming $propertyNaming, AliasNameResolver $aliasNameResolver)
{
$this->propertyNaming = $propertyNaming;
diff --git a/rules/CodingStyle/Rector/ClassConst/VarConstantCommentRector.php b/rules/CodingStyle/Rector/ClassConst/VarConstantCommentRector.php
deleted file mode 100644
index 4961e4a9a837..000000000000
--- a/rules/CodingStyle/Rector/ClassConst/VarConstantCommentRector.php
+++ /dev/null
@@ -1,148 +0,0 @@
-typeComparator = $typeComparator;
- $this->phpDocTypeChanger = $phpDocTypeChanger;
- $this->typeNormalizer = $typeNormalizer;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Constant should have a @var comment with type', [new CodeSample(<<<'CODE_SAMPLE'
-class SomeClass
-{
- const HI = 'hi';
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-class SomeClass
-{
- /**
- * @var string
- */
- const HI = 'hi';
-}
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [ClassConst::class];
- }
- /**
- * @param ClassConst $node
- */
- public function refactor(Node $node) : ?Node
- {
- if (\count($node->consts) > 1) {
- return null;
- }
- $constType = $this->getType($node->consts[0]->value);
- if ($constType instanceof MixedType) {
- return null;
- }
- // generalize false/true type to bool, as mostly default value but accepts both
- $constType = $this->typeNormalizer->generalizeConstantBoolTypes($constType);
- $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
- if ($this->shouldSkipConstantArrayType($constType, $phpDocInfo)) {
- return null;
- }
- if ($this->typeComparator->isSubtype($constType, $phpDocInfo->getVarType())) {
- return null;
- }
- $this->phpDocTypeChanger->changeVarType($phpDocInfo, $constType);
- if (!$phpDocInfo->hasChanged()) {
- return null;
- }
- return $node;
- }
- private function hasTwoAndMoreGenericClassStringTypes(ConstantArrayType $constantArrayType) : bool
- {
- $typeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($constantArrayType, TypeKind::RETURN);
- if (!$typeNode instanceof ArrayTypeNode) {
- return \false;
- }
- if (!$typeNode->type instanceof UnionTypeNode) {
- return \false;
- }
- $genericTypeNodeCount = 0;
- foreach ($typeNode->type->types as $unionedTypeNode) {
- if ($unionedTypeNode instanceof GenericTypeNode) {
- ++$genericTypeNodeCount;
- }
- }
- return $genericTypeNodeCount > 1;
- }
- /**
- * Skip big arrays and mixed[] constants
- */
- private function shouldSkipConstantArrayType(Type $constType, PhpDocInfo $phpDocInfo) : bool
- {
- if (!$constType instanceof ConstantArrayType) {
- return \false;
- }
- $currentVarType = $phpDocInfo->getVarType();
- if ($currentVarType instanceof ArrayType && $currentVarType->getItemType() instanceof MixedType) {
- return \true;
- }
- if ($this->hasTwoAndMoreGenericClassStringTypes($constType)) {
- return \true;
- }
- return $this->isHugeNestedConstantArrayTyp($constType);
- }
- private function isHugeNestedConstantArrayTyp(ConstantArrayType $constantArrayType) : bool
- {
- if (\count($constantArrayType->getValueTypes()) <= 3) {
- return \false;
- }
- foreach ($constantArrayType->getValueTypes() as $constValueType) {
- if ($constValueType instanceof ConstantArrayType) {
- return \true;
- }
- }
- return \false;
- }
-}
diff --git a/rules/CodingStyle/Rector/ClassMethod/UnSpreadOperatorRector.php b/rules/CodingStyle/Rector/ClassMethod/UnSpreadOperatorRector.php
index 18b18be7ada0..52734335c1f5 100644
--- a/rules/CodingStyle/Rector/ClassMethod/UnSpreadOperatorRector.php
+++ b/rules/CodingStyle/Rector/ClassMethod/UnSpreadOperatorRector.php
@@ -125,6 +125,9 @@ private function refactorClassMethod(ClassMethod $classMethod) : ?ClassMethod
}
private function refactorMethodCall(MethodCall $methodCall, Scope $scope) : ?MethodCall
{
+ if ($methodCall->isFirstClassCallable()) {
+ return null;
+ }
$methodReflection = $this->reflectionResolver->resolveMethodReflectionFromMethodCall($methodCall);
if (!$methodReflection instanceof MethodReflection) {
return null;
diff --git a/rules/CodingStyle/Rector/Class_/AddArrayDefaultToArrayPropertyRector.php b/rules/CodingStyle/Rector/Class_/AddArrayDefaultToArrayPropertyRector.php
index 71de26c257d3..a7ad0464be22 100644
--- a/rules/CodingStyle/Rector/Class_/AddArrayDefaultToArrayPropertyRector.php
+++ b/rules/CodingStyle/Rector/Class_/AddArrayDefaultToArrayPropertyRector.php
@@ -165,6 +165,9 @@ private function clearNotNullBeforeCount(Class_ $class, array $propertyNames) :
if (!$node instanceof FuncCall) {
return \false;
}
+ if ($node->isFirstClassCallable()) {
+ return \false;
+ }
if (!$this->isName($node, 'count')) {
return \false;
}
diff --git a/rules/CodingStyle/Rector/FuncCall/CallUserFuncToMethodCallRector.php b/rules/CodingStyle/Rector/FuncCall/CallUserFuncToMethodCallRector.php
index 145fffcf8d52..f1c1e9166353 100644
--- a/rules/CodingStyle/Rector/FuncCall/CallUserFuncToMethodCallRector.php
+++ b/rules/CodingStyle/Rector/FuncCall/CallUserFuncToMethodCallRector.php
@@ -64,6 +64,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'call_user_func')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($node->getArgs()[0])) {
return null;
}
diff --git a/rules/CodingStyle/Rector/FuncCall/ConsistentImplodeRector.php b/rules/CodingStyle/Rector/FuncCall/ConsistentImplodeRector.php
index 1243b089d228..4bcace0d6ee1 100644
--- a/rules/CodingStyle/Rector/FuncCall/ConsistentImplodeRector.php
+++ b/rules/CodingStyle/Rector/FuncCall/ConsistentImplodeRector.php
@@ -66,6 +66,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'implode')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (\count($node->getArgs()) === 1) {
// complete default value ''
$node->args[1] = $node->getArgs()[0];
diff --git a/rules/CodingStyle/Rector/FuncCall/CountArrayToEmptyArrayComparisonRector.php b/rules/CodingStyle/Rector/FuncCall/CountArrayToEmptyArrayComparisonRector.php
index a0019600fd9e..c4d6932f3385 100644
--- a/rules/CodingStyle/Rector/FuncCall/CountArrayToEmptyArrayComparisonRector.php
+++ b/rules/CodingStyle/Rector/FuncCall/CountArrayToEmptyArrayComparisonRector.php
@@ -153,7 +153,13 @@ private function matchCountFuncCallArgExpr(Expr $expr) : ?Expr
if (!$this->isName($expr, 'count')) {
return null;
}
+ if ($expr->isFirstClassCallable()) {
+ return null;
+ }
$firstArg = $expr->getArgs()[0];
+ if (!$this->isArray($firstArg->value)) {
+ return null;
+ }
return $firstArg->value;
}
private function isZeroLNumber(Expr $expr) : bool
diff --git a/rules/CodingStyle/Rector/FuncCall/VersionCompareFuncCallToConstantRector.php b/rules/CodingStyle/Rector/FuncCall/VersionCompareFuncCallToConstantRector.php
index 5381ab496416..776875522c6b 100644
--- a/rules/CodingStyle/Rector/FuncCall/VersionCompareFuncCallToConstantRector.php
+++ b/rules/CodingStyle/Rector/FuncCall/VersionCompareFuncCallToConstantRector.php
@@ -26,15 +26,15 @@
*/
final class VersionCompareFuncCallToConstantRector extends AbstractRector
{
- /**
- * @var array>
- */
- private const OPERATOR_TO_COMPARISON = ['=' => Identical::class, '==' => Identical::class, 'eq' => Identical::class, '!=' => NotIdentical::class, '<>' => NotIdentical::class, 'ne' => NotIdentical::class, '>' => Greater::class, 'gt' => Greater::class, '<' => Smaller::class, 'lt' => Smaller::class, '>=' => GreaterOrEqual::class, 'ge' => GreaterOrEqual::class, '<=' => SmallerOrEqual::class, 'le' => SmallerOrEqual::class];
/**
* @readonly
* @var \Rector\Core\Util\PhpVersionFactory
*/
private $phpVersionFactory;
+ /**
+ * @var array>
+ */
+ private const OPERATOR_TO_COMPARISON = ['=' => Identical::class, '==' => Identical::class, 'eq' => Identical::class, '!=' => NotIdentical::class, '<>' => NotIdentical::class, 'ne' => NotIdentical::class, '>' => Greater::class, 'gt' => Greater::class, '<' => Smaller::class, 'lt' => Smaller::class, '>=' => GreaterOrEqual::class, 'ge' => GreaterOrEqual::class, '<=' => SmallerOrEqual::class, 'le' => SmallerOrEqual::class];
public function __construct(PhpVersionFactory $phpVersionFactory)
{
$this->phpVersionFactory = $phpVersionFactory;
diff --git a/rules/CodingStyle/Rector/MethodCall/PreferThisOrSelfMethodCallRector.php b/rules/CodingStyle/Rector/MethodCall/PreferThisOrSelfMethodCallRector.php
deleted file mode 100644
index d255b056b17d..000000000000
--- a/rules/CodingStyle/Rector/MethodCall/PreferThisOrSelfMethodCallRector.php
+++ /dev/null
@@ -1,148 +0,0 @@
-
- */
- private $typeToPreference = [];
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\AstResolver
- */
- private $astResolver;
- public function __construct(AstResolver $astResolver)
- {
- $this->astResolver = $astResolver;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Changes $this->... and static:: to self:: or vise versa for given types', [new ConfiguredCodeSample(<<<'CODE_SAMPLE'
-use PHPUnit\Framework\TestCase;
-
-final class SomeClass extends TestCase
-{
- public function run()
- {
- $this->assertEquals('a', 'a');
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-use PHPUnit\Framework\TestCase;
-
-final class SomeClass extends TestCase
-{
- public function run()
- {
- self::assertEquals('a', 'a');
- }
-}
-CODE_SAMPLE
-, ['PHPUnit\\Framework\\TestCase' => PreferenceSelfThis::PREFER_SELF])]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [MethodCall::class, StaticCall::class];
- }
- /**
- * @param MethodCall|StaticCall $node
- */
- public function refactor(Node $node) : ?Node
- {
- foreach ($this->typeToPreference as $type => $preference) {
- if (!$this->nodeTypeResolver->isMethodStaticCallOrClassMethodObjectType($node, new ObjectType($type))) {
- continue;
- }
- if ($preference === PreferenceSelfThis::PREFER_SELF) {
- return $this->processToSelf($node);
- }
- return $this->processToThis($node);
- }
- return null;
- }
- /**
- * @param mixed[] $configuration
- */
- public function configure(array $configuration) : void
- {
- Assert::allString(\array_keys($configuration));
- Assert::allString($configuration);
- Assert::allOneOf($configuration, [PreferenceSelfThis::PREFER_THIS, PreferenceSelfThis::PREFER_SELF]);
- $this->typeToPreference = $configuration;
- }
- /**
- * @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall $node
- */
- private function processToSelf($node) : ?StaticCall
- {
- // class is already "self", let's skip it
- if ($node instanceof StaticCall && $this->isName($node->class, ObjectReference::SELF)) {
- return null;
- }
- if ($node instanceof MethodCall && !$this->isName($node->var, self::THIS)) {
- return null;
- }
- $classMethod = $this->astResolver->resolveClassMethodFromCall($node);
- if ($classMethod instanceof ClassMethod && !$classMethod->isStatic()) {
- return null;
- }
- $name = $this->getName($node->name);
- if ($name === null) {
- return null;
- }
- return $this->nodeFactory->createStaticCall(ObjectReference::SELF, $name, $node->args);
- }
- /**
- * @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall $node
- */
- private function processToThis($node) : ?MethodCall
- {
- if ($node instanceof MethodCall) {
- return null;
- }
- if (!$this->isNames($node->class, [ObjectReference::SELF, ObjectReference::STATIC])) {
- return null;
- }
- $name = $this->getName($node->name);
- if ($name === null) {
- return null;
- }
- // avoid adding dynamic method call to static method
- $classMethod = $this->betterNodeFinder->findParentByTypes($node, [ClassMethod::class]);
- if (!$classMethod instanceof ClassMethod) {
- return $this->nodeFactory->createMethodCall(new Variable(self::THIS), $name, $node->args);
- }
- if (!$classMethod->isStatic()) {
- return $this->nodeFactory->createMethodCall(new Variable(self::THIS), $name, $node->args);
- }
- return null;
- }
-}
diff --git a/rules/CodingStyle/Rector/Stmt/NewlineAfterStatementRector.php b/rules/CodingStyle/Rector/Stmt/NewlineAfterStatementRector.php
index 656ca07f7342..43a907b42230 100644
--- a/rules/CodingStyle/Rector/Stmt/NewlineAfterStatementRector.php
+++ b/rules/CodingStyle/Rector/Stmt/NewlineAfterStatementRector.php
@@ -25,7 +25,6 @@
use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\NodeTypeResolver\Node\AttributeKey;
-use Rector\PostRector\Collector\NodesToRemoveCollector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
@@ -37,15 +36,6 @@ final class NewlineAfterStatementRector extends AbstractRector
* @var array>
*/
private const STMTS_TO_HAVE_NEXT_NEWLINE = [ClassMethod::class, Function_::class, Property::class, If_::class, Foreach_::class, Do_::class, While_::class, For_::class, ClassConst::class, TryCatch::class, Class_::class, Trait_::class, Interface_::class, Switch_::class];
- /**
- * @readonly
- * @var \Rector\PostRector\Collector\NodesToRemoveCollector
- */
- private $nodesToRemoveCollector;
- public function __construct(NodesToRemoveCollector $nodesToRemoveCollector)
- {
- $this->nodesToRemoveCollector = $nodesToRemoveCollector;
- }
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Add new line after statements to tidify code', [new CodeSample(<<<'CODE_SAMPLE'
@@ -121,9 +111,6 @@ private function processAddNewLine($node, bool $hasChanged, int $jumpToKey = 0)
if ($rangeLine > 1) {
continue;
}
- if ($this->isRemoved($stmt)) {
- continue;
- }
\array_splice($node->stmts, $key + 1, 0, [new Nop()]);
$hasChanged = \true;
return $this->processAddNewLine($node, $hasChanged, $key + 2);
@@ -162,10 +149,6 @@ private function hasNoComment(?array $comments) : bool
}
return !isset($comments[0]);
}
- private function isRemoved(Stmt $stmt) : bool
- {
- return $this->nodesToRemoveCollector->isNodeRemoved($stmt);
- }
private function shouldSkip(Stmt $stmt) : bool
{
return !\in_array(\get_class($stmt), self::STMTS_TO_HAVE_NEXT_NEWLINE, \true);
diff --git a/rules/CodingStyle/Rector/String_/UseClassKeywordForClassNameResolutionRector.php b/rules/CodingStyle/Rector/String_/UseClassKeywordForClassNameResolutionRector.php
index 0d7e589c1ccc..a13ed45e7d4e 100644
--- a/rules/CodingStyle/Rector/String_/UseClassKeywordForClassNameResolutionRector.php
+++ b/rules/CodingStyle/Rector/String_/UseClassKeywordForClassNameResolutionRector.php
@@ -18,16 +18,16 @@
*/
final class UseClassKeywordForClassNameResolutionRector extends AbstractRector
{
- /**
- * @var string
- * @see https://regex101.com/r/Vv41Qr/1/
- */
- private const CLASS_BEFORE_STATIC_ACCESS_REGEX = '#(?[\\\\a-zA-Z0-9_\\x80-\\xff]*)::#';
/**
* @readonly
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @var string
+ * @see https://regex101.com/r/Vv41Qr/1/
+ */
+ private const CLASS_BEFORE_STATIC_ACCESS_REGEX = '#(?[\\\\a-zA-Z0-9_\\x80-\\xff]*)::#';
public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
diff --git a/rules/CodingStyle/ValueObject/ReturnArrayClassMethodToYield.php b/rules/CodingStyle/ValueObject/ReturnArrayClassMethodToYield.php
deleted file mode 100644
index e82320c3f128..000000000000
--- a/rules/CodingStyle/ValueObject/ReturnArrayClassMethodToYield.php
+++ /dev/null
@@ -1,34 +0,0 @@
-type = $type;
- $this->method = $method;
- RectorAssert::className($type);
- }
- public function getObjectType() : ObjectType
- {
- return new ObjectType($this->type);
- }
- public function getMethod() : string
- {
- return $this->method;
- }
-}
diff --git a/rules/Compatibility/NodeAnalyzer/RequiredAnnotationPropertyAnalyzer.php b/rules/Compatibility/NodeAnalyzer/RequiredAnnotationPropertyAnalyzer.php
deleted file mode 100644
index 127e0c940796..000000000000
--- a/rules/Compatibility/NodeAnalyzer/RequiredAnnotationPropertyAnalyzer.php
+++ /dev/null
@@ -1,47 +0,0 @@
-valueResolver = $valueResolver;
- }
- public function isRequiredProperty(PhpDocInfo $phpDocInfo, Property $property) : bool
- {
- if ($phpDocInfo->hasByAnnotationClass('Doctrine\\Common\\Annotations\\Annotation\\Required')) {
- return \true;
- }
- // sometimes property has default null, but @var says its not null - that's due to nullability of typed properties
- // in that case, we should treat property as required
- $firstProperty = $property->props[0];
- if (!$firstProperty->default instanceof Expr) {
- return \false;
- }
- if (!$this->valueResolver->isNull($firstProperty->default)) {
- return \false;
- }
- $varTagValueNode = $phpDocInfo->getVarTagValueNode();
- if (!$varTagValueNode instanceof VarTagValueNode) {
- return \false;
- }
- if ($varTagValueNode->type instanceof NullableTypeNode) {
- return \false;
- }
- return $property->type instanceof NullableType;
- }
-}
diff --git a/rules/Compatibility/NodeFactory/ConstructorClassMethodFactory.php b/rules/Compatibility/NodeFactory/ConstructorClassMethodFactory.php
deleted file mode 100644
index 083bee203e86..000000000000
--- a/rules/Compatibility/NodeFactory/ConstructorClassMethodFactory.php
+++ /dev/null
@@ -1,45 +0,0 @@
-phpDocInfoFactory = $phpDocInfoFactory;
- $this->paramTagRemover = $paramTagRemover;
- }
- /**
- * @param PropertyWithPhpDocInfo[] $requiredPropertiesWithPhpDocInfos
- * @param Param[] $params
- */
- public function createConstructorClassMethod(array $requiredPropertiesWithPhpDocInfos, array $params) : ClassMethod
- {
- $classMethod = new ClassMethod(MethodName::CONSTRUCT, ['flags' => Class_::MODIFIER_PUBLIC, 'params' => $params]);
- $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod);
- foreach ($requiredPropertiesWithPhpDocInfos as $requiredPropertyWithPhpDocInfo) {
- $paramTagValueNode = $requiredPropertyWithPhpDocInfo->getParamTagValueNode();
- $phpDocInfo->addTagValueNode($paramTagValueNode);
- }
- $this->paramTagRemover->removeParamTagsIfUseless($phpDocInfo, $classMethod);
- return $classMethod;
- }
-}
diff --git a/rules/Compatibility/Rector/Class_/AttributeCompatibleAnnotationRector.php b/rules/Compatibility/Rector/Class_/AttributeCompatibleAnnotationRector.php
deleted file mode 100644
index 6b034e0dc5a5..000000000000
--- a/rules/Compatibility/Rector/Class_/AttributeCompatibleAnnotationRector.php
+++ /dev/null
@@ -1,165 +0,0 @@
-phpAttributeAnalyzer = $phpAttributeAnalyzer;
- $this->phpDocTagRemover = $phpDocTagRemover;
- $this->requiredAnnotationPropertyAnalyzer = $requiredAnnotationPropertyAnalyzer;
- $this->constructorClassMethodFactory = $constructorClassMethodFactory;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Change annotation to attribute compatible form, see https://tomasvotruba.com/blog/doctrine-annotations-and-attributes-living-together-in-peace/', [new CodeSample(<<<'CODE_SAMPLE'
-use Doctrine\Common\Annotations\Annotation\Required;
-
-/**
- * @annotation
- */
-class SomeAnnotation
-{
- /**
- * @var string[]
- * @Required()
- */
- public array $enum;
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-use Doctrine\Common\Annotations\Annotation\NamedArgumentConstructor;
-
-/**
- * @annotation
- * @NamedArgumentConstructor
- */
-class SomeAnnotation
-{
- /**
- * @param string[] $enum
- */
- public function __construct(
- public array $enum
- ) {
- }
-}
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [Class_::class];
- }
- /**
- * @param Class_ $node
- */
- public function refactor(Node $node) : ?Node
- {
- $phpDocInfo = $this->phpDocInfoFactory->createFromNode($node);
- if (!$phpDocInfo instanceof PhpDocInfo) {
- return null;
- }
- if ($this->shouldSkipClass($phpDocInfo, $node)) {
- return null;
- }
- // add "NamedArgumentConstructor"
- $phpDocInfo->addTagValueNode(new DoctrineAnnotationTagValueNode(new IdentifierTypeNode('Doctrine\\Common\\Annotations\\Annotation\\NamedArgumentConstructor')));
- // resolve required properties
- $requiredPropertiesWithPhpDocInfos = [];
- foreach ($node->getProperties() as $property) {
- if (!$property->isPublic()) {
- continue;
- }
- $propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
- if (!$this->requiredAnnotationPropertyAnalyzer->isRequiredProperty($propertyPhpDocInfo, $property)) {
- continue;
- }
- $propertyName = $this->getName($property);
- $requiredPropertiesWithPhpDocInfos[] = new PropertyWithPhpDocInfo($propertyName, $property, $propertyPhpDocInfo);
- }
- $params = $this->createConstructParams($requiredPropertiesWithPhpDocInfos);
- $constructorClassMethod = $this->constructorClassMethodFactory->createConstructorClassMethod($requiredPropertiesWithPhpDocInfos, $params);
- $node->stmts = \array_merge($node->stmts, [$constructorClassMethod]);
- return $node;
- }
- private function shouldSkipClass(PhpDocInfo $phpDocInfo, Class_ $class) : bool
- {
- if (!$phpDocInfo->hasByNames(['Annotation', 'annotation'])) {
- return \true;
- }
- if ($phpDocInfo->hasByAnnotationClass('Doctrine\\Common\\Annotations\\Annotation\\NamedArgumentConstructor')) {
- return \true;
- }
- // has attribute? skip it
- return $this->phpAttributeAnalyzer->hasPhpAttribute($class, AttributeName::ATTRIBUTE);
- }
- /**
- * @param PropertyWithPhpDocInfo[] $requiredPropertiesWithPhpDocInfos
- * @return Param[]
- */
- private function createConstructParams(array $requiredPropertiesWithPhpDocInfos) : array
- {
- $params = [];
- foreach ($requiredPropertiesWithPhpDocInfos as $requiredPropertyWithPhpDocInfo) {
- $property = $requiredPropertyWithPhpDocInfo->getProperty();
- $propertyName = $this->getName($property);
- // unwrap nullable type, as variable is required
- $propertyType = $property->type;
- if ($propertyType instanceof NullableType) {
- $propertyType = $propertyType->type;
- }
- $params[] = new Param(new Variable($propertyName), null, $propertyType, \false, \false, [], $property->flags);
- $propertyPhpDocInfo = $requiredPropertyWithPhpDocInfo->getPhpDocInfo();
- // remove required
- $this->phpDocTagRemover->removeByName($propertyPhpDocInfo, 'Doctrine\\Common\\Annotations\\Annotation\\Required');
- $this->removeNode($property);
- }
- return $params;
- }
-}
diff --git a/rules/Compatibility/ValueObject/PropertyWithPhpDocInfo.php b/rules/Compatibility/ValueObject/PropertyWithPhpDocInfo.php
deleted file mode 100644
index 4caa7364db19..000000000000
--- a/rules/Compatibility/ValueObject/PropertyWithPhpDocInfo.php
+++ /dev/null
@@ -1,50 +0,0 @@
-propertyName = $propertyName;
- $this->property = $property;
- $this->phpDocInfo = $phpDocInfo;
- }
- public function getProperty() : Property
- {
- return $this->property;
- }
- public function getPhpDocInfo() : PhpDocInfo
- {
- return $this->phpDocInfo;
- }
- public function getParamTagValueNode() : ParamTagValueNode
- {
- $varTagValueNode = $this->phpDocInfo->getVarTagValueNode();
- if (!$varTagValueNode instanceof VarTagValueNode) {
- throw new ShouldNotHappenException();
- }
- return new ParamTagValueNode($varTagValueNode->type, \false, '$' . $this->propertyName, '');
- }
-}
diff --git a/rules/DeadCode/Comparator/CurrentAndParentClassMethodComparator.php b/rules/DeadCode/Comparator/CurrentAndParentClassMethodComparator.php
deleted file mode 100644
index 87501fbe989f..000000000000
--- a/rules/DeadCode/Comparator/CurrentAndParentClassMethodComparator.php
+++ /dev/null
@@ -1,160 +0,0 @@
-nodeNameResolver = $nodeNameResolver;
- $this->parameterDefaultsComparator = $parameterDefaultsComparator;
- $this->parameterTypeComparator = $parameterTypeComparator;
- $this->nodeComparator = $nodeComparator;
- $this->reflectionResolver = $reflectionResolver;
- }
- public function isParentCallMatching(ClassMethod $classMethod, StaticCall $staticCall, Scope $scope) : bool
- {
- if (!$this->isSameMethodParentCall($classMethod, $staticCall)) {
- return \false;
- }
- if (!$this->areArgsAndParamsEqual($staticCall->args, $classMethod->params)) {
- return \false;
- }
- if (!$this->parameterTypeComparator->isClassMethodIdenticalToParentStaticCall($classMethod, $staticCall, $scope)) {
- return \false;
- }
- return !$this->isParentClassMethodVisibilityOrDefaultOverride($classMethod, $staticCall, $scope);
- }
- private function isSameMethodParentCall(ClassMethod $classMethod, StaticCall $staticCall) : bool
- {
- if (!$this->nodeNameResolver->areNamesEqual($staticCall->name, $classMethod->name)) {
- return \false;
- }
- return $this->nodeNameResolver->isName($staticCall->class, ObjectReference::PARENT);
- }
- /**
- * @param Arg[]|VariadicPlaceholder[] $parentStaticCallArgs
- * @param Param[] $currentClassMethodParams
- */
- private function areArgsAndParamsEqual(array $parentStaticCallArgs, array $currentClassMethodParams) : bool
- {
- if (\count($parentStaticCallArgs) !== \count($currentClassMethodParams)) {
- return \false;
- }
- if ($parentStaticCallArgs === []) {
- return \true;
- }
- foreach ($parentStaticCallArgs as $key => $arg) {
- if (!isset($currentClassMethodParams[$key])) {
- return \false;
- }
- if (!$arg instanceof Arg) {
- continue;
- }
- // this only compares variable name, but those can be differnt, so its kinda useless
- $param = $currentClassMethodParams[$key];
- if (!$this->nodeComparator->areNodesEqual($param->var, $arg->value)) {
- return \false;
- }
- }
- return \true;
- }
- private function isParentClassMethodVisibilityOrDefaultOverride(ClassMethod $classMethod, StaticCall $staticCall, Scope $scope) : bool
- {
- $classReflection = $this->reflectionResolver->resolveClassReflection($classMethod);
- if (!$classReflection instanceof ClassReflection) {
- return \false;
- }
- $methodName = $this->nodeNameResolver->getName($staticCall->name);
- if ($methodName === null) {
- return \false;
- }
- foreach ($classReflection->getParents() as $parentClassReflection) {
- if (!$parentClassReflection->hasMethod($methodName)) {
- continue;
- }
- $nativeParentClassReflection = $parentClassReflection->getNativeReflection();
- $nativeParentClassMethodReflection = $nativeParentClassReflection->getMethod($methodName);
- if (!$nativeParentClassMethodReflection->isProtected()) {
- return $this->isOverridingParentParameters($classMethod, $parentClassReflection, $methodName, $scope);
- }
- if (!$nativeParentClassMethodReflection->isPublic()) {
- return $this->isOverridingParentParameters($classMethod, $parentClassReflection, $methodName, $scope);
- }
- return \true;
- }
- return \false;
- }
- private function isOverridingParentParameters(ClassMethod $classMethod, ClassReflection $classReflection, string $methodName, Scope $scope) : bool
- {
- $extendedMethodReflection = $classReflection->getMethod($methodName, $scope);
- // 3rd party code
- if (!$extendedMethodReflection->isPrivate() && !$extendedMethodReflection->isPublic() && $classMethod->isPublic()) {
- return \true;
- }
- if ($extendedMethodReflection->isInternal()->yes()) {
- // we can't know for certain so we assume its a override with purpose
- return \true;
- }
- return $this->areParameterDefaultsDifferent($classMethod, $extendedMethodReflection);
- }
- private function areParameterDefaultsDifferent(ClassMethod $classMethod, ExtendedMethodReflection $extendedMethodReflection) : bool
- {
- $parametersAcceptorWithPhpDocs = ParametersAcceptorSelector::selectSingle($extendedMethodReflection->getVariants());
- foreach ($parametersAcceptorWithPhpDocs->getParameters() as $key => $parameterReflectionWithPhpDoc) {
- if (!isset($classMethod->params[$key])) {
- if ($parameterReflectionWithPhpDoc->getDefaultValue() instanceof Type) {
- continue;
- }
- return \true;
- }
- $methodParam = $classMethod->params[$key];
- if ($this->parameterDefaultsComparator->areDefaultValuesDifferent($parameterReflectionWithPhpDoc, $methodParam)) {
- return \true;
- }
- }
- return \false;
- }
-}
diff --git a/rules/DeadCode/Comparator/Parameter/ParameterDefaultsComparator.php b/rules/DeadCode/Comparator/Parameter/ParameterDefaultsComparator.php
deleted file mode 100644
index bb550dac0b6a..000000000000
--- a/rules/DeadCode/Comparator/Parameter/ParameterDefaultsComparator.php
+++ /dev/null
@@ -1,52 +0,0 @@
-nodeComparator = $nodeComparator;
- $this->defaultParameterValueResolver = $defaultParameterValueResolver;
- }
- public function areDefaultValuesDifferent(ParameterReflection $parameterReflection, Param $param) : bool
- {
- if (!$parameterReflection->getDefaultValue() instanceof Type && !$param->default instanceof Expr) {
- return \false;
- }
- if ($this->isMutuallyExclusiveNull($parameterReflection, $param)) {
- return \true;
- }
- /** @var Expr $paramDefault */
- $paramDefault = $param->default;
- $defaultValueExpr = $this->defaultParameterValueResolver->resolveFromParameterReflection($parameterReflection);
- return !$this->nodeComparator->areNodesEqual($paramDefault, $defaultValueExpr);
- }
- private function isMutuallyExclusiveNull(ParameterReflection $parameterReflection, Param $param) : bool
- {
- if (!$parameterReflection->getDefaultValue() instanceof Type && $param->default instanceof Expr) {
- return \true;
- }
- if (!$parameterReflection->getDefaultValue() instanceof Type) {
- return \false;
- }
- return !$param->default instanceof Expr;
- }
-}
diff --git a/rules/DeadCode/Comparator/Parameter/ParameterTypeComparator.php b/rules/DeadCode/Comparator/Parameter/ParameterTypeComparator.php
deleted file mode 100644
index 5ba1a4ae3090..000000000000
--- a/rules/DeadCode/Comparator/Parameter/ParameterTypeComparator.php
+++ /dev/null
@@ -1,36 +0,0 @@
-methodParameterTypeResolver = $methodParameterTypeResolver;
- }
- public function isClassMethodIdenticalToParentStaticCall(ClassMethod $classMethod, StaticCall $staticCall, Scope $scope) : bool
- {
- $currentParameterTypes = $this->methodParameterTypeResolver->provideParameterTypesByClassMethod($classMethod, $scope);
- $parentParameterTypes = $this->methodParameterTypeResolver->provideParameterTypesByStaticCall($staticCall, $scope);
- foreach ($currentParameterTypes as $key => $currentParameterType) {
- if (!isset($parentParameterTypes[$key])) {
- continue;
- }
- $parentParameterType = $parentParameterTypes[$key];
- if (!$currentParameterType->equals($parentParameterType)) {
- return \false;
- }
- }
- return \true;
- }
-}
diff --git a/rules/DeadCode/NodeAnalyzer/ExprUsedInNodeAnalyzer.php b/rules/DeadCode/NodeAnalyzer/ExprUsedInNodeAnalyzer.php
index 6e901c501e33..d0983e907899 100644
--- a/rules/DeadCode/NodeAnalyzer/ExprUsedInNodeAnalyzer.php
+++ b/rules/DeadCode/NodeAnalyzer/ExprUsedInNodeAnalyzer.php
@@ -7,8 +7,8 @@
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\Include_;
use PhpParser\Node\Expr\Variable;
-use Rector\Core\Contract\PhpParser\NodePrinterInterface;
use Rector\Core\NodeAnalyzer\CompactFuncCallAnalyzer;
+use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
final class ExprUsedInNodeAnalyzer
{
/**
@@ -23,14 +23,14 @@ final class ExprUsedInNodeAnalyzer
private $compactFuncCallAnalyzer;
/**
* @readonly
- * @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
+ * @var \Rector\Core\PhpParser\Printer\BetterStandardPrinter
*/
- private $nodePrinter;
- public function __construct(\Rector\DeadCode\NodeAnalyzer\UsedVariableNameAnalyzer $usedVariableNameAnalyzer, CompactFuncCallAnalyzer $compactFuncCallAnalyzer, NodePrinterInterface $nodePrinter)
+ private $betterStandardPrinter;
+ public function __construct(\Rector\DeadCode\NodeAnalyzer\UsedVariableNameAnalyzer $usedVariableNameAnalyzer, CompactFuncCallAnalyzer $compactFuncCallAnalyzer, BetterStandardPrinter $betterStandardPrinter)
{
$this->usedVariableNameAnalyzer = $usedVariableNameAnalyzer;
$this->compactFuncCallAnalyzer = $compactFuncCallAnalyzer;
- $this->nodePrinter = $nodePrinter;
+ $this->betterStandardPrinter = $betterStandardPrinter;
}
public function isUsed(Node $node, Variable $variable) : bool
{
@@ -39,7 +39,7 @@ public function isUsed(Node $node, Variable $variable) : bool
}
// variable as variable variable need mark as used
if ($node instanceof Variable) {
- $print = $this->nodePrinter->print($node);
+ $print = $this->betterStandardPrinter->print($node);
if (\strncmp($print, '${$', \strlen('${$')) === 0) {
return \true;
}
diff --git a/rules/DeadCode/NodeAnalyzer/IsClassMethodUsedAnalyzer.php b/rules/DeadCode/NodeAnalyzer/IsClassMethodUsedAnalyzer.php
index 84a8c89692bd..7ccfe2cc558e 100644
--- a/rules/DeadCode/NodeAnalyzer/IsClassMethodUsedAnalyzer.php
+++ b/rules/DeadCode/NodeAnalyzer/IsClassMethodUsedAnalyzer.php
@@ -3,14 +3,15 @@
declare (strict_types=1);
namespace Rector\DeadCode\NodeAnalyzer;
+use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
-use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
+use PHPStan\Parser\ArrayMapArgVisitor;
use PHPStan\Reflection\ClassReflection;
use Rector\Core\PhpParser\AstResolver;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
@@ -101,11 +102,7 @@ private function isClassMethodCalledInLocalMethodCall(Class_ $class, string $cla
}
private function isInArrayMap(Class_ $class, Array_ $array) : bool
{
- $parentFuncCall = $this->betterNodeFinder->findParentType($array, FuncCall::class);
- if (!$parentFuncCall instanceof FuncCall) {
- return \false;
- }
- if (!$this->nodeNameResolver->isName($parentFuncCall->name, 'array_map')) {
+ if (!$array->getAttribute(ArrayMapArgVisitor::ATTRIBUTE_NAME) instanceof Arg) {
return \false;
}
if (\count($array->items) !== 2) {
diff --git a/rules/DeadCode/NodeAnalyzer/PropertyWriteonlyAnalyzer.php b/rules/DeadCode/NodeAnalyzer/PropertyWriteonlyAnalyzer.php
new file mode 100644
index 000000000000..31b0c56441f8
--- /dev/null
+++ b/rules/DeadCode/NodeAnalyzer/PropertyWriteonlyAnalyzer.php
@@ -0,0 +1,52 @@
+betterNodeFinder = $betterNodeFinder;
+ }
+ public function hasClassDynamicPropertyNames(Class_ $class) : bool
+ {
+ return (bool) $this->betterNodeFinder->findFirst($class, static function (Node $node) : bool {
+ if (!$node instanceof PropertyFetch) {
+ return \false;
+ }
+ // has dynamic name - could be anything
+ return $node->name instanceof Expr;
+ });
+ }
+ /**
+ * The property fetches are always only assigned to, nothing else
+ *
+ * @param array $propertyFetches
+ */
+ public function arePropertyFetchesExclusivelyBeingAssignedTo(array $propertyFetches) : bool
+ {
+ foreach ($propertyFetches as $propertyFetch) {
+ if ((bool) $propertyFetch->getAttribute(AttributeKey::IS_MULTI_ASSIGN, \false)) {
+ return \false;
+ }
+ if ((bool) $propertyFetch->getAttribute(AttributeKey::IS_BEING_ASSIGNED, \false)) {
+ continue;
+ }
+ return \false;
+ }
+ return \true;
+ }
+}
diff --git a/rules/DeadCode/NodeManipulator/ControllerClassMethodManipulator.php b/rules/DeadCode/NodeManipulator/ControllerClassMethodManipulator.php
index 04d225e4f349..818599b38413 100644
--- a/rules/DeadCode/NodeManipulator/ControllerClassMethodManipulator.php
+++ b/rules/DeadCode/NodeManipulator/ControllerClassMethodManipulator.php
@@ -8,7 +8,6 @@
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\PhpDocParser\Ast\PhpDoc\GenericTagValueNode;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeNameResolver\NodeNameResolver;
final class ControllerClassMethodManipulator
{
@@ -22,34 +21,24 @@ final class ControllerClassMethodManipulator
* @var \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory
*/
private $phpDocInfoFactory;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- public function __construct(NodeNameResolver $nodeNameResolver, PhpDocInfoFactory $phpDocInfoFactory, BetterNodeFinder $betterNodeFinder)
+ public function __construct(NodeNameResolver $nodeNameResolver, PhpDocInfoFactory $phpDocInfoFactory)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->phpDocInfoFactory = $phpDocInfoFactory;
- $this->betterNodeFinder = $betterNodeFinder;
}
- public function isControllerClassMethodWithBehaviorAnnotation(ClassMethod $classMethod) : bool
+ public function isControllerClassMethodWithBehaviorAnnotation(Class_ $class, ClassMethod $classMethod) : bool
{
- if (!$this->isControllerClassMethod($classMethod)) {
+ if (!$this->isControllerClassMethod($class, $classMethod)) {
return \false;
}
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod);
return $phpDocInfo->hasByType(GenericTagValueNode::class);
}
- private function isControllerClassMethod(ClassMethod $classMethod) : bool
+ private function isControllerClassMethod(Class_ $class, ClassMethod $classMethod) : bool
{
if (!$classMethod->isPublic()) {
return \false;
}
- $class = $this->betterNodeFinder->findParentType($classMethod, Class_::class);
- if (!$class instanceof Class_) {
- return \false;
- }
return $this->hasParentClassController($class);
}
private function hasParentClassController(Class_ $class) : bool
diff --git a/rules/DeadCode/NodeManipulator/CountManipulator.php b/rules/DeadCode/NodeManipulator/CountManipulator.php
index c08276c75a92..141489224b85 100644
--- a/rules/DeadCode/NodeManipulator/CountManipulator.php
+++ b/rules/DeadCode/NodeManipulator/CountManipulator.php
@@ -92,6 +92,9 @@ private function isCountWithExpression(Expr $node, Expr $expr) : bool
if (!$this->nodeNameResolver->isName($node, 'count')) {
return \false;
}
+ if ($node->isFirstClassCallable()) {
+ return \false;
+ }
if (!isset($node->getArgs()[0])) {
return \false;
}
diff --git a/rules/DeadCode/NodeManipulator/VariadicFunctionLikeDetector.php b/rules/DeadCode/NodeManipulator/VariadicFunctionLikeDetector.php
index 0d66bdcf2e80..78bd1ee4f383 100644
--- a/rules/DeadCode/NodeManipulator/VariadicFunctionLikeDetector.php
+++ b/rules/DeadCode/NodeManipulator/VariadicFunctionLikeDetector.php
@@ -11,10 +11,6 @@
use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser;
final class VariadicFunctionLikeDetector
{
- /**
- * @var string[]
- */
- private const VARIADIC_FUNCTION_NAMES = ['func_get_arg', 'func_get_args', 'func_num_args'];
/**
* @readonly
* @var \Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser
@@ -25,6 +21,10 @@ final class VariadicFunctionLikeDetector
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
+ /**
+ * @var string[]
+ */
+ private const VARIADIC_FUNCTION_NAMES = ['func_get_arg', 'func_get_args', 'func_num_args'];
public function __construct(SimpleCallableNodeTraverser $simpleCallableNodeTraverser, NodeNameResolver $nodeNameResolver)
{
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
diff --git a/rules/DeadCode/PhpDoc/DeadReturnTagValueNodeAnalyzer.php b/rules/DeadCode/PhpDoc/DeadReturnTagValueNodeAnalyzer.php
index 706c5b8639b8..58c445b78148 100644
--- a/rules/DeadCode/PhpDoc/DeadReturnTagValueNodeAnalyzer.php
+++ b/rules/DeadCode/PhpDoc/DeadReturnTagValueNodeAnalyzer.php
@@ -4,18 +4,17 @@
namespace Rector\DeadCode\PhpDoc;
use PhpParser\Node;
-use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\Trait_;
+use PHPStan\Analyser\Scope;
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use PHPStan\PhpDocParser\Ast\Type\ThisTypeNode;
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
use Rector\BetterPhpDocParser\ValueObject\Type\BracketsAwareUnionTypeNode;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\DeadCode\PhpDoc\Guard\StandaloneTypeRemovalGuard;
use Rector\DeadCode\TypeNodeAnalyzer\GenericTypeNodeAnalyzer;
use Rector\DeadCode\TypeNodeAnalyzer\MixedArrayTypeNodeAnalyzer;
+use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\TypeComparator\TypeComparator;
final class DeadReturnTagValueNodeAnalyzer
{
@@ -24,11 +23,6 @@ final class DeadReturnTagValueNodeAnalyzer
* @var \Rector\NodeTypeResolver\TypeComparator\TypeComparator
*/
private $typeComparator;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
/**
* @readonly
* @var \Rector\DeadCode\TypeNodeAnalyzer\GenericTypeNodeAnalyzer
@@ -49,10 +43,9 @@ final class DeadReturnTagValueNodeAnalyzer
* @var \Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger
*/
private $phpDocTypeChanger;
- public function __construct(TypeComparator $typeComparator, BetterNodeFinder $betterNodeFinder, GenericTypeNodeAnalyzer $genericTypeNodeAnalyzer, MixedArrayTypeNodeAnalyzer $mixedArrayTypeNodeAnalyzer, StandaloneTypeRemovalGuard $standaloneTypeRemovalGuard, PhpDocTypeChanger $phpDocTypeChanger)
+ public function __construct(TypeComparator $typeComparator, GenericTypeNodeAnalyzer $genericTypeNodeAnalyzer, MixedArrayTypeNodeAnalyzer $mixedArrayTypeNodeAnalyzer, StandaloneTypeRemovalGuard $standaloneTypeRemovalGuard, PhpDocTypeChanger $phpDocTypeChanger)
{
$this->typeComparator = $typeComparator;
- $this->betterNodeFinder = $betterNodeFinder;
$this->genericTypeNodeAnalyzer = $genericTypeNodeAnalyzer;
$this->mixedArrayTypeNodeAnalyzer = $mixedArrayTypeNodeAnalyzer;
$this->standaloneTypeRemovalGuard = $standaloneTypeRemovalGuard;
@@ -64,8 +57,8 @@ public function isDead(ReturnTagValueNode $returnTagValueNode, ClassMethod $clas
if ($returnType === null) {
return \false;
}
- $classLike = $this->betterNodeFinder->findParentType($classMethod, ClassLike::class);
- if ($classLike instanceof Trait_ && $returnTagValueNode->type instanceof ThisTypeNode) {
+ $scope = $classMethod->getAttribute(AttributeKey::SCOPE);
+ if ($scope instanceof Scope && $scope->isInTrait() && $returnTagValueNode->type instanceof ThisTypeNode) {
return \false;
}
if (!$this->typeComparator->arePhpParserAndPhpStanPhpDocTypesEqual($returnType, $returnTagValueNode->type, $classMethod)) {
diff --git a/rules/DeadCode/Rector/Array_/RemoveDuplicatedArrayKeyRector.php b/rules/DeadCode/Rector/Array_/RemoveDuplicatedArrayKeyRector.php
index 22e7cf4fb6d8..060078b52da2 100644
--- a/rules/DeadCode/Rector/Array_/RemoveDuplicatedArrayKeyRector.php
+++ b/rules/DeadCode/Rector/Array_/RemoveDuplicatedArrayKeyRector.php
@@ -9,7 +9,7 @@
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\PreDec;
use PhpParser\Node\Expr\PreInc;
-use Rector\Core\Contract\PhpParser\NodePrinterInterface;
+use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\MultiInstanceofChecker;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -20,23 +20,23 @@
*/
final class RemoveDuplicatedArrayKeyRector extends AbstractRector
{
- /**
- * @var array>
- */
- private const ALLOWED_KEY_DUPLICATES = [PreInc::class, PreDec::class];
/**
* @readonly
- * @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
+ * @var \Rector\Core\PhpParser\Printer\BetterStandardPrinter
*/
- private $nodePrinter;
+ private $betterStandardPrinter;
/**
* @readonly
* @var \Rector\Core\Util\MultiInstanceofChecker
*/
private $multiInstanceofChecker;
- public function __construct(NodePrinterInterface $nodePrinter, MultiInstanceofChecker $multiInstanceofChecker)
+ /**
+ * @var array>
+ */
+ private const ALLOWED_KEY_DUPLICATES = [PreInc::class, PreDec::class];
+ public function __construct(BetterStandardPrinter $betterStandardPrinter, MultiInstanceofChecker $multiInstanceofChecker)
{
- $this->nodePrinter = $nodePrinter;
+ $this->betterStandardPrinter = $betterStandardPrinter;
$this->multiInstanceofChecker = $multiInstanceofChecker;
}
public function getRuleDefinition() : RuleDefinition
@@ -94,7 +94,7 @@ private function resolveDuplicateKeysArrayItems(Array_ $array) : array
if (!$arrayItem->key instanceof Expr) {
continue;
}
- $keyValue = $this->nodePrinter->print($arrayItem->key);
+ $keyValue = $this->betterStandardPrinter->print($arrayItem->key);
$arrayItemsByKeys[$keyValue][] = $arrayItem;
}
return $this->filterItemsWithSameKey($arrayItemsByKeys);
diff --git a/rules/DeadCode/Rector/Assign/RemoveDoubleAssignRector.php b/rules/DeadCode/Rector/Assign/RemoveDoubleAssignRector.php
index 918160fb38e0..069e4e340445 100644
--- a/rules/DeadCode/Rector/Assign/RemoveDoubleAssignRector.php
+++ b/rules/DeadCode/Rector/Assign/RemoveDoubleAssignRector.php
@@ -59,7 +59,7 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
if ($stmts === null) {
return null;
}
- $hasRemovedStmt = \false;
+ $hasChanged = \false;
foreach ($stmts as $key => $stmt) {
if (!isset($stmts[$key + 1])) {
continue;
@@ -94,10 +94,10 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
continue;
}
// remove current Stmt if will be overriden in next stmt
- $this->removeNode($stmt);
- $hasRemovedStmt = \true;
+ unset($node->stmts[$key]);
+ $hasChanged = \true;
}
- if (!$hasRemovedStmt) {
+ if (!$hasChanged) {
return null;
}
return $node;
diff --git a/rules/DeadCode/Rector/Assign/RemoveUnusedVariableAssignRector.php b/rules/DeadCode/Rector/Assign/RemoveUnusedVariableAssignRector.php
index 3f80d5a07a0a..737c9e231ff3 100644
--- a/rules/DeadCode/Rector/Assign/RemoveUnusedVariableAssignRector.php
+++ b/rules/DeadCode/Rector/Assign/RemoveUnusedVariableAssignRector.php
@@ -102,9 +102,7 @@ public function refactorWithScope(Node $node, Scope $scope) : ?ClassMethod
$currentStmt = $classMethodStmts[$stmtPosition];
/** @var Assign $assign */
$assign = $currentStmt->expr;
- /** @var Scope $assignScope */
- $assignScope = $assign->getAttribute(AttributeKey::SCOPE);
- if ($this->hasCallLikeInAssignExpr($assign, $assignScope)) {
+ if ($this->hasCallLikeInAssignExpr($assign, $scope)) {
// clean safely
$cleanAssignedExpr = $this->cleanCastedExpr($assign->expr);
$node->stmts[$stmtPosition] = new Expression($cleanAssignedExpr);
diff --git a/rules/DeadCode/Rector/Cast/RecastingRemovalRector.php b/rules/DeadCode/Rector/Cast/RecastingRemovalRector.php
index ea96e1a9dae6..f25f4d5a9e68 100644
--- a/rules/DeadCode/Rector/Cast/RecastingRemovalRector.php
+++ b/rules/DeadCode/Rector/Cast/RecastingRemovalRector.php
@@ -39,10 +39,6 @@
*/
final class RecastingRemovalRector extends AbstractRector
{
- /**
- * @var array, class-string>
- */
- private const CAST_CLASS_TO_NODE_TYPE = [String_::class => StringType::class, Bool_::class => BooleanType::class, Array_::class => ArrayType::class, Int_::class => IntegerType::class, Object_::class => ObjectType::class, Double::class => FloatType::class];
/**
* @readonly
* @var \Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer
@@ -63,6 +59,10 @@ final class RecastingRemovalRector extends AbstractRector
* @var \Rector\Core\PhpParser\AstResolver
*/
private $astResolver;
+ /**
+ * @var array, class-string>
+ */
+ private const CAST_CLASS_TO_NODE_TYPE = [String_::class => StringType::class, Bool_::class => BooleanType::class, Array_::class => ArrayType::class, Int_::class => IntegerType::class, Object_::class => ObjectType::class, Double::class => FloatType::class];
public function __construct(PropertyFetchAnalyzer $propertyFetchAnalyzer, ReflectionResolver $reflectionResolver, ExprAnalyzer $exprAnalyzer, AstResolver $astResolver)
{
$this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
diff --git a/rules/DeadCode/Rector/ClassConst/RemoveUnusedPrivateClassConstantRector.php b/rules/DeadCode/Rector/ClassConst/RemoveUnusedPrivateClassConstantRector.php
index 866b95dbfacf..2a3dd70087d3 100644
--- a/rules/DeadCode/Rector/ClassConst/RemoveUnusedPrivateClassConstantRector.php
+++ b/rules/DeadCode/Rector/ClassConst/RemoveUnusedPrivateClassConstantRector.php
@@ -5,37 +5,32 @@
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassConst;
+use PhpParser\NodeTraverser;
+use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
-use Rector\Core\NodeAnalyzer\EnumAnalyzer;
use Rector\Core\NodeManipulator\ClassConstManipulator;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\Reflection\ReflectionResolver;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\DeadCode\Rector\ClassConst\RemoveUnusedPrivateClassConstantRector\RemoveUnusedPrivateClassConstantRectorTest
*/
-final class RemoveUnusedPrivateClassConstantRector extends AbstractRector
+final class RemoveUnusedPrivateClassConstantRector extends AbstractScopeAwareRector
{
/**
* @readonly
* @var \Rector\Core\NodeManipulator\ClassConstManipulator
*/
private $classConstManipulator;
- /**
- * @readonly
- * @var \Rector\Core\NodeAnalyzer\EnumAnalyzer
- */
- private $enumAnalyzer;
/**
* @readonly
* @var \Rector\Core\Reflection\ReflectionResolver
*/
private $reflectionResolver;
- public function __construct(ClassConstManipulator $classConstManipulator, EnumAnalyzer $enumAnalyzer, ReflectionResolver $reflectionResolver)
+ public function __construct(ClassConstManipulator $classConstManipulator, ReflectionResolver $reflectionResolver)
{
$this->classConstManipulator = $classConstManipulator;
- $this->enumAnalyzer = $enumAnalyzer;
$this->reflectionResolver = $reflectionResolver;
}
public function getRuleDefinition() : RuleDefinition
@@ -70,9 +65,9 @@ public function getNodeTypes() : array
/**
* @param ClassConst $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?int
{
- if ($this->shouldSkipClassConst($node)) {
+ if ($this->shouldSkipClassConst($node, $scope)) {
return null;
}
$classReflection = $this->reflectionResolver->resolveClassReflection($node);
@@ -82,10 +77,9 @@ public function refactor(Node $node) : ?Node
if ($this->classConstManipulator->hasClassConstFetch($node, $classReflection)) {
return null;
}
- $this->removeNode($node);
- return null;
+ return NodeTraverser::REMOVE_NODE;
}
- private function shouldSkipClassConst(ClassConst $classConst) : bool
+ private function shouldSkipClassConst(ClassConst $classConst, Scope $scope) : bool
{
if (!$classConst->isPrivate()) {
return \true;
@@ -93,6 +87,19 @@ private function shouldSkipClassConst(ClassConst $classConst) : bool
if (\count($classConst->consts) !== 1) {
return \true;
}
- return $this->enumAnalyzer->isEnumClassConst($classConst);
+ $classReflection = $scope->getClassReflection();
+ if (!$classReflection instanceof ClassReflection) {
+ return \false;
+ }
+ return $this->hasParentClassOfEnumSuffix($classReflection);
+ }
+ private function hasParentClassOfEnumSuffix(ClassReflection $classReflection) : bool
+ {
+ foreach ($classReflection->getParentClassesNames() as $parentClassesName) {
+ if (\substr_compare($parentClassesName, 'Enum', -\strlen('Enum')) === 0) {
+ return \true;
+ }
+ }
+ return \false;
}
}
diff --git a/rules/DeadCode/Rector/ClassLike/RemoveAnnotationRector.php b/rules/DeadCode/Rector/ClassLike/RemoveAnnotationRector.php
index 572fd71e0474..019c68335111 100644
--- a/rules/DeadCode/Rector/ClassLike/RemoveAnnotationRector.php
+++ b/rules/DeadCode/Rector/ClassLike/RemoveAnnotationRector.php
@@ -20,15 +20,15 @@
*/
final class RemoveAnnotationRector extends AbstractRector implements ConfigurableRectorInterface
{
- /**
- * @var string[]
- */
- private $annotationsToRemove = [];
/**
* @readonly
* @var \Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTagRemover
*/
private $phpDocTagRemover;
+ /**
+ * @var string[]
+ */
+ private $annotationsToRemove = [];
public function __construct(PhpDocTagRemover $phpDocTagRemover)
{
$this->phpDocTagRemover = $phpDocTagRemover;
diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveDelegatingParentCallRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveDelegatingParentCallRector.php
deleted file mode 100644
index 7008e27d2e18..000000000000
--- a/rules/DeadCode/Rector/ClassMethod/RemoveDelegatingParentCallRector.php
+++ /dev/null
@@ -1,165 +0,0 @@
-currentAndParentClassMethodComparator = $currentAndParentClassMethodComparator;
- $this->phpAttributeAnalyzer = $phpAttributeAnalyzer;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Removed dead parent call, that does not change anything', [new CodeSample(<<<'CODE_SAMPLE'
-class SomeClass
-{
- public function prettyPrint(array $stmts): string
- {
- return parent::prettyPrint($stmts);
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-class SomeClass
-{
-}
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [ClassMethod::class];
- }
- /**
- * @param ClassMethod $node
- */
- public function refactorWithScope(Node $node, Scope $scope) : ?Node
- {
- $classLike = $this->betterNodeFinder->findParentType($node, Class_::class);
- if ($this->shouldSkipClass($classLike)) {
- return null;
- }
- $onlyStmt = $this->matchClassMethodOnlyStmt($node);
- if ($onlyStmt === null) {
- return null;
- }
- // are both return?
- if ($this->isMethodReturnType($node, 'void') && !$onlyStmt instanceof Return_) {
- return null;
- }
- $staticCall = $this->matchStaticCall($onlyStmt);
- if (!$staticCall instanceof StaticCall) {
- return null;
- }
- if (!$this->currentAndParentClassMethodComparator->isParentCallMatching($node, $staticCall, $scope)) {
- return null;
- }
- if ($this->shouldSkipWithAnnotationsOrAttributes($node)) {
- return null;
- }
- // the method is just delegation, nothing extra
- $this->removeNode($node);
- return null;
- }
- private function shouldSkipClass(?ClassLike $classLike) : bool
- {
- if (!$classLike instanceof Class_) {
- return \true;
- }
- return !$classLike->extends instanceof Name;
- }
- private function isMethodReturnType(ClassMethod $classMethod, string $type) : bool
- {
- if ($classMethod->returnType === null) {
- return \false;
- }
- return $this->isName($classMethod->returnType, $type);
- }
- /**
- * @param \PhpParser\Node\Expr|\PhpParser\Node\Stmt $node
- */
- private function matchStaticCall($node) : ?StaticCall
- {
- // must be static call
- if ($node instanceof Return_) {
- if ($node->expr instanceof StaticCall) {
- return $node->expr;
- }
- return null;
- }
- if ($node instanceof StaticCall) {
- return $node;
- }
- return null;
- }
- private function shouldSkipWithAnnotationsOrAttributes(ClassMethod $classMethod) : bool
- {
- $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod);
- if ($phpDocInfo->hasByNames(self::ALLOWED_ANNOTATIONS)) {
- return \true;
- }
- return $this->phpAttributeAnalyzer->hasPhpAttributes($classMethod, self::ALLOWED_ATTRIBUTES);
- }
- /**
- * @return null|\PhpParser\Node\Stmt|\PhpParser\Node\Expr
- */
- private function matchClassMethodOnlyStmt(ClassMethod $classMethod)
- {
- $classMethodStmts = $classMethod->stmts;
- if ($classMethodStmts === null) {
- return null;
- }
- if (\count($classMethodStmts) !== 1) {
- return null;
- }
- // recount empty notes
- $stmtsValues = \array_values($classMethodStmts);
- $stmtValue = $stmtsValues[0];
- if ($stmtValue instanceof Expression) {
- return $stmtValue->expr;
- }
- return $stmtValue;
- }
-}
diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveEmptyClassMethodRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveEmptyClassMethodRector.php
index 9f15b1027cd5..59a88a8780a0 100644
--- a/rules/DeadCode/Rector/ClassMethod/RemoveEmptyClassMethodRector.php
+++ b/rules/DeadCode/Rector/ClassMethod/RemoveEmptyClassMethodRector.php
@@ -62,33 +62,39 @@ class OrphanClass
*/
public function getNodeTypes() : array
{
- return [ClassMethod::class];
+ return [Class_::class];
}
/**
- * @param ClassMethod $node
+ * @param Class_ $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactor(Node $node) : ?Class_
{
- $classLike = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$classLike instanceof Class_) {
- return null;
+ $hasChanged = \false;
+ foreach ($node->stmts as $key => $stmt) {
+ if (!$stmt instanceof ClassMethod) {
+ continue;
+ }
+ if ($stmt->stmts !== null && $stmt->stmts !== []) {
+ continue;
+ }
+ if ($stmt->isAbstract()) {
+ continue;
+ }
+ if ($stmt->isFinal() && !$node->isFinal()) {
+ continue;
+ }
+ if ($this->shouldSkipNonFinalNonPrivateClassMethod($node, $stmt)) {
+ continue;
+ }
+ if ($this->shouldSkipClassMethod($node, $stmt)) {
+ continue;
+ }
+ unset($node->stmts[$key]);
+ $hasChanged = \true;
}
- if ($node->stmts !== null && $node->stmts !== []) {
- return null;
+ if ($hasChanged) {
+ return $node;
}
- if ($node->isAbstract()) {
- return null;
- }
- if ($node->isFinal() && !$classLike->isFinal()) {
- return null;
- }
- if ($this->shouldSkipNonFinalNonPrivateClassMethod($classLike, $node)) {
- return null;
- }
- if ($this->shouldSkipClassMethod($classLike, $node)) {
- return null;
- }
- $this->removeNode($node);
return null;
}
private function shouldSkipNonFinalNonPrivateClassMethod(Class_ $class, ClassMethod $classMethod) : bool
@@ -115,12 +121,11 @@ private function shouldSkipClassMethod(Class_ $class, ClassMethod $classMethod)
if ($this->paramAnalyzer->hasPropertyPromotion($classMethod->params)) {
return \true;
}
- if ($this->controllerClassMethodManipulator->isControllerClassMethodWithBehaviorAnnotation($classMethod)) {
+ if ($this->controllerClassMethodManipulator->isControllerClassMethodWithBehaviorAnnotation($class, $classMethod)) {
return \true;
}
if ($this->nodeNameResolver->isName($classMethod, MethodName::CONSTRUCT)) {
- $class = $this->betterNodeFinder->findParentType($classMethod, Class_::class);
- return $class instanceof Class_ && $class->extends instanceof FullyQualified;
+ return $class->extends instanceof FullyQualified;
}
return $this->nodeNameResolver->isName($classMethod, MethodName::INVOKE);
}
diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveLastReturnRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveLastReturnRector.php
deleted file mode 100644
index 6c16f66c152f..000000000000
--- a/rules/DeadCode/Rector/ClassMethod/RemoveLastReturnRector.php
+++ /dev/null
@@ -1,83 +0,0 @@
-contextAnalyzer = $contextAnalyzer;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Remove very last `return` that has no meaning', [new CodeSample(<<<'CODE_SAMPLE'
-function some_function($value)
-{
- if ($value === 1000) {
- return;
- }
-
- if ($value) {
- return;
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-function some_function($value)
-{
- if ($value === 1000) {
- return;
- }
-
- if ($value) {
- }
-}
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [ClassMethod::class, Function_::class, Closure::class];
- }
- /**
- * @param ClassMethod|Function_ $node
- */
- public function refactor(Node $node) : ?Node
- {
- // last node and last return
- $lastNode = $this->betterNodeFinder->findLastInstanceOf((array) $node->stmts, Node::class);
- $lastReturn = $this->betterNodeFinder->findLastInstanceOf((array) $node->stmts, Return_::class);
- if (!$lastReturn instanceof Return_) {
- return null;
- }
- if ($lastNode !== $lastReturn) {
- return null;
- }
- if ($this->contextAnalyzer->isInLoop($lastReturn)) {
- return null;
- }
- $this->removeNode($lastReturn);
- return null;
- }
-}
diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPrivateMethodRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPrivateMethodRector.php
index 137d5a6f862a..2d229782bc7b 100644
--- a/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPrivateMethodRector.php
+++ b/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPrivateMethodRector.php
@@ -78,19 +78,22 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
if ($this->hasDynamicMethodCallOnFetchThis($node)) {
return null;
}
+ if ($node->getMethods() === []) {
+ return null;
+ }
$hasChanged = \false;
- $classReflection = null;
- foreach ($node->getMethods() as $classMethod) {
- if (!$classReflection instanceof ClassReflection) {
- $classReflection = $this->reflectionResolver->resolveClassReflection($classMethod);
+ $classReflection = $this->reflectionResolver->resolveClassReflection($node);
+ foreach ($node->stmts as $key => $stmt) {
+ if (!$stmt instanceof ClassMethod) {
+ continue;
}
- if ($this->shouldSkip($classMethod, $classReflection)) {
+ if ($this->shouldSkip($stmt, $classReflection)) {
continue;
}
- if ($this->isClassMethodUsedAnalyzer->isClassMethodUsed($node, $classMethod, $scope)) {
+ if ($this->isClassMethodUsedAnalyzer->isClassMethodUsed($node, $stmt, $scope)) {
continue;
}
- $this->removeNode($classMethod);
+ unset($node->stmts[$key]);
$hasChanged = \true;
}
if ($hasChanged) {
diff --git a/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPromotedPropertyRector.php b/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPromotedPropertyRector.php
index c548c7695a41..385ba1b03805 100644
--- a/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPromotedPropertyRector.php
+++ b/rules/DeadCode/Rector/ClassMethod/RemoveUnusedPromotedPropertyRector.php
@@ -7,13 +7,14 @@
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
+use PhpParser\Node\Stmt\TraitUse;
use PHPStan\Analyser\Scope;
-use Rector\Core\NodeManipulator\PropertyManipulator;
use Rector\Core\PhpParser\NodeFinder\PropertyFetchFinder;
use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\MethodName;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\Core\ValueObject\Visibility;
+use Rector\DeadCode\NodeAnalyzer\PropertyWriteonlyAnalyzer;
use Rector\Privatization\NodeManipulator\VisibilityManipulator;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -30,19 +31,19 @@ final class RemoveUnusedPromotedPropertyRector extends AbstractScopeAwareRector
private $propertyFetchFinder;
/**
* @readonly
- * @var \Rector\Core\NodeManipulator\PropertyManipulator
+ * @var \Rector\Privatization\NodeManipulator\VisibilityManipulator
*/
- private $propertyManipulator;
+ private $visibilityManipulator;
/**
* @readonly
- * @var \Rector\Privatization\NodeManipulator\VisibilityManipulator
+ * @var \Rector\DeadCode\NodeAnalyzer\PropertyWriteonlyAnalyzer
*/
- private $visibilityManipulator;
- public function __construct(PropertyFetchFinder $propertyFetchFinder, PropertyManipulator $propertyManipulator, VisibilityManipulator $visibilityManipulator)
+ private $propertyWriteonlyAnalyzer;
+ public function __construct(PropertyFetchFinder $propertyFetchFinder, VisibilityManipulator $visibilityManipulator, PropertyWriteonlyAnalyzer $propertyWriteonlyAnalyzer)
{
$this->propertyFetchFinder = $propertyFetchFinder;
- $this->propertyManipulator = $propertyManipulator;
$this->visibilityManipulator = $visibilityManipulator;
+ $this->propertyWriteonlyAnalyzer = $propertyWriteonlyAnalyzer;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -93,24 +94,23 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
if (!$constructClassMethod instanceof ClassMethod) {
return null;
}
- // is attribute? skip it
- if ($node->attrGroups !== []) {
+ if ($this->shouldSkipClass($node)) {
return null;
}
- $hasRemovedProperty = \false;
- foreach ($constructClassMethod->getParams() as $param) {
+ $hasChanged = \false;
+ foreach ($constructClassMethod->params as $key => $param) {
// only private local scope; removing public property might be dangerous
if (!$this->visibilityManipulator->hasVisibility($param, Visibility::PRIVATE)) {
continue;
}
- if ($this->propertyManipulator->isPropertyUsedInReadContext($node, $param, $scope)) {
- continue;
- }
$paramName = $this->getName($param);
$propertyFetches = $this->propertyFetchFinder->findLocalPropertyFetchesByName($node, $paramName);
if ($propertyFetches !== []) {
continue;
}
+ if (!$this->propertyWriteonlyAnalyzer->arePropertyFetchesExclusivelyBeingAssignedTo($propertyFetches)) {
+ continue;
+ }
// is variable used? only remove property, keep param
$variable = $this->betterNodeFinder->findVariableOfName((array) $constructClassMethod->stmts, $paramName);
if ($variable instanceof Variable) {
@@ -118,10 +118,10 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
continue;
}
// remove param
- $this->removeNode($param);
- $hasRemovedProperty = \true;
+ unset($constructClassMethod->params[$key]);
+ $hasChanged = \true;
}
- if ($hasRemovedProperty) {
+ if ($hasChanged) {
return $node;
}
return null;
@@ -130,4 +130,16 @@ public function provideMinPhpVersion() : int
{
return PhpVersionFeature::PROPERTY_PROMOTION;
}
+ private function shouldSkipClass(Class_ $class) : bool
+ {
+ if ($class->attrGroups !== []) {
+ return \true;
+ }
+ foreach ($class->stmts as $stmt) {
+ if ($stmt instanceof TraitUse) {
+ return \true;
+ }
+ }
+ return \false;
+ }
}
diff --git a/rules/DeadCode/Rector/Class_/TargetRemoveClassMethodRector.php b/rules/DeadCode/Rector/Class_/TargetRemoveClassMethodRector.php
deleted file mode 100644
index c25446b4b9af..000000000000
--- a/rules/DeadCode/Rector/Class_/TargetRemoveClassMethodRector.php
+++ /dev/null
@@ -1,85 +0,0 @@
-classAnalyzer = $classAnalyzer;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Remove defined class method', [new ConfiguredCodeSample(<<<'CODE_SAMPLE'
-class SomeClass
-{
- public function run()
- {
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-class SomeClass
-{
-}
-CODE_SAMPLE
-, [new TargetRemoveClassMethod('SomeClass', 'run')])]);
- }
- public function getNodeTypes() : array
- {
- return [Class_::class];
- }
- /**
- * @param Class_ $node
- */
- public function refactor(Node $node) : ?Node
- {
- if ($this->classAnalyzer->isAnonymousClass($node)) {
- return null;
- }
- foreach ($this->targetRemoveClassMethods as $targetRemoveClassMethod) {
- if (!$this->isName($node, $targetRemoveClassMethod->getClassName())) {
- continue;
- }
- $classMethod = $node->getMethod($targetRemoveClassMethod->getMethodName());
- if (!$classMethod instanceof ClassMethod) {
- continue;
- }
- $this->removeNode($classMethod);
- return null;
- }
- return null;
- }
- /**
- * @param mixed[] $configuration
- */
- public function configure(array $configuration) : void
- {
- Assert::notEmpty($configuration);
- Assert::allIsInstanceOf($configuration, TargetRemoveClassMethod::class);
- $this->targetRemoveClassMethods = $configuration;
- }
-}
diff --git a/rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php b/rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php
index 3315c316e875..4b8eee66ab1e 100644
--- a/rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php
+++ b/rules/DeadCode/Rector/ConstFetch/RemovePhpVersionIdCheckRector.php
@@ -12,52 +12,34 @@
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\If_;
-use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
+use PhpParser\NodeTraverser;
use Rector\Core\Php\PhpVersionProvider;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersion;
-use ReflectionClass;
-use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
+use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
-use RectorPrefix202306\Webmozart\Assert\Assert;
/**
* @see \Rector\Tests\DeadCode\Rector\ConstFetch\RemovePhpVersionIdCheckRector\RemovePhpVersionIdCheckRectorTest
*/
-final class RemovePhpVersionIdCheckRector extends AbstractRector implements ConfigurableRectorInterface
+final class RemovePhpVersionIdCheckRector extends AbstractRector
{
- /**
- * @var PhpVersion::*|null
- */
- private $phpVersion = null;
/**
* @readonly
* @var \Rector\Core\Php\PhpVersionProvider
*/
private $phpVersionProvider;
- public function __construct(PhpVersionProvider $phpVersionProvider)
- {
- $this->phpVersionProvider = $phpVersionProvider;
- }
/**
- * @param mixed[] $configuration
+ * @var PhpVersion::*|null
*/
- public function configure(array $configuration) : void
+ private $phpVersion = null;
+ public function __construct(PhpVersionProvider $phpVersionProvider)
{
- $phpVersion = $configuration[0];
- Assert::integer($phpVersion);
- // get all constants
- $phpVersionReflectionClass = new ReflectionClass(PhpVersion::class);
- // @todo check
- if (\in_array($phpVersion, $phpVersionReflectionClass->getConstants(), \true)) {
- return;
- }
- // ensure cast to (string) first to allow string like "8.0" value to be converted to the int value
- /** @var PhpVersion::* $phpVersion */
- $this->phpVersion = $phpVersion;
+ $this->phpVersionProvider = $phpVersionProvider;
+ $this->phpVersion = $this->phpVersionProvider->provide();
}
public function getRuleDefinition() : RuleDefinition
{
- return new RuleDefinition('Remove unneeded PHP_VERSION_ID conditional checks', [new ConfiguredCodeSample(<<<'CODE_SAMPLE'
+ return new RuleDefinition('Remove unneeded PHP_VERSION_ID conditional checks', [new CodeSample(<<<'CODE_SAMPLE'
class SomeClass
{
public function run()
@@ -79,7 +61,7 @@ public function run()
}
}
CODE_SAMPLE
-, [PhpVersion::PHP_80])]);
+)]);
}
/**
* @return array>
@@ -90,7 +72,7 @@ public function getNodeTypes() : array
}
/**
* @param If_ $node
- * @return null|If_|Stmt[]
+ * @return null|int|Stmt[]
*/
public function refactor(Node $node)
{
@@ -116,47 +98,46 @@ public function refactor(Node $node)
return $this->refactorConstFetch($binaryOp->right, $node, $binaryOp);
}
/**
- * @return null|If_|Stmt[]
+ * @return null|Stmt[]|int
*/
- private function processSmaller(ConstFetch $constFetch, Smaller $smaller, If_ $if)
+ private function refactorSmaller(ConstFetch $constFetch, Smaller $smaller, If_ $if)
{
if ($smaller->left === $constFetch) {
- return $this->processSmallerLeft($smaller, $if);
+ return $this->refactorSmallerLeft($smaller);
}
if ($smaller->right === $constFetch) {
- return $this->processSmallerRight($smaller, $if);
+ return $this->refactorSmallerRight($smaller, $if);
}
return null;
}
/**
- * @return null|If_|Stmt[]
+ * @return null|int|Stmt[]
*/
private function processGreaterOrEqual(ConstFetch $constFetch, GreaterOrEqual $greaterOrEqual, If_ $if)
{
if ($greaterOrEqual->left === $constFetch) {
- return $this->processGreaterOrEqualLeft($greaterOrEqual, $if);
+ return $this->refactorGreaterOrEqualLeft($greaterOrEqual, $if);
}
if ($greaterOrEqual->right === $constFetch) {
- return $this->processGreaterOrEqualRight($greaterOrEqual, $if);
+ return $this->refactorGreaterOrEqualRight($greaterOrEqual);
}
return null;
}
- private function processSmallerLeft(Smaller $smaller, If_ $if) : ?If_
+ private function refactorSmallerLeft(Smaller $smaller) : ?int
{
$value = $smaller->right;
if (!$value instanceof LNumber) {
return null;
}
if ($this->phpVersion >= $value->value) {
- $this->removeNode($if);
- return $if;
+ return NodeTraverser::REMOVE_NODE;
}
return null;
}
/**
- * @return null|If_|Stmt[]
+ * @return null|Stmt[]|int
*/
- private function processSmallerRight(Smaller $smaller, If_ $if)
+ private function refactorSmallerRight(Smaller $smaller, If_ $if)
{
$value = $smaller->left;
if (!$value instanceof LNumber) {
@@ -166,15 +147,14 @@ private function processSmallerRight(Smaller $smaller, If_ $if)
return null;
}
if ($if->stmts === []) {
- $this->removeNode($if);
- return $if;
+ return NodeTraverser::REMOVE_NODE;
}
return $if->stmts;
}
/**
- * @return null|If_|Stmt[]
+ * @return null|Stmt[]|int
*/
- private function processGreaterOrEqualLeft(GreaterOrEqual $greaterOrEqual, If_ $if)
+ private function refactorGreaterOrEqualLeft(GreaterOrEqual $greaterOrEqual, If_ $if)
{
$value = $greaterOrEqual->right;
if (!$value instanceof LNumber) {
@@ -184,40 +164,38 @@ private function processGreaterOrEqualLeft(GreaterOrEqual $greaterOrEqual, If_ $
return null;
}
if ($if->stmts === []) {
- $this->removeNode($if);
- return $if;
+ return NodeTraverser::REMOVE_NODE;
}
return $if->stmts;
}
- private function processGreaterOrEqualRight(GreaterOrEqual $greaterOrEqual, If_ $if) : ?If_
+ private function refactorGreaterOrEqualRight(GreaterOrEqual $greaterOrEqual) : ?int
{
$value = $greaterOrEqual->left;
if (!$value instanceof LNumber) {
return null;
}
if ($this->phpVersion >= $value->value) {
- $this->removeNode($if);
- return $if;
+ return NodeTraverser::REMOVE_NODE;
}
return null;
}
/**
- * @return null|If_|Stmt[]
+ * @return null|Stmt[]|int
*/
- private function processGreater(ConstFetch $constFetch, Greater $greater, If_ $if)
+ private function refactorGreater(ConstFetch $constFetch, Greater $greater, If_ $if)
{
if ($greater->left === $constFetch) {
- return $this->processGreaterLeft($greater, $if);
+ return $this->refactorGreaterLeft($greater, $if);
}
if ($greater->right === $constFetch) {
- return $this->processGreaterRight($greater, $if);
+ return $this->refactorGreaterRight($greater);
}
return null;
}
/**
- * @return null|If_|Stmt[]
+ * @return null|Stmt[]|int
*/
- private function processGreaterLeft(Greater $greater, If_ $if)
+ private function refactorGreaterLeft(Greater $greater, If_ $if)
{
$value = $greater->right;
if (!$value instanceof LNumber) {
@@ -227,36 +205,34 @@ private function processGreaterLeft(Greater $greater, If_ $if)
return null;
}
if ($if->stmts === []) {
- $this->removeNode($if);
- return $if;
+ return NodeTraverser::REMOVE_NODE;
}
return $if->stmts;
}
- private function processGreaterRight(Greater $greater, If_ $if) : ?If_
+ private function refactorGreaterRight(Greater $greater) : ?int
{
$value = $greater->left;
if (!$value instanceof LNumber) {
return null;
}
if ($this->phpVersion >= $value->value) {
- $this->removeNode($if);
- return $if;
+ return NodeTraverser::REMOVE_NODE;
}
return null;
}
/**
- * @return null|If_|Stmt[]
+ * @return null|Stmt[]|int
*/
private function refactorConstFetch(ConstFetch $constFetch, If_ $if, BinaryOp $binaryOp)
{
if ($binaryOp instanceof Smaller) {
- return $this->processSmaller($constFetch, $binaryOp, $if);
+ return $this->refactorSmaller($constFetch, $binaryOp, $if);
}
if ($binaryOp instanceof GreaterOrEqual) {
return $this->processGreaterOrEqual($constFetch, $binaryOp, $if);
}
if ($binaryOp instanceof Greater) {
- return $this->processGreater($constFetch, $binaryOp, $if);
+ return $this->refactorGreater($constFetch, $binaryOp, $if);
}
return null;
}
diff --git a/rules/DeadCode/Rector/Expression/RemoveDeadStmtRector.php b/rules/DeadCode/Rector/Expression/RemoveDeadStmtRector.php
index dedbb1ebab5f..9789b0c1b273 100644
--- a/rules/DeadCode/Rector/Expression/RemoveDeadStmtRector.php
+++ b/rules/DeadCode/Rector/Expression/RemoveDeadStmtRector.php
@@ -8,6 +8,7 @@
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Nop;
+use PhpParser\NodeTraverser;
use PHPStan\Reflection\Php\PhpPropertyReflection;
use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
use Rector\Core\Rector\AbstractRector;
@@ -62,7 +63,7 @@ public function getNodeTypes() : array
}
/**
* @param Expression $node
- * @return Node[]|Node|null
+ * @return Node[]|Node|null|int
*/
public function refactor(Node $node)
{
@@ -98,7 +99,10 @@ private function hasGetMagic(Expression $expression) : bool
*/
return !$phpPropertyReflection instanceof PhpPropertyReflection;
}
- private function removeNodeAndKeepComments(Expression $expression) : ?Node
+ /**
+ * @return int|\PhpParser\Node
+ */
+ private function removeNodeAndKeepComments(Expression $expression)
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($expression);
if ($expression->getComments() !== []) {
@@ -106,7 +110,6 @@ private function removeNodeAndKeepComments(Expression $expression) : ?Node
$nop->setAttribute(AttributeKey::PHP_DOC_INFO, $phpDocInfo);
return $nop;
}
- $this->removeNode($expression);
- return null;
+ return NodeTraverser::REMOVE_NODE;
}
}
diff --git a/rules/DeadCode/Rector/Expression/SimplifyMirrorAssignRector.php b/rules/DeadCode/Rector/Expression/SimplifyMirrorAssignRector.php
index 9af3f064d590..4dd791978fef 100644
--- a/rules/DeadCode/Rector/Expression/SimplifyMirrorAssignRector.php
+++ b/rules/DeadCode/Rector/Expression/SimplifyMirrorAssignRector.php
@@ -6,6 +6,7 @@
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Stmt\Expression;
+use PhpParser\NodeTraverser;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@@ -37,16 +38,15 @@ public function getNodeTypes() : array
/**
* @param Expression $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactor(Node $node) : ?int
{
if (!$node->expr instanceof Assign) {
return null;
}
- /** @var Assign $assignNode */
- $assignNode = $node->expr;
- if ($this->nodeComparator->areNodesEqual($assignNode->var, $assignNode->expr)) {
- $this->removeNode($node);
+ $assign = $node->expr;
+ if (!$this->nodeComparator->areNodesEqual($assign->var, $assign->expr)) {
+ return null;
}
- return null;
+ return NodeTraverser::REMOVE_NODE;
}
}
diff --git a/rules/DeadCode/Rector/For_/RemoveDeadIfForeachForRector.php b/rules/DeadCode/Rector/For_/RemoveDeadIfForeachForRector.php
index e95d5059af45..122b4bf68425 100644
--- a/rules/DeadCode/Rector/For_/RemoveDeadIfForeachForRector.php
+++ b/rules/DeadCode/Rector/For_/RemoveDeadIfForeachForRector.php
@@ -5,12 +5,13 @@
use PhpParser\Node;
use PhpParser\Node\Expr;
-use PhpParser\Node\Expr\Variable;
-use PhpParser\Node\Scalar;
+use PhpParser\Node\Expr\Assign;
+use PhpParser\Node\Expr\CallLike;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\For_;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\If_;
+use PhpParser\NodeTraverser;
use Rector\Core\Rector\AbstractRector;
use Rector\EarlyReturn\NodeTransformer\ConditionInverter;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -34,15 +35,11 @@ public function getRuleDefinition() : RuleDefinition
return new RuleDefinition('Remove if, foreach and for that does not do anything', [new CodeSample(<<<'CODE_SAMPLE'
class SomeClass
{
- public function run($someObject)
+ public function run($value)
{
- $value = 5;
if ($value) {
}
- if ($someObject->run()) {
- }
-
foreach ($values as $value) {
}
@@ -53,12 +50,8 @@ public function run($someObject)
, <<<'CODE_SAMPLE'
class SomeClass
{
- public function run($someObject)
+ public function run($value)
{
- $value = 5;
- if ($someObject->run()) {
- }
-
return $value;
}
}
@@ -74,61 +67,37 @@ public function getNodeTypes() : array
}
/**
* @param For_|If_|Foreach_ $node
+ * @return \PhpParser\Node|null|int
*/
- public function refactor(Node $node) : ?Node
+ public function refactor(Node $node)
{
if ($node instanceof If_) {
- $this->processIf($node);
- return null;
- }
- if ($node instanceof Foreach_) {
- $this->processForeach($node);
- return null;
+ if ($node->stmts !== []) {
+ return null;
+ }
+ if ($node->elseifs !== []) {
+ return null;
+ }
+ // useless if ()
+ if (!$node->else instanceof Else_) {
+ if ($this->hasNodeSideEffect($node->cond)) {
+ return null;
+ }
+ return NodeTraverser::REMOVE_NODE;
+ }
+ $node->cond = $this->conditionInverter->createInvertedCondition($node->cond);
+ $node->stmts = $node->else->stmts;
+ $node->else = null;
+ return $node;
}
- // For
- if ($node->stmts !== []) {
- return null;
+ // nothing to "for"
+ if ($node->stmts === []) {
+ return NodeTraverser::REMOVE_NODE;
}
- $this->removeNode($node);
return null;
}
- private function processIf(If_ $if) : void
+ private function hasNodeSideEffect(Expr $expr) : bool
{
- if ($if->stmts !== []) {
- return;
- }
- if ($if->elseifs !== []) {
- return;
- }
- if ($if->else instanceof Else_) {
- $if->cond = $this->conditionInverter->createInvertedCondition($if->cond);
- $if->stmts = $if->else->stmts;
- $if->else = null;
- return;
- }
- if ($this->isNodeWithSideEffect($if->cond)) {
- return;
- }
- $this->removeNode($if);
- }
- private function processForeach(Foreach_ $foreach) : void
- {
- if ($foreach->stmts !== []) {
- return;
- }
- if ($this->isNodeWithSideEffect($foreach->expr)) {
- return;
- }
- $this->removeNode($foreach);
- }
- private function isNodeWithSideEffect(Expr $expr) : bool
- {
- if ($expr instanceof Variable) {
- return \false;
- }
- if ($expr instanceof Scalar) {
- return \false;
- }
- return !$this->valueResolver->isTrueOrFalse($expr);
+ return $this->betterNodeFinder->hasInstancesOf($expr, [CallLike::class, Assign::class]);
}
}
diff --git a/rules/DeadCode/Rector/For_/RemoveDeadLoopRector.php b/rules/DeadCode/Rector/For_/RemoveDeadLoopRector.php
index 6f5c8f0bf4ca..9ac39423b490 100644
--- a/rules/DeadCode/Rector/For_/RemoveDeadLoopRector.php
+++ b/rules/DeadCode/Rector/For_/RemoveDeadLoopRector.php
@@ -8,6 +8,7 @@
use PhpParser\Node\Stmt\For_;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\While_;
+use PhpParser\NodeTraverser;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@@ -48,12 +49,11 @@ public function getNodeTypes() : array
/**
* @param Do_|For_|Foreach_|While_ $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactor(Node $node) : ?int
{
if ($node->stmts !== []) {
return null;
}
- $this->removeNode($node);
- return null;
+ return NodeTraverser::REMOVE_NODE;
}
}
diff --git a/rules/DeadCode/Rector/FunctionLike/RemoveDeadReturnRector.php b/rules/DeadCode/Rector/FunctionLike/RemoveDeadReturnRector.php
index f3bb1547b1be..48dabaa49e6a 100644
--- a/rules/DeadCode/Rector/FunctionLike/RemoveDeadReturnRector.php
+++ b/rules/DeadCode/Rector/FunctionLike/RemoveDeadReturnRector.php
@@ -7,7 +7,9 @@
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Stmt\ClassMethod;
+use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\Function_;
+use PhpParser\Node\Stmt\If_;
use PhpParser\Node\Stmt\Return_;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -61,21 +63,43 @@ public function getNodeTypes() : array
*/
public function refactor(Node $node) : ?Node
{
- if ($node->stmts === []) {
+ if ($node->stmts === [] || $node->stmts === null) {
return null;
}
- if ($node->stmts === null) {
- return null;
+ \end($node->stmts);
+ $lastStmtKey = \key($node->stmts);
+ $lastStmt = $node->stmts[$lastStmtKey];
+ if ($lastStmt instanceof If_) {
+ if (!$this->isBareIfWithOnlyStmtEmptyReturn($lastStmt)) {
+ return null;
+ }
+ $lastStmt->stmts = [];
+ return $node;
}
- $stmtValues = \array_values($node->stmts);
- $lastStmt = \end($stmtValues);
if (!$lastStmt instanceof Return_) {
return null;
}
if ($lastStmt->expr instanceof Expr) {
return null;
}
- $this->removeNode($lastStmt);
+ unset($node->stmts[$lastStmtKey]);
return $node;
}
+ private function isBareIfWithOnlyStmtEmptyReturn(If_ $if) : bool
+ {
+ if ($if->else instanceof Else_) {
+ return \false;
+ }
+ if ($if->elseifs !== []) {
+ return \false;
+ }
+ if (\count($if->stmts) !== 1) {
+ return \false;
+ }
+ $onlyStmt = $if->stmts[0];
+ if (!$onlyStmt instanceof Return_) {
+ return \false;
+ }
+ return !$onlyStmt->expr instanceof Expr;
+ }
}
diff --git a/rules/DeadCode/Rector/If_/RemoveAlwaysTrueIfConditionRector.php b/rules/DeadCode/Rector/If_/RemoveAlwaysTrueIfConditionRector.php
index 2cacba14def7..bd193543efae 100644
--- a/rules/DeadCode/Rector/If_/RemoveAlwaysTrueIfConditionRector.php
+++ b/rules/DeadCode/Rector/If_/RemoveAlwaysTrueIfConditionRector.php
@@ -12,6 +12,7 @@
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\If_;
+use PhpParser\NodeTraverser;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\Constant\ConstantBooleanType;
use Rector\Core\NodeAnalyzer\ExprAnalyzer;
@@ -76,7 +77,7 @@ public function getNodeTypes() : array
}
/**
* @param If_ $node
- * @return If_|null|Stmt[]
+ * @return int|null|Stmt[]
*/
public function refactor(Node $node)
{
@@ -105,8 +106,7 @@ public function refactor(Node $node)
return null;
}
if ($node->stmts === []) {
- $this->removeNode($node);
- return null;
+ return NodeTraverser::REMOVE_NODE;
}
return $node->stmts;
}
diff --git a/rules/DeadCode/Rector/If_/RemoveDeadInstanceOfRector.php b/rules/DeadCode/Rector/If_/RemoveDeadInstanceOfRector.php
index 14a25b0167b2..67231692cf52 100644
--- a/rules/DeadCode/Rector/If_/RemoveDeadInstanceOfRector.php
+++ b/rules/DeadCode/Rector/If_/RemoveDeadInstanceOfRector.php
@@ -5,25 +5,18 @@
use PhpParser\Node;
use PhpParser\Node\Expr;
-use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BooleanNot;
+use PhpParser\Node\Expr\CallLike;
use PhpParser\Node\Expr\Instanceof_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticPropertyFetch;
-use PhpParser\Node\Expr\Variable;
-use PhpParser\Node\FunctionLike;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
-use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\If_;
-use PhpParser\Node\Stmt\Property;
-use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
+use PhpParser\NodeTraverser;
+use PHPStan\Type\MixedType;
use Rector\Core\NodeManipulator\IfManipulator;
use Rector\Core\Rector\AbstractRector;
-use Rector\NodeNestingScope\ContextAnalyzer;
-use Rector\NodeTypeResolver\Node\AttributeKey;
-use Rector\Php80\NodeAnalyzer\PromotedPropertyResolver;
-use Rector\TypeDeclaration\AlreadyAssignDetector\ConstructorAssignDetector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
@@ -36,56 +29,26 @@ final class RemoveDeadInstanceOfRector extends AbstractRector
* @var \Rector\Core\NodeManipulator\IfManipulator
*/
private $ifManipulator;
- /**
- * @readonly
- * @var \Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer
- */
- private $propertyFetchAnalyzer;
- /**
- * @readonly
- * @var \Rector\TypeDeclaration\AlreadyAssignDetector\ConstructorAssignDetector
- */
- private $constructorAssignDetector;
- /**
- * @readonly
- * @var \Rector\Php80\NodeAnalyzer\PromotedPropertyResolver
- */
- private $promotedPropertyResolver;
- /**
- * @readonly
- * @var \Rector\NodeNestingScope\ContextAnalyzer
- */
- private $contextAnalyzer;
- public function __construct(IfManipulator $ifManipulator, PropertyFetchAnalyzer $propertyFetchAnalyzer, ConstructorAssignDetector $constructorAssignDetector, PromotedPropertyResolver $promotedPropertyResolver, ContextAnalyzer $contextAnalyzer)
+ public function __construct(IfManipulator $ifManipulator)
{
$this->ifManipulator = $ifManipulator;
- $this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
- $this->constructorAssignDetector = $constructorAssignDetector;
- $this->promotedPropertyResolver = $promotedPropertyResolver;
- $this->contextAnalyzer = $contextAnalyzer;
}
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Remove dead instanceof check on type hinted variable', [new CodeSample(<<<'CODE_SAMPLE'
-final class SomeClass
+function run(stdClass $stdClass)
{
- public function go(stdClass $stdClass)
- {
- if (! $stdClass instanceof stdClass) {
- return false;
- }
-
- return true;
+ if (! $stdClass instanceof stdClass) {
+ return false;
}
+
+ return true;
}
CODE_SAMPLE
, <<<'CODE_SAMPLE'
-final class SomeClass
+function run(stdClass $stdClass)
{
- public function go(stdClass $stdClass)
- {
- return true;
- }
+ return true;
}
CODE_SAMPLE
)]);
@@ -99,112 +62,61 @@ public function getNodeTypes() : array
}
/**
* @param If_ $node
- * @return Stmt[]|null|If_
+ * @return Stmt[]|null|int
*/
public function refactor(Node $node)
{
if (!$this->ifManipulator->isIfWithoutElseAndElseIfs($node)) {
return null;
}
- if ($this->contextAnalyzer->isInLoop($node)) {
- return null;
- }
- $originalCondNode = $node->cond->getAttribute(AttributeKey::ORIGINAL_NODE);
- if (!$originalCondNode instanceof Node) {
- return null;
- }
if ($node->cond instanceof BooleanNot && $node->cond->expr instanceof Instanceof_) {
- return $this->processMayDeadInstanceOf($node, $node->cond->expr);
+ return $this->refactorStmtAndInstanceof($node, $node->cond->expr);
}
if ($node->cond instanceof Instanceof_) {
- return $this->processMayDeadInstanceOf($node, $node->cond);
+ return $this->refactorStmtAndInstanceof($node, $node->cond);
}
return null;
}
/**
- * @return null|Stmt[]|If_
+ * @return null|Stmt[]|int
*/
- private function processMayDeadInstanceOf(If_ $if, Instanceof_ $instanceof)
+ private function refactorStmtAndInstanceof(If_ $if, Instanceof_ $instanceof)
{
if (!$instanceof->class instanceof Name) {
return null;
}
+ // handle in another rule
+ if ($this->isPropertyFetch($instanceof->expr) || $instanceof->expr instanceof CallLike) {
+ return null;
+ }
$classType = $this->nodeTypeResolver->getType($instanceof->class);
$exprType = $this->nodeTypeResolver->getType($instanceof->expr);
$isSameStaticTypeOrSubtype = $classType->equals($exprType) || $classType->isSuperTypeOf($exprType)->yes();
if (!$isSameStaticTypeOrSubtype) {
return null;
}
- if (!$instanceof->expr instanceof Variable && !$this->isInPropertyPromotedParams($instanceof->expr) && $this->isSkippedPropertyFetch($instanceof->expr)) {
- return null;
- }
if ($this->shouldSkipFromNotTypedParam($instanceof)) {
return null;
}
- if ($if->cond === $instanceof && $if->stmts !== []) {
- return $if->stmts;
+ if ($if->cond !== $instanceof) {
+ return NodeTraverser::REMOVE_NODE;
+ }
+ if ($if->stmts === []) {
+ return NodeTraverser::REMOVE_NODE;
}
- $this->removeNode($if);
- return $if;
+ // unwrap stmts
+ return $if->stmts;
}
private function shouldSkipFromNotTypedParam(Instanceof_ $instanceof) : bool
{
- $functionLike = $this->betterNodeFinder->findParentType($instanceof, FunctionLike::class);
- if (!$functionLike instanceof FunctionLike) {
- return \false;
- }
- $variable = $instanceof->expr;
- $isReAssign = (bool) $this->betterNodeFinder->findFirstPrevious($instanceof, function (Node $subNode) use($variable) : bool {
- return $subNode instanceof Assign && $this->nodeComparator->areNodesEqual($subNode->var, $variable);
- });
- if ($isReAssign) {
- return \false;
- }
- $params = $functionLike->getParams();
- foreach ($params as $param) {
- if ($this->nodeComparator->areNodesEqual($param->var, $instanceof->expr)) {
- return $param->type === null;
- }
- }
- return \false;
+ $nativeParamType = $this->nodeTypeResolver->getNativeType($instanceof->expr);
+ return $nativeParamType instanceof MixedType;
}
- private function isSkippedPropertyFetch(Expr $expr) : bool
+ private function isPropertyFetch(Expr $expr) : bool
{
- if (!$this->propertyFetchAnalyzer->isPropertyFetch($expr)) {
+ if ($expr instanceof PropertyFetch) {
return \true;
}
- /** @var PropertyFetch|StaticPropertyFetch $propertyFetch */
- $propertyFetch = $expr;
- $classLike = $this->betterNodeFinder->findParentType($propertyFetch, Class_::class);
- if (!$classLike instanceof Class_) {
- return \true;
- }
- /** @var string $propertyName */
- $propertyName = $this->nodeNameResolver->getName($propertyFetch);
- $property = $classLike->getProperty($propertyName);
- if (!$property instanceof Property) {
- return \true;
- }
- $isPropertyAssignedInConstuctor = $this->constructorAssignDetector->isPropertyAssigned($classLike, $propertyName);
- return $property->type === null && !$isPropertyAssignedInConstuctor;
- }
- private function isInPropertyPromotedParams(Expr $expr) : bool
- {
- if (!$expr instanceof PropertyFetch) {
- return \false;
- }
- $classLike = $this->betterNodeFinder->findParentType($expr, Class_::class);
- if (!$classLike instanceof Class_) {
- return \false;
- }
- /** @var string $propertyName */
- $propertyName = $this->nodeNameResolver->getName($expr);
- $params = $this->promotedPropertyResolver->resolveFromClass($classLike);
- foreach ($params as $param) {
- if ($this->nodeNameResolver->isName($param, $propertyName)) {
- return \true;
- }
- }
- return \false;
+ return $expr instanceof StaticPropertyFetch;
}
}
diff --git a/rules/DeadCode/Rector/If_/RemoveTypedPropertyDeadInstanceOfRector.php b/rules/DeadCode/Rector/If_/RemoveTypedPropertyDeadInstanceOfRector.php
new file mode 100644
index 000000000000..2cd35debcf5e
--- /dev/null
+++ b/rules/DeadCode/Rector/If_/RemoveTypedPropertyDeadInstanceOfRector.php
@@ -0,0 +1,201 @@
+ifManipulator = $ifManipulator;
+ $this->constructorAssignDetector = $constructorAssignDetector;
+ $this->promotedPropertyResolver = $promotedPropertyResolver;
+ }
+ public function getRuleDefinition() : RuleDefinition
+ {
+ return new RuleDefinition('Remove dead instanceof check on type hinted property', [new CodeSample(<<<'CODE_SAMPLE'
+final class SomeClass
+{
+ private $someObject;
+
+ public function __construct(SomeObject $someObject)
+ {
+ $this->someObject = $someObject;
+ }
+
+ public function run()
+ {
+ if ($this->someObject instanceof SomeObject) {
+ return true;
+ }
+
+ return false;
+ }
+}
+CODE_SAMPLE
+, <<<'CODE_SAMPLE'
+final class SomeClass
+{
+ private $someObject;
+
+ public function __construct(SomeObject $someObject)
+ {
+ $this->someObject = $someObject;
+ }
+
+ public function run()
+ {
+ return true;
+ }
+}
+CODE_SAMPLE
+)]);
+ }
+ /**
+ * @return array>
+ */
+ public function getNodeTypes() : array
+ {
+ return [Class_::class];
+ }
+ /**
+ * @param Class_ $node
+ */
+ public function refactor(Node $node) : ?Class_
+ {
+ $hasChanged = \false;
+ $class = $node;
+ $this->traverseNodesWithCallable($node->getMethods(), function (Node $node) use(&$hasChanged, $class) {
+ // avoid loop ifs
+ if ($node instanceof While_ || $node instanceof Foreach_ || $node instanceof For_ || $node instanceof Do_) {
+ return NodeTraverser::STOP_TRAVERSAL;
+ }
+ if (!$node instanceof If_) {
+ return null;
+ }
+ if (!$this->ifManipulator->isIfWithoutElseAndElseIfs($node)) {
+ return null;
+ }
+ if ($node->cond instanceof BooleanNot && $node->cond->expr instanceof Instanceof_) {
+ $result = $this->refactorStmtAndInstanceof($class, $node, $node->cond->expr);
+ if ($result !== null) {
+ $hasChanged = \true;
+ return $result;
+ }
+ }
+ if ($node->cond instanceof Instanceof_) {
+ $result = $this->refactorStmtAndInstanceof($class, $node, $node->cond);
+ if ($result !== null) {
+ $hasChanged = \true;
+ return $result;
+ }
+ }
+ return null;
+ });
+ if ($hasChanged) {
+ return $node;
+ }
+ return null;
+ }
+ /**
+ * @return null|Stmt[]|int
+ */
+ private function refactorStmtAndInstanceof(Class_ $class, If_ $if, Instanceof_ $instanceof)
+ {
+ // check local property only
+ if (!$instanceof->expr instanceof PropertyFetch || !$this->isName($instanceof->expr->var, 'this')) {
+ return null;
+ }
+ if (!$instanceof->class instanceof Name) {
+ return null;
+ }
+ $classType = $this->nodeTypeResolver->getType($instanceof->class);
+ $exprType = $this->nodeTypeResolver->getType($instanceof->expr);
+ $isSameStaticTypeOrSubtype = $classType->equals($exprType) || $classType->isSuperTypeOf($exprType)->yes();
+ if (!$isSameStaticTypeOrSubtype) {
+ return null;
+ }
+ if (!$this->isInPropertyPromotedParams($class, $instanceof->expr) && $this->isSkippedPropertyFetch($class, $instanceof->expr)) {
+ return null;
+ }
+ if ($if->cond !== $instanceof) {
+ return NodeTraverser::REMOVE_NODE;
+ }
+ if ($if->stmts === []) {
+ return NodeTraverser::REMOVE_NODE;
+ }
+ return $if->stmts;
+ }
+ /**
+ * @param \PhpParser\Node\Expr\PropertyFetch|\PhpParser\Node\Expr\StaticPropertyFetch $propertyFetch
+ */
+ private function isSkippedPropertyFetch(Class_ $class, $propertyFetch) : bool
+ {
+ $propertyName = $this->getName($propertyFetch->name);
+ if ($propertyName === null) {
+ return \true;
+ }
+ if ($this->constructorAssignDetector->isPropertyAssigned($class, $propertyName)) {
+ return \false;
+ }
+ $property = $class->getProperty($propertyName);
+ if (!$property instanceof Property) {
+ return \false;
+ }
+ return $property->type === null;
+ }
+ /**
+ * @param \PhpParser\Node\Expr\PropertyFetch|\PhpParser\Node\Expr\StaticPropertyFetch $propertyFetch
+ */
+ private function isInPropertyPromotedParams(Class_ $class, $propertyFetch) : bool
+ {
+ /** @var string $propertyName */
+ $propertyName = $this->nodeNameResolver->getName($propertyFetch);
+ $params = $this->promotedPropertyResolver->resolveFromClass($class);
+ foreach ($params as $param) {
+ if ($this->nodeNameResolver->isName($param, $propertyName)) {
+ return \true;
+ }
+ }
+ return \false;
+ }
+}
diff --git a/rules/DeadCode/Rector/If_/SimplifyIfElseWithSameContentRector.php b/rules/DeadCode/Rector/If_/SimplifyIfElseWithSameContentRector.php
index 9816d48e0c71..07601e233a35 100644
--- a/rules/DeadCode/Rector/If_/SimplifyIfElseWithSameContentRector.php
+++ b/rules/DeadCode/Rector/If_/SimplifyIfElseWithSameContentRector.php
@@ -7,8 +7,8 @@
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\If_;
-use Rector\Core\Contract\PhpParser\NodePrinterInterface;
use Rector\Core\Exception\ShouldNotHappenException;
+use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@@ -19,12 +19,12 @@ final class SimplifyIfElseWithSameContentRector extends AbstractRector
{
/**
* @readonly
- * @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
+ * @var \Rector\Core\PhpParser\Printer\BetterStandardPrinter
*/
- private $nodePrinter;
- public function __construct(NodePrinterInterface $nodePrinter)
+ private $betterStandardPrinter;
+ public function __construct(BetterStandardPrinter $betterStandardPrinter)
{
- $this->nodePrinter = $nodePrinter;
+ $this->betterStandardPrinter = $betterStandardPrinter;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -76,15 +76,15 @@ public function refactor(Node $node) : ?array
private function isIfWithConstantReturns(If_ $if) : bool
{
$possibleContents = [];
- $possibleContents[] = $this->nodePrinter->print($if->stmts);
+ $possibleContents[] = $this->betterStandardPrinter->print($if->stmts);
foreach ($if->elseifs as $elseif) {
- $possibleContents[] = $this->nodePrinter->print($elseif->stmts);
+ $possibleContents[] = $this->betterStandardPrinter->print($elseif->stmts);
}
$else = $if->else;
if (!$else instanceof Else_) {
throw new ShouldNotHappenException();
}
- $possibleContents[] = $this->nodePrinter->print($else->stmts);
+ $possibleContents[] = $this->betterStandardPrinter->print($else->stmts);
$uniqueContents = \array_unique($possibleContents);
// only one content for all
return \count($uniqueContents) === 1;
diff --git a/rules/DeadCode/Rector/If_/UnwrapFutureCompatibleIfPhpVersionRector.php b/rules/DeadCode/Rector/If_/UnwrapFutureCompatibleIfPhpVersionRector.php
index d43bd9f03fe4..275ced2d5b89 100644
--- a/rules/DeadCode/Rector/If_/UnwrapFutureCompatibleIfPhpVersionRector.php
+++ b/rules/DeadCode/Rector/If_/UnwrapFutureCompatibleIfPhpVersionRector.php
@@ -7,6 +7,7 @@
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\If_;
+use PhpParser\NodeTraverser;
use Rector\Core\Rector\AbstractRector;
use Rector\DeadCode\ConditionEvaluator;
use Rector\DeadCode\ConditionResolver;
@@ -60,9 +61,9 @@ public function getNodeTypes() : array
}
/**
* @param If_ $node
- * @return Stmt[]|null
+ * @return Stmt[]|null|int
*/
- public function refactor(Node $node) : ?array
+ public function refactor(Node $node)
{
if ($node->elseifs !== []) {
return null;
@@ -95,14 +96,13 @@ private function refactorIsMatch(If_ $if) : ?array
return $if->stmts;
}
/**
- * @return Stmt[]|null
+ * @return Stmt[]|int
*/
- private function refactorIsNotMatch(If_ $if) : ?array
+ private function refactorIsNotMatch(If_ $if)
{
// no else → just remove the node
if (!$if->else instanceof Else_) {
- $this->removeNode($if);
- return null;
+ return NodeTraverser::REMOVE_NODE;
}
// else is always used
return $if->else->stmts;
diff --git a/rules/DeadCode/Rector/MethodCall/RemoveEmptyMethodCallRector.php b/rules/DeadCode/Rector/MethodCall/RemoveEmptyMethodCallRector.php
deleted file mode 100644
index 6766fb8d459c..000000000000
--- a/rules/DeadCode/Rector/MethodCall/RemoveEmptyMethodCallRector.php
+++ /dev/null
@@ -1,199 +0,0 @@
-reflectionAstResolver = $reflectionAstResolver;
- $this->callAnalyzer = $callAnalyzer;
- $this->reflectionResolver = $reflectionResolver;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Remove empty method call', [new CodeSample(<<<'CODE_SAMPLE'
-class SomeClass
-{
- public function callThis()
- {
- }
-}
-
-$some = new SomeClass();
-$some->callThis();
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-class SomeClass
-{
- public function callThis()
- {
- }
-}
-
-$some = new SomeClass();
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [Expression::class, If_::class, Assign::class];
- }
- /**
- * @param Expression|If_|Assign $node
- */
- public function refactorWithScope(Node $node, Scope $scope)
- {
- if ($node instanceof If_) {
- return $this->refactorIf($node, $scope);
- }
- if ($node instanceof Expression) {
- $this->refactorExpression($node, $scope);
- return null;
- }
- if (!$node->expr instanceof MethodCall) {
- return null;
- }
- if (!$this->shouldRemoveMethodCall($node->expr, $scope)) {
- return null;
- }
- $node->expr = $this->nodeFactory->createFalse();
- return $node;
- }
- private function resolveClassLike(MethodCall $methodCall) : ?ClassLike
- {
- $classReflection = $this->reflectionResolver->resolveClassReflectionSourceObject($methodCall);
- if (!$classReflection instanceof ClassReflection) {
- return null;
- }
- return $this->reflectionAstResolver->resolveClassFromName($classReflection->getName());
- }
- private function shouldSkipMethodCall(MethodCall $methodCall) : bool
- {
- if ($this->callAnalyzer->isObjectCall($methodCall->var)) {
- return \true;
- }
- $parentArg = $this->betterNodeFinder->findParentType($methodCall, Arg::class);
- return $parentArg instanceof Arg;
- }
- /**
- * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Trait_|\PhpParser\Node\Stmt\Interface_|\PhpParser\Node\Stmt\Enum_ $classLike
- */
- private function shouldSkipClassMethod($classLike, MethodCall $methodCall, TypeWithClassName $typeWithClassName) : bool
- {
- if (!$classLike instanceof Class_) {
- return \true;
- }
- $methodName = $this->getName($methodCall->name);
- if ($methodName === null) {
- return \true;
- }
- $classMethod = $classLike->getMethod($methodName);
- if (!$classMethod instanceof ClassMethod) {
- return \true;
- }
- if ($classMethod->isAbstract()) {
- return \true;
- }
- if ((array) $classMethod->stmts !== []) {
- return \true;
- }
- $class = $this->betterNodeFinder->findParentType($methodCall, Class_::class);
- if (!$class instanceof Class_) {
- return \false;
- }
- if (!$typeWithClassName instanceof ThisType) {
- return \false;
- }
- if ($class->isFinal()) {
- return \false;
- }
- return !$classMethod->isPrivate();
- }
- private function shouldRemoveMethodCall(MethodCall $methodCall, Scope $scope) : bool
- {
- if ($this->shouldSkipMethodCall($methodCall)) {
- return \false;
- }
- $type = $scope->getType($methodCall->var);
- if (!$type instanceof TypeWithClassName) {
- return \false;
- }
- $classLike = $this->resolveClassLike($methodCall);
- if (!$classLike instanceof ClassLike) {
- return \false;
- }
- /** @var Class_|Trait_|Interface_|Enum_ $classLike */
- return !$this->shouldSkipClassMethod($classLike, $methodCall, $type);
- }
- /**
- * If->cond cannot removed,
- * it has to be replaced with false, see https://3v4l.org/U9S9i
- */
- private function refactorIf(If_ $if, Scope $scope) : ?If_
- {
- if (!$if->cond instanceof MethodCall) {
- return null;
- }
- if (!$this->shouldRemoveMethodCall($if->cond, $scope)) {
- return null;
- }
- $if->cond = $this->nodeFactory->createFalse();
- return $if;
- }
- private function refactorExpression(Expression $expression, Scope $scope) : void
- {
- if (!$expression->expr instanceof MethodCall) {
- return;
- }
- $methodCall = $expression->expr;
- if (!$this->shouldRemoveMethodCall($methodCall, $scope)) {
- return;
- }
- $this->removeNode($expression);
- }
-}
diff --git a/rules/DeadCode/Rector/Node/RemoveNonExistingVarAnnotationRector.php b/rules/DeadCode/Rector/Node/RemoveNonExistingVarAnnotationRector.php
index a21226e24aac..164aa8a094e0 100644
--- a/rules/DeadCode/Rector/Node/RemoveNonExistingVarAnnotationRector.php
+++ b/rules/DeadCode/Rector/Node/RemoveNonExistingVarAnnotationRector.php
@@ -4,8 +4,6 @@
namespace Rector\DeadCode\Rector\Node;
use PhpParser\Node;
-use PhpParser\Node\Expr\Assign;
-use PhpParser\Node\Expr\AssignRef;
use PhpParser\Node\Expr\CallLike;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\New_;
@@ -23,7 +21,6 @@
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
use Rector\Core\Rector\AbstractRector;
-use Rector\Core\Util\MultiInstanceofChecker;
use Rector\DeadCode\NodeAnalyzer\ExprUsedInNodeAnalyzer;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@@ -34,24 +31,14 @@
*/
final class RemoveNonExistingVarAnnotationRector extends AbstractRector
{
- /**
- * @var array>
- */
- private const NODES_TO_MATCH = [Assign::class, AssignRef::class, Foreach_::class, Static_::class, Echo_::class, Return_::class, Expression::class, Throw_::class, If_::class, While_::class, Switch_::class, Nop::class];
/**
* @readonly
* @var \Rector\DeadCode\NodeAnalyzer\ExprUsedInNodeAnalyzer
*/
private $exprUsedInNodeAnalyzer;
- /**
- * @readonly
- * @var \Rector\Core\Util\MultiInstanceofChecker
- */
- private $multiInstanceofChecker;
- public function __construct(ExprUsedInNodeAnalyzer $exprUsedInNodeAnalyzer, MultiInstanceofChecker $multiInstanceofChecker)
+ public function __construct(ExprUsedInNodeAnalyzer $exprUsedInNodeAnalyzer)
{
$this->exprUsedInNodeAnalyzer = $exprUsedInNodeAnalyzer;
- $this->multiInstanceofChecker = $multiInstanceofChecker;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -81,7 +68,7 @@ public function get()
*/
public function getNodeTypes() : array
{
- return [Node::class];
+ return [Foreach_::class, Static_::class, Echo_::class, Return_::class, Expression::class, Throw_::class, If_::class, While_::class, Switch_::class, Nop::class];
}
public function refactor(Node $node) : ?Node
{
@@ -132,13 +119,7 @@ private function isUsedInNextNodeWithExtractPreviouslyCalled(Node $node, string
}
private function shouldSkip(Node $node) : bool
{
- if (!$node instanceof Nop) {
- return !$this->multiInstanceofChecker->isInstanceOf($node, self::NODES_TO_MATCH);
- }
- if (\count($node->getComments()) <= 1) {
- return !$this->multiInstanceofChecker->isInstanceOf($node, self::NODES_TO_MATCH);
- }
- return \true;
+ return \count($node->getComments()) !== 1;
}
private function hasVariableName(Node $node, string $variableName) : bool
{
diff --git a/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php b/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php
index 747cd976cee9..92b989233f4e 100644
--- a/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php
+++ b/rules/DeadCode/Rector/Property/RemoveUnusedPrivatePropertyRector.php
@@ -4,56 +4,43 @@
namespace Rector\DeadCode\Rector\Property;
use PhpParser\Node;
+use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Stmt\Class_;
+use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Property;
+use PhpParser\Node\Stmt\TraitUse;
+use PhpParser\NodeTraverser;
use PHPStan\Analyser\Scope;
-use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface;
-use Rector\Core\NodeManipulator\PropertyManipulator;
+use Rector\BetterPhpDocParser\PhpDoc\DoctrineAnnotationTagValueNode;
+use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
+use Rector\Core\PhpParser\NodeFinder\PropertyFetchFinder;
use Rector\Core\Rector\AbstractScopeAwareRector;
-use Rector\Removing\NodeManipulator\ComplexNodeRemover;
-use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
+use Rector\DeadCode\NodeAnalyzer\PropertyWriteonlyAnalyzer;
+use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see \Rector\Tests\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector\RemoveUnusedPrivatePropertyRectorTest
*/
-final class RemoveUnusedPrivatePropertyRector extends AbstractScopeAwareRector implements AllowEmptyConfigurableRectorInterface
+final class RemoveUnusedPrivatePropertyRector extends AbstractScopeAwareRector
{
- /**
- * @api
- * @var string
- */
- public const REMOVE_ASSIGN_SIDE_EFFECT = 'remove_assign_side_effect';
- /**
- * Default to true, which apply remove assign even has side effect.
- * Set to false will allow to skip when assign has side effect.
- * @var bool
- */
- private $removeAssignSideEffect = \true;
/**
* @readonly
- * @var \Rector\Core\NodeManipulator\PropertyManipulator
+ * @var \Rector\Core\PhpParser\NodeFinder\PropertyFetchFinder
*/
- private $propertyManipulator;
+ private $propertyFetchFinder;
/**
* @readonly
- * @var \Rector\Removing\NodeManipulator\ComplexNodeRemover
- */
- private $complexNodeRemover;
- public function __construct(PropertyManipulator $propertyManipulator, ComplexNodeRemover $complexNodeRemover)
- {
- $this->propertyManipulator = $propertyManipulator;
- $this->complexNodeRemover = $complexNodeRemover;
- }
- /**
- * @param mixed[] $configuration
+ * @var \Rector\DeadCode\NodeAnalyzer\PropertyWriteonlyAnalyzer
*/
- public function configure(array $configuration) : void
+ private $propertyWriteonlyAnalyzer;
+ public function __construct(PropertyFetchFinder $propertyFetchFinder, PropertyWriteonlyAnalyzer $propertyWriteonlyAnalyzer)
{
- $this->removeAssignSideEffect = $configuration[self::REMOVE_ASSIGN_SIDE_EFFECT] ?? (bool) \current($configuration);
+ $this->propertyFetchFinder = $propertyFetchFinder;
+ $this->propertyWriteonlyAnalyzer = $propertyWriteonlyAnalyzer;
}
public function getRuleDefinition() : RuleDefinition
{
- return new RuleDefinition('Remove unused private properties', [new ConfiguredCodeSample(<<<'CODE_SAMPLE'
+ return new RuleDefinition('Remove unused private properties', [new CodeSample(<<<'CODE_SAMPLE'
class SomeClass
{
private $property;
@@ -64,7 +51,7 @@ class SomeClass
{
}
CODE_SAMPLE
-, [self::REMOVE_ASSIGN_SIDE_EFFECT => \true])]);
+)]);
}
/**
* @return array>
@@ -78,6 +65,9 @@ public function getNodeTypes() : array
*/
public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
+ if ($this->shouldSkipClass($node)) {
+ return null;
+ }
$hasChanged = \false;
foreach ($node->stmts as $key => $stmt) {
if (!$stmt instanceof Property) {
@@ -86,23 +76,76 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
if ($this->shouldSkipProperty($stmt)) {
continue;
}
- if ($this->propertyManipulator->isPropertyUsedInReadContext($node, $stmt, $scope)) {
+ if (!$this->shouldRemoveProperty($node, $stmt)) {
continue;
}
- // use different variable to avoid re-assign back $hasRemoved to false
- // when already asssigned to true
- $isRemoved = $this->complexNodeRemover->removePropertyAndUsages($node, $stmt, $this->removeAssignSideEffect, $scope, $key);
- if ($isRemoved) {
- $hasChanged = \true;
- }
+ // remove property
+ unset($node->stmts[$key]);
+ $propertyName = $this->getName($stmt);
+ $this->removePropertyAssigns($node, $propertyName);
+ $hasChanged = \true;
}
- return $hasChanged ? $node : null;
+ if ($hasChanged) {
+ return $node;
+ }
+ return null;
}
private function shouldSkipProperty(Property $property) : bool
{
+ // has some attribute logic
+ if ($property->attrGroups !== []) {
+ return \true;
+ }
if (\count($property->props) !== 1) {
return \true;
}
- return !$property->isPrivate();
+ if (!$property->isPrivate()) {
+ return \true;
+ }
+ // has some possible magic
+ if ($property->isStatic()) {
+ return \true;
+ }
+ $propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNode($property);
+ if (!$propertyPhpDocInfo instanceof PhpDocInfo) {
+ return \false;
+ }
+ // skip as might contain important metadata
+ return $propertyPhpDocInfo->hasByType(DoctrineAnnotationTagValueNode::class);
+ }
+ private function shouldRemoveProperty(Class_ $class, Property $property) : bool
+ {
+ $propertyName = $this->getName($property);
+ $propertyFetches = $this->propertyFetchFinder->findLocalPropertyFetchesByName($class, $propertyName);
+ if ($propertyFetches === []) {
+ return \true;
+ }
+ return $this->propertyWriteonlyAnalyzer->arePropertyFetchesExclusivelyBeingAssignedTo($propertyFetches);
+ }
+ private function shouldSkipClass(Class_ $class) : bool
+ {
+ foreach ($class->stmts as $stmt) {
+ // unclear what property can be used there
+ if ($stmt instanceof TraitUse) {
+ return \true;
+ }
+ }
+ return $this->propertyWriteonlyAnalyzer->hasClassDynamicPropertyNames($class);
+ }
+ private function removePropertyAssigns(Class_ $class, string $propertyName) : void
+ {
+ $this->traverseNodesWithCallable($class, function (Node $node) use($class, $propertyName) : ?int {
+ if (!$node instanceof Expression) {
+ return null;
+ }
+ if (!$node->expr instanceof Assign) {
+ return null;
+ }
+ $assign = $node->expr;
+ if (!$this->propertyFetchFinder->isLocalPropertyFetchByName($assign->var, $class, $propertyName)) {
+ return null;
+ }
+ return NodeTraverser::REMOVE_NODE;
+ });
}
}
diff --git a/rules/DeadCode/Rector/StaticCall/RemoveParentCallWithoutParentRector.php b/rules/DeadCode/Rector/StaticCall/RemoveParentCallWithoutParentRector.php
index a874c59c3a24..b4a90bcae146 100644
--- a/rules/DeadCode/Rector/StaticCall/RemoveParentCallWithoutParentRector.php
+++ b/rules/DeadCode/Rector/StaticCall/RemoveParentCallWithoutParentRector.php
@@ -11,7 +11,6 @@
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Expression;
-use PhpParser\NodeTraverser;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Core\Enum\ObjectReference;
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
@@ -81,51 +80,51 @@ public function refactor(Node $node) : ?Node
if ($this->shouldSkipClass($node)) {
return null;
}
- $class = $node;
+ $hasChanged = \false;
foreach ($node->getMethods() as $classMethod) {
- $this->traverseNodesWithCallable($classMethod, function (Node $node) use($class) {
- // skip nested anonmyous class
- if ($node instanceof Class_) {
- return NodeTraverser::STOP_TRAVERSAL;
+ if ($classMethod->stmts === null) {
+ continue;
+ }
+ foreach ($classMethod->stmts as $key => $stmt) {
+ if (!$stmt instanceof Expression) {
+ continue;
}
- if ($node instanceof Assign) {
- return $this->refactorAssign($node, $class);
+ if ($stmt->expr instanceof StaticCall && $this->isParentStaticCall($stmt->expr)) {
+ if ($this->doesCalledMethodExistInParent($stmt->expr, $node)) {
+ continue;
+ }
+ unset($classMethod->stmts[$key]);
+ $hasChanged = \true;
}
- if ($node instanceof Expression) {
- $this->refactorExpression($node, $class);
- return null;
+ if ($stmt->expr instanceof Assign) {
+ $assign = $stmt->expr;
+ if ($assign->expr instanceof StaticCall && $this->isParentStaticCall($assign->expr)) {
+ $staticCall = $assign->expr;
+ // is valid call
+ if ($this->doesCalledMethodExistInParent($staticCall, $node)) {
+ continue;
+ }
+ $assign->expr = $this->nodeFactory->createNull();
+ $hasChanged = \true;
+ }
}
- return null;
- });
+ }
}
- return null;
- }
- public function refactorAssign(Assign $assign, Class_ $class) : ?Assign
- {
- if (!$this->isParentStaticCall($assign->expr)) {
- return null;
+ if ($hasChanged) {
+ return $node;
}
- /** @var StaticCall $staticCall */
- $staticCall = $assign->expr;
- // is valid call
- if ($this->doesCalledMethodExistInParent($staticCall, $class)) {
- return null;
- }
- $assign->expr = $this->nodeFactory->createNull();
- return $assign;
+ return null;
}
private function isParentStaticCall(Expr $expr) : bool
{
if (!$expr instanceof StaticCall) {
return \false;
}
- if (!$expr->class instanceof Name) {
- return \false;
- }
return $this->isName($expr->class, ObjectReference::PARENT);
}
private function shouldSkipClass(Class_ $class) : bool
{
+ // skip cases when parent class reflection is not found
if ($class->extends instanceof FullyQualified && !$this->reflectionProvider->hasClass($class->extends->toString())) {
return \true;
}
@@ -143,18 +142,4 @@ private function doesCalledMethodExistInParent(StaticCall $staticCall, Class_ $c
}
return $this->classMethodManipulator->hasParentMethodOrInterfaceMethod($class, $calledMethodName);
}
- private function refactorExpression(Expression $expression, Class_ $class) : void
- {
- if (!$expression->expr instanceof StaticCall) {
- return;
- }
- if (!$this->isParentStaticCall($expression->expr)) {
- return;
- }
- // is valid call
- if ($this->doesCalledMethodExistInParent($expression->expr, $class)) {
- return;
- }
- $this->removeNode($expression);
- }
}
diff --git a/rules/DeadCode/Rector/TryCatch/RemoveDeadTryCatchRector.php b/rules/DeadCode/Rector/TryCatch/RemoveDeadTryCatchRector.php
index 5bb706035776..f4469bcece0f 100644
--- a/rules/DeadCode/Rector/TryCatch/RemoveDeadTryCatchRector.php
+++ b/rules/DeadCode/Rector/TryCatch/RemoveDeadTryCatchRector.php
@@ -9,6 +9,7 @@
use PhpParser\Node\Stmt\Nop;
use PhpParser\Node\Stmt\Throw_;
use PhpParser\Node\Stmt\TryCatch;
+use PhpParser\NodeTraverser;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@@ -52,7 +53,7 @@ public function getNodeTypes() : array
}
/**
* @param TryCatch $node
- * @return Stmt[]|null|TryCatch
+ * @return Stmt[]|null|TryCatch|int
*/
public function refactor(Node $node)
{
@@ -62,8 +63,7 @@ public function refactor(Node $node)
return null;
}
if ($this->isEmpty($node->stmts)) {
- $this->removeNode($node);
- return null;
+ return NodeTraverser::REMOVE_NODE;
}
if (\count($node->catches) !== 1) {
return null;
diff --git a/rules/DeadCode/SideEffect/PureFunctionDetector.php b/rules/DeadCode/SideEffect/PureFunctionDetector.php
index 686929db2baa..14f9957fccf3 100644
--- a/rules/DeadCode/SideEffect/PureFunctionDetector.php
+++ b/rules/DeadCode/SideEffect/PureFunctionDetector.php
@@ -11,6 +11,16 @@
use Rector\NodeNameResolver\NodeNameResolver;
final class PureFunctionDetector
{
+ /**
+ * @readonly
+ * @var \Rector\NodeNameResolver\NodeNameResolver
+ */
+ private $nodeNameResolver;
+ /**
+ * @readonly
+ * @var \PHPStan\Reflection\ReflectionProvider
+ */
+ private $reflectionProvider;
/**
* @see https://github.com/vimeo/psalm/blob/d470903722cfcbc1cd04744c5491d3e6d13ec3d9/src/Psalm/Internal/Codebase/Functions.php#L288
* @var string[]
@@ -225,16 +235,6 @@ final class PureFunctionDetector
// stream
'stream_filter_append',
];
- /**
- * @readonly
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
- /**
- * @readonly
- * @var \PHPStan\Reflection\ReflectionProvider
- */
- private $reflectionProvider;
public function __construct(NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider)
{
$this->nodeNameResolver = $nodeNameResolver;
diff --git a/rules/DeadCode/SideEffect/SideEffectNodeDetector.php b/rules/DeadCode/SideEffect/SideEffectNodeDetector.php
index d4185e08e320..be033cfaad34 100644
--- a/rules/DeadCode/SideEffect/SideEffectNodeDetector.php
+++ b/rules/DeadCode/SideEffect/SideEffectNodeDetector.php
@@ -25,14 +25,6 @@
use Rector\NodeTypeResolver\NodeTypeResolver;
final class SideEffectNodeDetector
{
- /**
- * @var array>
- */
- private const SIDE_EFFECT_NODE_TYPES = [Encapsed::class, New_::class, Concat::class, PropertyFetch::class];
- /**
- * @var array>
- */
- private const CALL_EXPR_SIDE_EFFECT_NODE_TYPES = [MethodCall::class, New_::class, NullsafeMethodCall::class, StaticCall::class];
/**
* @readonly
* @var \Rector\NodeTypeResolver\NodeTypeResolver
@@ -43,6 +35,14 @@ final class SideEffectNodeDetector
* @var \Rector\DeadCode\SideEffect\PureFunctionDetector
*/
private $pureFunctionDetector;
+ /**
+ * @var array>
+ */
+ private const SIDE_EFFECT_NODE_TYPES = [Encapsed::class, New_::class, Concat::class, PropertyFetch::class];
+ /**
+ * @var array>
+ */
+ private const CALL_EXPR_SIDE_EFFECT_NODE_TYPES = [MethodCall::class, New_::class, NullsafeMethodCall::class, StaticCall::class];
public function __construct(NodeTypeResolver $nodeTypeResolver, \Rector\DeadCode\SideEffect\PureFunctionDetector $pureFunctionDetector)
{
$this->nodeTypeResolver = $nodeTypeResolver;
diff --git a/rules/DeadCode/ValueObject/TargetRemoveClassMethod.php b/rules/DeadCode/ValueObject/TargetRemoveClassMethod.php
deleted file mode 100644
index 4b5950d0a5f9..000000000000
--- a/rules/DeadCode/ValueObject/TargetRemoveClassMethod.php
+++ /dev/null
@@ -1,31 +0,0 @@
-className = $className;
- $this->methodName = $methodName;
- }
- public function getClassName() : string
- {
- return $this->className;
- }
- public function getMethodName() : string
- {
- return $this->methodName;
- }
-}
diff --git a/rules/DependencyInjection/Collector/VariablesToPropertyFetchCollection.php b/rules/DependencyInjection/Collector/VariablesToPropertyFetchCollection.php
deleted file mode 100644
index 8f5fa022909d..000000000000
--- a/rules/DependencyInjection/Collector/VariablesToPropertyFetchCollection.php
+++ /dev/null
@@ -1,24 +0,0 @@
-
- */
- private $variableNameAndType = [];
- public function addVariableNameAndType(string $name, ObjectType $objectType) : void
- {
- $this->variableNameAndType[$name] = $objectType;
- }
- /**
- * @return array
- */
- public function getVariableNamesAndTypes() : array
- {
- return $this->variableNameAndType;
- }
-}
diff --git a/rules/DependencyInjection/NodeManipulator/PropertyConstructorInjectionManipulator.php b/rules/DependencyInjection/NodeManipulator/PropertyConstructorInjectionManipulator.php
deleted file mode 100644
index 6883ea6a4aec..000000000000
--- a/rules/DependencyInjection/NodeManipulator/PropertyConstructorInjectionManipulator.php
+++ /dev/null
@@ -1,75 +0,0 @@
-nodeNameResolver = $nodeNameResolver;
- $this->phpDocInfoFactory = $phpDocInfoFactory;
- $this->phpDocTypeChanger = $phpDocTypeChanger;
- $this->phpDocTagRemover = $phpDocTagRemover;
- $this->propertyToAddCollector = $propertyToAddCollector;
- $this->betterNodeFinder = $betterNodeFinder;
- }
- /**
- * @api symfony
- */
- public function refactor(Property $property, Type $type, DoctrineAnnotationTagValueNode $doctrineAnnotationTagValueNode) : void
- {
- $propertyName = $this->nodeNameResolver->getName($property);
- $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
- $this->phpDocTypeChanger->changeVarType($phpDocInfo, $type);
- $this->phpDocTagRemover->removeTagValueFromNode($phpDocInfo, $doctrineAnnotationTagValueNode);
- $class = $this->betterNodeFinder->findParentType($property, Class_::class);
- if (!$class instanceof Class_) {
- throw new ShouldNotHappenException();
- }
- $propertyMetadata = new PropertyMetadata($propertyName, $type, $property->flags);
- $this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
- }
-}
diff --git a/rules/DependencyInjection/Rector/ClassMethod/AddMethodParentCallRector.php b/rules/DependencyInjection/Rector/ClassMethod/AddMethodParentCallRector.php
deleted file mode 100644
index 619bc139b7a2..000000000000
--- a/rules/DependencyInjection/Rector/ClassMethod/AddMethodParentCallRector.php
+++ /dev/null
@@ -1,122 +0,0 @@
-
- */
- private $methodByParentTypes = [];
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Add method parent call, in case new parent method is added', [new ConfiguredCodeSample(<<<'CODE_SAMPLE'
-class SunshineCommand extends ParentClassWithNewConstructor
-{
- public function __construct()
- {
- $value = 5;
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-class SunshineCommand extends ParentClassWithNewConstructor
-{
- public function __construct()
- {
- $value = 5;
-
- parent::__construct();
- }
-}
-CODE_SAMPLE
-, ['ParentClassWithNewConstructor' => MethodName::CONSTRUCT])]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [ClassMethod::class];
- }
- /**
- * @param ClassMethod $node
- */
- public function refactor(Node $node) : ?Node
- {
- $classLike = $this->betterNodeFinder->findParentType($node, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
- return null;
- }
- $className = (string) $this->nodeNameResolver->getName($classLike);
- foreach ($this->methodByParentTypes as $type => $method) {
- // not itself
- if ($className === $type) {
- continue;
- }
- if ($this->shouldSkipMethod($node, $method)) {
- continue;
- }
- if (!$this->isObjectType($classLike, new ObjectType($type))) {
- continue;
- }
- $node->stmts[] = $this->createParentStaticCall($method);
- return $node;
- }
- return null;
- }
- /**
- * @param mixed[] $configuration
- */
- public function configure(array $configuration) : void
- {
- Assert::allString(\array_keys($configuration));
- Assert::allString($configuration);
- /** @var array $configuration */
- $this->methodByParentTypes = $configuration;
- }
- private function shouldSkipMethod(ClassMethod $classMethod, string $method) : bool
- {
- if (!$this->isName($classMethod, $method)) {
- return \true;
- }
- return $this->hasParentCallOfMethod($classMethod, $method);
- }
- private function createParentStaticCall(string $method) : Expression
- {
- $staticCall = $this->nodeFactory->createStaticCall(ObjectReference::PARENT, $method);
- return new Expression($staticCall);
- }
- /**
- * Looks for "parent::
- */
- private function hasParentCallOfMethod(ClassMethod $classMethod, string $method) : bool
- {
- return (bool) $this->betterNodeFinder->findFirst((array) $classMethod->stmts, function (Node $node) use($method) : bool {
- if (!$node instanceof StaticCall) {
- return \false;
- }
- if (!$this->isName($node->class, ObjectReference::PARENT)) {
- return \false;
- }
- return $this->isName($node->name, $method);
- });
- }
-}
diff --git a/rules/DependencyInjection/Rector/Class_/ActionInjectionToConstructorInjectionRector.php b/rules/DependencyInjection/Rector/Class_/ActionInjectionToConstructorInjectionRector.php
deleted file mode 100644
index 3281fbfce1ef..000000000000
--- a/rules/DependencyInjection/Rector/Class_/ActionInjectionToConstructorInjectionRector.php
+++ /dev/null
@@ -1,152 +0,0 @@
-applicationServiceMapProvider = $applicationServiceMapProvider;
- $this->variablesToPropertyFetchCollection = $variablesToPropertyFetchCollection;
- $this->propertyToAddCollector = $propertyToAddCollector;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Turns action injection in Controllers to constructor injection', [new CodeSample(<<<'CODE_SAMPLE'
-final class SomeController
-{
- public function default(ProductRepository $productRepository)
- {
- $products = $productRepository->fetchAll();
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-final class SomeController
-{
- public function __construct(
- private ProductRepository $productRepository
- ) {
- }
-
- public function default()
- {
- $products = $this->productRepository->fetchAll();
- }
-}
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [Class_::class];
- }
- /**
- * @param Class_ $node
- */
- public function refactor(Node $node) : ?Node
- {
- if (!$this->isName($node, '*Controller')) {
- return null;
- }
- foreach ($node->getMethods() as $classMethod) {
- $this->processClassMethod($node, $classMethod);
- }
- foreach ($node->getMethods() as $classMethod) {
- $this->refactorVariablesToPropertyFetches($classMethod);
- }
- return $node;
- }
- private function refactorVariablesToPropertyFetches(ClassMethod $classMethod) : void
- {
- if (!$classMethod->isPublic()) {
- return;
- }
- $this->traverseNodesWithCallable((array) $classMethod->stmts, function (Node $node) : ?PropertyFetch {
- if (!$node instanceof Variable) {
- return null;
- }
- foreach ($this->variablesToPropertyFetchCollection->getVariableNamesAndTypes() as $name => $objectType) {
- if (!$this->isName($node, $name)) {
- continue;
- }
- if (!$this->isObjectType($node, $objectType)) {
- continue;
- }
- return $this->nodeFactory->createPropertyFetch('this', $name);
- }
- return null;
- });
- }
- private function processClassMethod(Class_ $class, ClassMethod $classMethod) : void
- {
- foreach ($classMethod->params as $key => $paramNode) {
- if (!$this->isActionInjectedParamNode($paramNode)) {
- continue;
- }
- $paramType = $this->getType($paramNode);
- if (!$paramType instanceof ObjectType) {
- throw new ShouldNotHappenException();
- }
- /** @var string $paramName */
- $paramName = $this->getName($paramNode->var);
- $propertyMetadata = new PropertyMetadata($paramName, $paramType, Class_::MODIFIER_PRIVATE);
- $this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
- unset($classMethod->params[$key]);
- $this->variablesToPropertyFetchCollection->addVariableNameAndType($paramName, $paramType);
- }
- }
- private function isActionInjectedParamNode(Param $param) : bool
- {
- if ($param->type === null) {
- return \false;
- }
- $typehint = $this->getName($param->type);
- if ($typehint === null) {
- return \false;
- }
- $paramStaticType = $this->getType($param);
- if (!$paramStaticType instanceof ObjectType) {
- return \false;
- }
- $serviceMap = $this->applicationServiceMapProvider->provide();
- return $serviceMap->hasService($paramStaticType->getClassName());
- }
-}
diff --git a/rules/MysqlToMysqli/Rector/FuncCall/MysqlFuncCallToMysqliRector.php b/rules/MysqlToMysqli/Rector/FuncCall/MysqlFuncCallToMysqliRector.php
index 452a5123c904..cdc80b0a6d2a 100644
--- a/rules/MysqlToMysqli/Rector/FuncCall/MysqlFuncCallToMysqliRector.php
+++ b/rules/MysqlToMysqli/Rector/FuncCall/MysqlFuncCallToMysqliRector.php
@@ -72,6 +72,9 @@ public function refactor(Node $node) : ?FuncCall
}
private function processMysqlCreateDb(FuncCall $funcCall) : ?FuncCall
{
+ if ($funcCall->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($funcCall->getArgs()[0])) {
return null;
}
@@ -84,6 +87,9 @@ private function processMysqlCreateDb(FuncCall $funcCall) : ?FuncCall
}
private function processMysqlDropDb(FuncCall $funcCall) : ?FuncCall
{
+ if ($funcCall->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($funcCall->getArgs()[0])) {
return null;
}
diff --git a/rules/MysqlToMysqli/Rector/FuncCall/MysqlPConnectToMysqliConnectRector.php b/rules/MysqlToMysqli/Rector/FuncCall/MysqlPConnectToMysqliConnectRector.php
index b30ef4f5d587..a41919c142b8 100644
--- a/rules/MysqlToMysqli/Rector/FuncCall/MysqlPConnectToMysqliConnectRector.php
+++ b/rules/MysqlToMysqli/Rector/FuncCall/MysqlPConnectToMysqliConnectRector.php
@@ -55,6 +55,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'mysql_pconnect')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($node->getArgs()[0])) {
return null;
}
diff --git a/rules/MysqlToMysqli/Rector/FuncCall/MysqlQueryMysqlErrorWithLinkRector.php b/rules/MysqlToMysqli/Rector/FuncCall/MysqlQueryMysqlErrorWithLinkRector.php
index f6239e928d15..ee3e0fe82feb 100644
--- a/rules/MysqlToMysqli/Rector/FuncCall/MysqlQueryMysqlErrorWithLinkRector.php
+++ b/rules/MysqlToMysqli/Rector/FuncCall/MysqlQueryMysqlErrorWithLinkRector.php
@@ -76,6 +76,9 @@ public function getNodeTypes() : array
*/
public function refactor(Node $node) : ?Node
{
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
foreach (self::FUNCTION_RENAME_MAP as $oldFunction => $newFunction) {
if (!$this->isName($node, $oldFunction)) {
continue;
diff --git a/rules/Naming/Contract/Guard/ConflictingNameGuardInterface.php b/rules/Naming/Contract/Guard/ConflictingNameGuardInterface.php
deleted file mode 100644
index 8fcf79eb9b3e..000000000000
--- a/rules/Naming/Contract/Guard/ConflictingNameGuardInterface.php
+++ /dev/null
@@ -1,16 +0,0 @@
-
*/
@@ -29,11 +34,6 @@ final class InflectorSingularResolver
* @var string
*/
private const CAMELCASE = 'camelcase';
- /**
- * @readonly
- * @var \Doctrine\Inflector\Inflector
- */
- private $inflector;
public function __construct(Inflector $inflector)
{
$this->inflector = $inflector;
diff --git a/rules/Naming/Guard/BreakingVariableRenameGuard.php b/rules/Naming/Guard/BreakingVariableRenameGuard.php
index 1f2d13c4d7fc..f5be7d942354 100644
--- a/rules/Naming/Guard/BreakingVariableRenameGuard.php
+++ b/rules/Naming/Guard/BreakingVariableRenameGuard.php
@@ -5,17 +5,13 @@
use DateTimeInterface;
use PhpParser\Node;
-use PhpParser\Node\Expr;
use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Error;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\Else_;
-use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\Function_;
-use PhpParser\Node\Stmt\If_;
use PHPStan\Analyser\Scope;
use PHPStan\Type\ObjectType;
use PHPStan\Type\TypeWithClassName;
@@ -32,11 +28,6 @@
*/
final class BreakingVariableRenameGuard
{
- /**
- * @var string
- * @see https://regex101.com/r/1pKLgf/1
- */
- public const AT_NAMING_REGEX = '#[\\w+]At$#';
/**
* @readonly
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
@@ -67,6 +58,11 @@ final class BreakingVariableRenameGuard
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
+ /**
+ * @var string
+ * @see https://regex101.com/r/1pKLgf/1
+ */
+ public const AT_NAMING_REGEX = '#[\\w+]At$#';
public function __construct(BetterNodeFinder $betterNodeFinder, ConflictingNameResolver $conflictingNameResolver, NodeTypeResolver $nodeTypeResolver, OverridenExistingNamesResolver $overridenExistingNamesResolver, TypeUnwrapper $typeUnwrapper, NodeNameResolver $nodeNameResolver)
{
$this->betterNodeFinder = $betterNodeFinder;
@@ -98,13 +94,7 @@ public function shouldSkipVariable(string $currentName, string $expectedName, $f
if ($this->hasConflictVariable($functionLike, $expectedName)) {
return \true;
}
- if ($this->isUsedInClosureUsesName($expectedName, $functionLike)) {
- return \true;
- }
- if ($this->isUsedInForeachKeyValueVar($variable, $currentName)) {
- return \true;
- }
- return $this->isUsedInIfAndOtherBranches($variable, $currentName);
+ return $this->isUsedInClosureUsesName($expectedName, $functionLike);
}
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Expr\ArrowFunction $classMethod
@@ -135,6 +125,9 @@ public function shouldSkipParam(string $currentName, string $expectedName, $clas
if ($this->isRamseyUuidInterface($param)) {
return \true;
}
+ if ($this->isGenerator($param)) {
+ return \true;
+ }
if ($this->isDateTimeAtNamingConvention($param)) {
return \true;
}
@@ -174,55 +167,10 @@ private function isUsedInClosureUsesName(string $expectedName, $functionLike) :
}
return $this->betterNodeFinder->hasVariableOfName($functionLike->uses, $expectedName);
}
- private function isUsedInForeachKeyValueVar(Variable $variable, string $currentName) : bool
- {
- $previousForeach = $this->betterNodeFinder->findFirstPreviousOfTypes($variable, [Foreach_::class]);
- if ($previousForeach instanceof Foreach_) {
- if ($previousForeach->keyVar === $variable) {
- return \false;
- }
- if ($previousForeach->valueVar === $variable) {
- return \false;
- }
- if ($this->nodeNameResolver->isName($previousForeach->valueVar, $currentName)) {
- return \true;
- }
- if (!$previousForeach->keyVar instanceof Expr) {
- return \false;
- }
- if ($this->nodeNameResolver->isName($previousForeach->keyVar, $currentName)) {
- return \true;
- }
- }
- return \false;
- }
- private function isUsedInIfAndOtherBranches(Variable $variable, string $currentVariableName) : bool
- {
- // is in if branches?
- $previousIf = $this->betterNodeFinder->findFirstPreviousOfTypes($variable, [If_::class]);
- if ($previousIf instanceof If_) {
- $variableUses = [];
- $variableUses[] = $this->betterNodeFinder->findVariableOfName($previousIf->stmts, $currentVariableName);
- $previousStmts = $previousIf->else instanceof Else_ ? $previousIf->else->stmts : [];
- $variableUses[] = $this->betterNodeFinder->findVariableOfName($previousStmts, $currentVariableName);
- $variableUses[] = $this->betterNodeFinder->findVariableOfName($previousIf->elseifs, $currentVariableName);
- $variableUses = \array_filter($variableUses);
- if (\count($variableUses) > 1) {
- return \true;
- }
- }
- return \false;
- }
- /**
- * @TODO Remove once ParamRenamer created
- */
private function isRamseyUuidInterface(Param $param) : bool
{
return $this->nodeTypeResolver->isObjectType($param, new ObjectType('Ramsey\\Uuid\\UuidInterface'));
}
- /**
- * @TODO Remove once ParamRenamer created
- */
private function isDateTimeAtNamingConvention(Param $param) : bool
{
$type = $this->nodeTypeResolver->getType($param);
@@ -237,4 +185,8 @@ private function isDateTimeAtNamingConvention(Param $param) : bool
$currentName = $this->nodeNameResolver->getName($param);
return StringUtils::isMatch($currentName, self::AT_NAMING_REGEX . '');
}
+ private function isGenerator(Param $param) : bool
+ {
+ return $this->nodeTypeResolver->isObjectType($param, new ObjectType('Symfony\\Component\\DependencyInjection\\Argument\\RewindableGenerator'));
+ }
}
diff --git a/rules/Naming/Guard/DateTimeAtNamingConventionGuard.php b/rules/Naming/Guard/DateTimeAtNamingConventionGuard.php
index 8391ab2d8ea3..408ad13eb068 100644
--- a/rules/Naming/Guard/DateTimeAtNamingConventionGuard.php
+++ b/rules/Naming/Guard/DateTimeAtNamingConventionGuard.php
@@ -6,15 +6,10 @@
use DateTimeInterface;
use PHPStan\Type\TypeWithClassName;
use Rector\Core\Util\StringUtils;
-use Rector\Naming\Contract\Guard\ConflictingNameGuardInterface;
-use Rector\Naming\Contract\RenameValueObjectInterface;
use Rector\Naming\ValueObject\PropertyRename;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\PHPStanStaticTypeMapper\Utils\TypeUnwrapper;
-/**
- * @implements ConflictingNameGuardInterface
- */
-final class DateTimeAtNamingConventionGuard implements ConflictingNameGuardInterface
+final class DateTimeAtNamingConventionGuard
{
/**
* @readonly
@@ -31,14 +26,7 @@ public function __construct(NodeTypeResolver $nodeTypeResolver, TypeUnwrapper $t
$this->nodeTypeResolver = $nodeTypeResolver;
$this->typeUnwrapper = $typeUnwrapper;
}
- /**
- * @param PropertyRename $renameValueObject
- */
- public function isConflicting(RenameValueObjectInterface $renameValueObject) : bool
- {
- return $this->isDateTimeAtNamingConvention($renameValueObject);
- }
- private function isDateTimeAtNamingConvention(PropertyRename $propertyRename) : bool
+ public function isConflicting(PropertyRename $propertyRename) : bool
{
$type = $this->nodeTypeResolver->getType($propertyRename->getProperty());
$type = $this->typeUnwrapper->unwrapFirstObjectTypeFromUnionType($type);
diff --git a/rules/Naming/Guard/HasMagicGetSetGuard.php b/rules/Naming/Guard/HasMagicGetSetGuard.php
index adbac0d4a1f4..fdee4cc784a2 100644
--- a/rules/Naming/Guard/HasMagicGetSetGuard.php
+++ b/rules/Naming/Guard/HasMagicGetSetGuard.php
@@ -4,13 +4,8 @@
namespace Rector\Naming\Guard;
use PHPStan\Reflection\ReflectionProvider;
-use Rector\Naming\Contract\Guard\ConflictingNameGuardInterface;
-use Rector\Naming\Contract\RenameValueObjectInterface;
use Rector\Naming\ValueObject\PropertyRename;
-/**
- * @implements ConflictingNameGuardInterface
- */
-final class HasMagicGetSetGuard implements ConflictingNameGuardInterface
+final class HasMagicGetSetGuard
{
/**
* @readonly
@@ -21,15 +16,12 @@ public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
}
- /**
- * @param PropertyRename $renameValueObject
- */
- public function isConflicting(RenameValueObjectInterface $renameValueObject) : bool
+ public function isConflicting(PropertyRename $propertyRename) : bool
{
- if (!$this->reflectionProvider->hasClass($renameValueObject->getClassLikeName())) {
+ if (!$this->reflectionProvider->hasClass($propertyRename->getClassLikeName())) {
return \false;
}
- $classReflection = $this->reflectionProvider->getClass($renameValueObject->getClassLikeName());
+ $classReflection = $this->reflectionProvider->getClass($propertyRename->getClassLikeName());
if ($classReflection->hasMethod('__set')) {
return \true;
}
diff --git a/rules/Naming/Guard/NotPrivatePropertyGuard.php b/rules/Naming/Guard/NotPrivatePropertyGuard.php
deleted file mode 100644
index e63220650294..000000000000
--- a/rules/Naming/Guard/NotPrivatePropertyGuard.php
+++ /dev/null
@@ -1,21 +0,0 @@
-
- */
-final class NotPrivatePropertyGuard implements ConflictingNameGuardInterface
-{
- /**
- * @param PropertyRename $renameValueObject
- */
- public function isConflicting(RenameValueObjectInterface $renameValueObject) : bool
- {
- return !$renameValueObject->isPrivateProperty();
- }
-}
diff --git a/rules/Naming/Guard/RamseyUuidInterfaceGuard.php b/rules/Naming/Guard/RamseyUuidInterfaceGuard.php
deleted file mode 100644
index a5656de3c911..000000000000
--- a/rules/Naming/Guard/RamseyUuidInterfaceGuard.php
+++ /dev/null
@@ -1,32 +0,0 @@
-
- */
-final class RamseyUuidInterfaceGuard implements ConflictingNameGuardInterface
-{
- /**
- * @readonly
- * @var \Rector\NodeTypeResolver\NodeTypeResolver
- */
- private $nodeTypeResolver;
- public function __construct(NodeTypeResolver $nodeTypeResolver)
- {
- $this->nodeTypeResolver = $nodeTypeResolver;
- }
- /**
- * @param PropertyRename $renameValueObject
- */
- public function isConflicting(RenameValueObjectInterface $renameValueObject) : bool
- {
- return $this->nodeTypeResolver->isObjectType($renameValueObject->getProperty(), new ObjectType('Ramsey\\Uuid\\UuidInterface'));
- }
-}
diff --git a/rules/Naming/Matcher/ForeachMatcher.php b/rules/Naming/Matcher/ForeachMatcher.php
index 5ad7383ad1f5..490a5d1c4c4d 100644
--- a/rules/Naming/Matcher/ForeachMatcher.php
+++ b/rules/Naming/Matcher/ForeachMatcher.php
@@ -8,7 +8,6 @@
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\Function_;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Naming\ValueObject\VariableAndCallForeach;
use Rector\NodeNameResolver\NodeNameResolver;
final class ForeachMatcher
@@ -23,18 +22,15 @@ final class ForeachMatcher
* @var \Rector\Naming\Matcher\CallMatcher
*/
private $callMatcher;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- public function __construct(NodeNameResolver $nodeNameResolver, \Rector\Naming\Matcher\CallMatcher $callMatcher, BetterNodeFinder $betterNodeFinder)
+ public function __construct(NodeNameResolver $nodeNameResolver, \Rector\Naming\Matcher\CallMatcher $callMatcher)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->callMatcher = $callMatcher;
- $this->betterNodeFinder = $betterNodeFinder;
}
- public function match(Foreach_ $foreach) : ?VariableAndCallForeach
+ /**
+ * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Stmt\Function_ $functionLike
+ */
+ public function match(Foreach_ $foreach, $functionLike) : ?VariableAndCallForeach
{
$call = $this->callMatcher->matchCall($foreach);
if ($call === null) {
@@ -43,21 +39,10 @@ public function match(Foreach_ $foreach) : ?VariableAndCallForeach
if (!$foreach->valueVar instanceof Variable) {
return null;
}
- $functionLike = $this->getFunctionLike($foreach);
- if ($functionLike === null) {
- return null;
- }
$variableName = $this->nodeNameResolver->getName($foreach->valueVar);
if ($variableName === null) {
return null;
}
return new VariableAndCallForeach($foreach->valueVar, $call, $variableName, $functionLike);
}
- /**
- * @return \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure|null
- */
- private function getFunctionLike(Foreach_ $foreach)
- {
- return $this->betterNodeFinder->findParentByTypes($foreach, [Closure::class, ClassMethod::class, Function_::class]);
- }
}
diff --git a/rules/Naming/Matcher/VariableAndCallAssignMatcher.php b/rules/Naming/Matcher/VariableAndCallAssignMatcher.php
index b2bd7f563497..436f8b3d0ac3 100644
--- a/rules/Naming/Matcher/VariableAndCallAssignMatcher.php
+++ b/rules/Naming/Matcher/VariableAndCallAssignMatcher.php
@@ -7,7 +7,6 @@
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Variable;
-use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
@@ -36,7 +35,10 @@ public function __construct(\Rector\Naming\Matcher\CallMatcher $callMatcher, Nod
$this->nodeNameResolver = $nodeNameResolver;
$this->betterNodeFinder = $betterNodeFinder;
}
- public function match(Assign $assign) : ?VariableAndCallAssign
+ /**
+ * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Stmt\Function_ $functionLike
+ */
+ public function match(Assign $assign, $functionLike) : ?VariableAndCallAssign
{
$call = $this->callMatcher->matchCall($assign);
if ($call === null) {
@@ -49,10 +51,6 @@ public function match(Assign $assign) : ?VariableAndCallAssign
if ($variableName === null) {
return null;
}
- $functionLike = $this->getFunctionLike($assign);
- if (!$functionLike instanceof FunctionLike) {
- return null;
- }
$isVariableFoundInCallArgs = (bool) $this->betterNodeFinder->findFirst($call->isFirstClassCallable() ? [] : $call->getArgs(), function (Node $subNode) use($variableName) : bool {
return $subNode instanceof Variable && $this->nodeNameResolver->isName($subNode, $variableName);
});
@@ -61,11 +59,4 @@ public function match(Assign $assign) : ?VariableAndCallAssign
}
return new VariableAndCallAssign($assign->var, $call, $assign, $variableName, $functionLike);
}
- /**
- * @return \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure|null
- */
- private function getFunctionLike(Assign $assign)
- {
- return $this->betterNodeFinder->findParentByTypes($assign, [Closure::class, ClassMethod::class, Function_::class]);
- }
}
diff --git a/rules/Naming/Naming/AliasNameResolver.php b/rules/Naming/Naming/AliasNameResolver.php
index a1db5f817f00..ba1be94040cc 100644
--- a/rules/Naming/Naming/AliasNameResolver.php
+++ b/rules/Naming/Naming/AliasNameResolver.php
@@ -18,7 +18,7 @@ public function __construct(\Rector\Naming\Naming\UseImportsResolver $useImports
}
public function resolveByName(Name $name) : ?string
{
- $uses = $this->useImportsResolver->resolveForNode($name);
+ $uses = $this->useImportsResolver->resolve();
$nameString = $name->toString();
foreach ($uses as $use) {
$prefix = $this->useImportsResolver->resolvePrefix($use);
diff --git a/rules/Naming/Naming/ConflictingNameResolver.php b/rules/Naming/Naming/ConflictingNameResolver.php
index 201c8d3162d6..3623c0e1f27b 100644
--- a/rules/Naming/Naming/ConflictingNameResolver.php
+++ b/rules/Naming/Naming/ConflictingNameResolver.php
@@ -14,10 +14,6 @@
use Rector\Naming\PhpArray\ArrayFilter;
final class ConflictingNameResolver
{
- /**
- * @var array
- */
- private $conflictingVariableNamesByClassMethod = [];
/**
* @readonly
* @var \Rector\Naming\PhpArray\ArrayFilter
@@ -43,6 +39,10 @@ final class ConflictingNameResolver
* @var \Rector\Core\NodeManipulator\FunctionLikeManipulator
*/
private $functionLikeManipulator;
+ /**
+ * @var array
+ */
+ private $conflictingVariableNamesByClassMethod = [];
public function __construct(ArrayFilter $arrayFilter, BetterNodeFinder $betterNodeFinder, \Rector\Naming\Naming\ExpectedNameResolver $expectedNameResolver, MatchParamTypeExpectedNameResolver $matchParamTypeExpectedNameResolver, FunctionLikeManipulator $functionLikeManipulator)
{
$this->arrayFilter = $arrayFilter;
diff --git a/rules/Naming/Naming/ExpectedNameResolver.php b/rules/Naming/Naming/ExpectedNameResolver.php
index a77b482393ba..99c6c497d95c 100644
--- a/rules/Naming/Naming/ExpectedNameResolver.php
+++ b/rules/Naming/Naming/ExpectedNameResolver.php
@@ -11,7 +11,6 @@
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name;
use PhpParser\Node\Param;
-use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\UnionType;
use PHPStan\Type\ArrayType;
use PHPStan\Type\MixedType;
@@ -19,8 +18,8 @@
use PHPStan\Type\Type;
use Rector\Naming\ExpectedNameResolver\MatchParamTypeExpectedNameResolver;
use Rector\Naming\ValueObject\ExpectedName;
+use Rector\Naming\ValueObject\VariableAndCallForeach;
use Rector\NodeNameResolver\NodeNameResolver;
-use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
final class ExpectedNameResolver
@@ -141,11 +140,9 @@ public function resolveForCall($expr) : ?string
}
return null;
}
- /**
- * @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall|\PhpParser\Node\Expr\FuncCall $expr
- */
- public function resolveForForeach($expr) : ?string
+ public function resolveForForeach(VariableAndCallForeach $variableAndCallForeach) : ?string
{
+ $expr = $variableAndCallForeach->getCall();
if ($this->isDynamicNameCall($expr)) {
return null;
}
@@ -159,7 +156,7 @@ public function resolveForForeach($expr) : ?string
}
$innerReturnedType = null;
if ($returnedType instanceof ArrayType) {
- $innerReturnedType = $this->resolveReturnTypeFromArrayType($expr, $returnedType);
+ $innerReturnedType = $this->resolveReturnTypeFromArrayType($returnedType);
if (!$innerReturnedType instanceof Type) {
return null;
}
@@ -194,15 +191,8 @@ private function isDynamicNameCall($expr) : bool
}
return $expr->name instanceof FuncCall;
}
- /**
- * @param \PhpParser\Node\Expr\FuncCall|\PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall $expr
- */
- private function resolveReturnTypeFromArrayType($expr, ArrayType $arrayType) : ?Type
+ private function resolveReturnTypeFromArrayType(ArrayType $arrayType) : ?Type
{
- $parentNode = $expr->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentNode instanceof Foreach_) {
- return null;
- }
if (!$arrayType->getItemType() instanceof ObjectType) {
return null;
}
diff --git a/rules/Naming/Naming/OverridenExistingNamesResolver.php b/rules/Naming/Naming/OverridenExistingNamesResolver.php
index a04a52c352ff..31ba632bb67e 100644
--- a/rules/Naming/Naming/OverridenExistingNamesResolver.php
+++ b/rules/Naming/Naming/OverridenExistingNamesResolver.php
@@ -14,10 +14,6 @@
use Rector\NodeNameResolver\NodeNameResolver;
final class OverridenExistingNamesResolver
{
- /**
- * @var array>
- */
- private $overridenExistingVariableNamesByClassMethod = [];
/**
* @readonly
* @var \Rector\Naming\PhpArray\ArrayFilter
@@ -33,6 +29,10 @@ final class OverridenExistingNamesResolver
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
+ /**
+ * @var array>
+ */
+ private $overridenExistingVariableNamesByClassMethod = [];
public function __construct(ArrayFilter $arrayFilter, BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver)
{
$this->arrayFilter = $arrayFilter;
diff --git a/rules/Naming/Naming/PropertyNaming.php b/rules/Naming/Naming/PropertyNaming.php
index a6ffb2e0adf3..5fdc5676b0bb 100644
--- a/rules/Naming/Naming/PropertyNaming.php
+++ b/rules/Naming/Naming/PropertyNaming.php
@@ -23,6 +23,16 @@
*/
final class PropertyNaming
{
+ /**
+ * @readonly
+ * @var \Rector\Naming\RectorNamingInflector
+ */
+ private $rectorNamingInflector;
+ /**
+ * @readonly
+ * @var \Rector\NodeTypeResolver\NodeTypeResolver
+ */
+ private $nodeTypeResolver;
/**
* @var string[]
*/
@@ -45,16 +55,6 @@ final class PropertyNaming
* @var string
*/
private const GET_PREFIX_REGEX = '#^get(?[A-Z].+)#';
- /**
- * @readonly
- * @var \Rector\Naming\RectorNamingInflector
- */
- private $rectorNamingInflector;
- /**
- * @readonly
- * @var \Rector\NodeTypeResolver\NodeTypeResolver
- */
- private $nodeTypeResolver;
public function __construct(RectorNamingInflector $rectorNamingInflector, NodeTypeResolver $nodeTypeResolver)
{
$this->rectorNamingInflector = $rectorNamingInflector;
@@ -184,11 +184,13 @@ private function fqnToShortName(string $fqn) : string
private function removeInterfaceSuffixPrefix(string $className, string $category) : string
{
// suffix
- if (Strings::match($className, '#' . $category . '$#i')) {
+ $iSuffixMatch = Strings::match($className, '#' . $category . '$#i');
+ if ($iSuffixMatch !== null) {
return Strings::substring($className, 0, -\strlen($category));
}
// prefix
- if (Strings::match($className, '#^' . $category . '#i')) {
+ $iPrefixMatch = Strings::match($className, '#^' . $category . '#i');
+ if ($iPrefixMatch !== null) {
return Strings::substring($className, \strlen($category));
}
// starts with "I\W+"?
diff --git a/rules/Naming/Naming/UseImportsResolver.php b/rules/Naming/Naming/UseImportsResolver.php
index 1ad99d497948..58759b9fa204 100644
--- a/rules/Naming/Naming/UseImportsResolver.php
+++ b/rules/Naming/Naming/UseImportsResolver.php
@@ -8,25 +8,26 @@
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Use_;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
+use Rector\Core\Provider\CurrentFileProvider;
+use Rector\Core\ValueObject\Application\File;
final class UseImportsResolver
{
/**
* @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
+ * @var \Rector\Core\Provider\CurrentFileProvider
*/
- private $betterNodeFinder;
- public function __construct(BetterNodeFinder $betterNodeFinder)
+ private $currentFileProvider;
+ public function __construct(CurrentFileProvider $currentFileProvider)
{
- $this->betterNodeFinder = $betterNodeFinder;
+ $this->currentFileProvider = $currentFileProvider;
}
/**
* @return Use_[]|GroupUse[]
*/
- public function resolveForNode(Node $node) : array
+ public function resolve() : array
{
- $namespace = $this->betterNodeFinder->findParentByTypes($node, [Namespace_::class, FileWithoutNamespace::class]);
+ $namespace = $this->resolveNamespace();
if (!$namespace instanceof Node) {
return [];
}
@@ -38,9 +39,9 @@ public function resolveForNode(Node $node) : array
* @api
* @return Use_[]
*/
- public function resolveBareUsesForNode(Node $node) : array
+ public function resolveBareUses() : array
{
- $namespace = $this->betterNodeFinder->findParentByTypes($node, [Namespace_::class, FileWithoutNamespace::class]);
+ $namespace = $this->resolveNamespace();
if (!$namespace instanceof Node) {
return [];
}
@@ -55,4 +56,35 @@ public function resolvePrefix($use) : string
{
return $use instanceof GroupUse ? $use->prefix . '\\' : '';
}
+ /**
+ * @return \PhpParser\Node\Stmt\Namespace_|\Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace|null
+ */
+ private function resolveNamespace()
+ {
+ /** @var File|null $file */
+ $file = $this->currentFileProvider->getFile();
+ if (!$file instanceof File) {
+ return null;
+ }
+ $newStmts = $file->getNewStmts();
+ if ($newStmts === []) {
+ return null;
+ }
+ $namespaces = \array_filter($newStmts, static function (Stmt $stmt) : bool {
+ return $stmt instanceof Namespace_;
+ });
+ // multiple namespaces is not supported
+ if (\count($namespaces) > 1) {
+ return null;
+ }
+ $currentNamespace = \current($namespaces);
+ if ($currentNamespace instanceof Namespace_) {
+ return $currentNamespace;
+ }
+ $currentStmt = \current($newStmts);
+ if (!$currentStmt instanceof FileWithoutNamespace) {
+ return null;
+ }
+ return $currentStmt;
+ }
}
diff --git a/rules/Naming/Naming/VariableNaming.php b/rules/Naming/Naming/VariableNaming.php
index 21d6fd4594d1..fcb1bf00a54b 100644
--- a/rules/Naming/Naming/VariableNaming.php
+++ b/rules/Naming/Naming/VariableNaming.php
@@ -13,12 +13,13 @@
use PhpParser\Node\Expr\NullsafeMethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Ternary;
-use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use PHPStan\Analyser\MutatingScope;
use PHPStan\Analyser\Scope;
use PHPStan\Type\ThisType;
use PHPStan\Type\Type;
+use Rector\Naming\AssignVariableNameResolver\NewAssignVariableNameResolver;
+use Rector\Naming\AssignVariableNameResolver\PropertyFetchAssignVariableNameResolver;
use Rector\Naming\Contract\AssignVariableNameResolverInterface;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
@@ -37,17 +38,13 @@ final class VariableNaming
private $nodeTypeResolver;
/**
* @var AssignVariableNameResolverInterface[]
- * @readonly
- */
- private $assignVariableNameResolvers;
- /**
- * @param AssignVariableNameResolverInterface[] $assignVariableNameResolvers
*/
- public function __construct(NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, array $assignVariableNameResolvers)
+ private $assignVariableNameResolvers = [];
+ public function __construct(NodeNameResolver $nodeNameResolver, NodeTypeResolver $nodeTypeResolver, PropertyFetchAssignVariableNameResolver $propertyFetchAssignVariableNameResolver, NewAssignVariableNameResolver $newAssignVariableNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
$this->nodeTypeResolver = $nodeTypeResolver;
- $this->assignVariableNameResolvers = $assignVariableNameResolvers;
+ $this->assignVariableNameResolvers = [$propertyFetchAssignVariableNameResolver, $newAssignVariableNameResolver];
}
/**
* @api
@@ -163,6 +160,9 @@ private function unwrapNode(Node $node) : ?Node
}
private function resolveBareFuncCallArgumentName(FuncCall $funcCall, string $fallbackName, string $suffix) : string
{
+ if ($funcCall->isFirstClassCallable()) {
+ return '';
+ }
if (!isset($funcCall->getArgs()[0])) {
return '';
}
diff --git a/rules/Naming/PropertyRenamer/MatchTypePropertyRenamer.php b/rules/Naming/PropertyRenamer/MatchTypePropertyRenamer.php
index c41004585fb9..0ffb77e0f286 100644
--- a/rules/Naming/PropertyRenamer/MatchTypePropertyRenamer.php
+++ b/rules/Naming/PropertyRenamer/MatchTypePropertyRenamer.php
@@ -4,30 +4,51 @@
namespace Rector\Naming\PropertyRenamer;
use PhpParser\Node\Stmt\Property;
+use PhpParser\Node\VarLikeIdentifier;
use Rector\Naming\Guard\PropertyConflictingNameGuard\MatchPropertyTypeConflictingNameGuard;
+use Rector\Naming\RenameGuard\PropertyRenameGuard;
use Rector\Naming\ValueObject\PropertyRename;
final class MatchTypePropertyRenamer
{
/**
* @readonly
- * @var \Rector\Naming\PropertyRenamer\PropertyRenamer
+ * @var \Rector\Naming\Guard\PropertyConflictingNameGuard\MatchPropertyTypeConflictingNameGuard
*/
- private $propertyRenamer;
+ private $matchPropertyTypeConflictingNameGuard;
/**
* @readonly
- * @var \Rector\Naming\Guard\PropertyConflictingNameGuard\MatchPropertyTypeConflictingNameGuard
+ * @var \Rector\Naming\RenameGuard\PropertyRenameGuard
*/
- private $matchPropertyTypeConflictingNameGuard;
- public function __construct(\Rector\Naming\PropertyRenamer\PropertyRenamer $propertyRenamer, MatchPropertyTypeConflictingNameGuard $matchPropertyTypeConflictingNameGuard)
+ private $propertyRenameGuard;
+ /**
+ * @readonly
+ * @var \Rector\Naming\PropertyRenamer\PropertyFetchRenamer
+ */
+ private $propertyFetchRenamer;
+ public function __construct(MatchPropertyTypeConflictingNameGuard $matchPropertyTypeConflictingNameGuard, PropertyRenameGuard $propertyRenameGuard, \Rector\Naming\PropertyRenamer\PropertyFetchRenamer $propertyFetchRenamer)
{
- $this->propertyRenamer = $propertyRenamer;
$this->matchPropertyTypeConflictingNameGuard = $matchPropertyTypeConflictingNameGuard;
+ $this->propertyRenameGuard = $propertyRenameGuard;
+ $this->propertyFetchRenamer = $propertyFetchRenamer;
}
public function rename(PropertyRename $propertyRename) : ?Property
{
if ($this->matchPropertyTypeConflictingNameGuard->isConflicting($propertyRename)) {
return null;
}
- return $this->propertyRenamer->rename($propertyRename);
+ if ($propertyRename->isAlreadyExpectedName()) {
+ return null;
+ }
+ if ($this->propertyRenameGuard->shouldSkip($propertyRename)) {
+ return null;
+ }
+ $onlyPropertyProperty = $propertyRename->getPropertyProperty();
+ $onlyPropertyProperty->name = new VarLikeIdentifier($propertyRename->getExpectedName());
+ $this->renamePropertyFetchesInClass($propertyRename);
+ return $propertyRename->getProperty();
+ }
+ private function renamePropertyFetchesInClass(PropertyRename $propertyRename) : void
+ {
+ $this->propertyFetchRenamer->renamePropertyFetchesInClass($propertyRename->getClassLike(), $propertyRename->getCurrentName(), $propertyRename->getExpectedName());
}
}
diff --git a/rules/Naming/PropertyRenamer/PropertyPromotionRenamer.php b/rules/Naming/PropertyRenamer/PropertyPromotionRenamer.php
index 717ae48ba028..7c94e6d0605e 100644
--- a/rules/Naming/PropertyRenamer/PropertyPromotionRenamer.php
+++ b/rules/Naming/PropertyRenamer/PropertyPromotionRenamer.php
@@ -121,17 +121,17 @@ private function renameParamVarNameAndVariableUsage(ClassLike $classLike, ClassM
$this->propertyFetchRenamer->renamePropertyFetchesInClass($classLike, $currentParamName, $desiredPropertyName);
/** @var string $paramVarName */
$paramVarName = $param->var->name;
- $this->renameParamDoc($classMethodPhpDocInfo, $param, $paramVarName, $desiredPropertyName);
+ $this->renameParamDoc($classMethodPhpDocInfo, $classMethod, $param, $paramVarName, $desiredPropertyName);
$param->var = new Variable($desiredPropertyName);
$this->variableRenamer->renameVariableInFunctionLike($classMethod, $paramVarName, $desiredPropertyName);
}
- private function renameParamDoc(PhpDocInfo $phpDocInfo, Param $param, string $paramVarName, string $desiredPropertyName) : void
+ private function renameParamDoc(PhpDocInfo $phpDocInfo, ClassMethod $classMethod, Param $param, string $paramVarName, string $desiredPropertyName) : void
{
$paramTagValueNode = $phpDocInfo->getParamTagValueByName($paramVarName);
if (!$paramTagValueNode instanceof ParamTagValueNode) {
return;
}
- $paramRename = $this->paramRenameFactory->createFromResolvedExpectedName($param, $desiredPropertyName);
+ $paramRename = $this->paramRenameFactory->createFromResolvedExpectedName($classMethod, $param, $desiredPropertyName);
if (!$paramRename instanceof ParamRename) {
return;
}
diff --git a/rules/Naming/PropertyRenamer/PropertyRenamer.php b/rules/Naming/PropertyRenamer/PropertyRenamer.php
deleted file mode 100644
index a2c4fdc7afc1..000000000000
--- a/rules/Naming/PropertyRenamer/PropertyRenamer.php
+++ /dev/null
@@ -1,44 +0,0 @@
-propertyRenameGuard = $propertyRenameGuard;
- $this->propertyFetchRenamer = $propertyFetchRenamer;
- }
- public function rename(PropertyRename $propertyRename) : ?Property
- {
- if ($propertyRename->isAlreadyExpectedName()) {
- return null;
- }
- if ($this->propertyRenameGuard->shouldSkip($propertyRename)) {
- return null;
- }
- $onlyPropertyProperty = $propertyRename->getPropertyProperty();
- $onlyPropertyProperty->name = new VarLikeIdentifier($propertyRename->getExpectedName());
- $this->renamePropertyFetchesInClass($propertyRename);
- return $propertyRename->getProperty();
- }
- private function renamePropertyFetchesInClass(PropertyRename $propertyRename) : void
- {
- $this->propertyFetchRenamer->renamePropertyFetchesInClass($propertyRename->getClassLike(), $propertyRename->getCurrentName(), $propertyRename->getExpectedName());
- }
-}
diff --git a/rules/Naming/Rector/Assign/RenameVariableToMatchMethodCallReturnTypeRector.php b/rules/Naming/Rector/Assign/RenameVariableToMatchMethodCallReturnTypeRector.php
index 7996bc4c6a21..6100fe6a6d57 100644
--- a/rules/Naming/Rector/Assign/RenameVariableToMatchMethodCallReturnTypeRector.php
+++ b/rules/Naming/Rector/Assign/RenameVariableToMatchMethodCallReturnTypeRector.php
@@ -6,8 +6,10 @@
use RectorPrefix202306\Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Expr\Assign;
+use PhpParser\Node\Expr\Closure;
+use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
-use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
+use PhpParser\Node\Stmt\Function_;
use Rector\Core\Rector\AbstractRector;
use Rector\Naming\Guard\BreakingVariableRenameGuard;
use Rector\Naming\Matcher\VariableAndCallAssignMatcher;
@@ -23,11 +25,6 @@
*/
final class RenameVariableToMatchMethodCallReturnTypeRector extends AbstractRector
{
- /**
- * @var string
- * @see https://regex101.com/r/JG5w9j/1
- */
- private const OR_BETWEEN_WORDS_REGEX = '#[a-z]Or[A-Z]#';
/**
* @readonly
* @var \Rector\Naming\Guard\BreakingVariableRenameGuard
@@ -58,6 +55,11 @@ final class RenameVariableToMatchMethodCallReturnTypeRector extends AbstractRect
* @var \Rector\Naming\VariableRenamer
*/
private $variableRenamer;
+ /**
+ * @var string
+ * @see https://regex101.com/r/JG5w9j/1
+ */
+ private const OR_BETWEEN_WORDS_REGEX = '#[a-z]Or[A-Z]#';
public function __construct(BreakingVariableRenameGuard $breakingVariableRenameGuard, ExpectedNameResolver $expectedNameResolver, NamingConventionAnalyzer $namingConventionAnalyzer, VarTagValueNodeRenamer $varTagValueNodeRenamer, VariableAndCallAssignMatcher $variableAndCallAssignMatcher, VariableRenamer $variableRenamer)
{
$this->breakingVariableRenameGuard = $breakingVariableRenameGuard;
@@ -104,10 +106,10 @@ public function getRunner(): Runner
*/
public function getNodeTypes() : array
{
- return [StmtsAwareInterface::class];
+ return [ClassMethod::class, Closure::class, Function_::class];
}
/**
- * @param StmtsAwareInterface $node
+ * @param ClassMethod|Closure|Function_ $node
*/
public function refactor(Node $node) : ?Node
{
@@ -122,7 +124,7 @@ public function refactor(Node $node) : ?Node
continue;
}
$assign = $stmt->expr;
- $variableAndCallAssign = $this->variableAndCallAssignMatcher->match($assign);
+ $variableAndCallAssign = $this->variableAndCallAssignMatcher->match($assign, $node);
if (!$variableAndCallAssign instanceof VariableAndCallAssign) {
return null;
}
diff --git a/rules/Naming/Rector/ClassMethod/RenameParamToMatchTypeRector.php b/rules/Naming/Rector/ClassMethod/RenameParamToMatchTypeRector.php
index 57e580f773a5..dff6ac3f8feb 100644
--- a/rules/Naming/Rector/ClassMethod/RenameParamToMatchTypeRector.php
+++ b/rules/Naming/Rector/ClassMethod/RenameParamToMatchTypeRector.php
@@ -24,10 +24,6 @@
*/
final class RenameParamToMatchTypeRector extends AbstractRector
{
- /**
- * @var bool
- */
- private $hasChanged = \false;
/**
* @readonly
* @var \Rector\Naming\Guard\BreakingVariableRenameGuard
@@ -53,6 +49,10 @@ final class RenameParamToMatchTypeRector extends AbstractRector
* @var \Rector\Naming\ParamRenamer\ParamRenamer
*/
private $paramRenamer;
+ /**
+ * @var bool
+ */
+ private $hasChanged = \false;
public function __construct(BreakingVariableRenameGuard $breakingVariableRenameGuard, ExpectedNameResolver $expectedNameResolver, MatchParamTypeExpectedNameResolver $matchParamTypeExpectedNameResolver, ParamRenameFactory $paramRenameFactory, ParamRenamer $paramRenamer)
{
$this->breakingVariableRenameGuard = $breakingVariableRenameGuard;
@@ -108,7 +108,7 @@ public function refactor(Node $node) : ?Node
if ($expectedName === null) {
continue;
}
- $paramRename = $this->paramRenameFactory->createFromResolvedExpectedName($param, $expectedName);
+ $paramRename = $this->paramRenameFactory->createFromResolvedExpectedName($node, $param, $expectedName);
if (!$paramRename instanceof ParamRename) {
continue;
}
diff --git a/rules/Naming/Rector/Class_/RenamePropertyToMatchTypeRector.php b/rules/Naming/Rector/Class_/RenamePropertyToMatchTypeRector.php
index 9514e99deb02..5eeebaba6494 100644
--- a/rules/Naming/Rector/Class_/RenamePropertyToMatchTypeRector.php
+++ b/rules/Naming/Rector/Class_/RenamePropertyToMatchTypeRector.php
@@ -21,10 +21,6 @@
*/
final class RenamePropertyToMatchTypeRector extends AbstractRector
{
- /**
- * @var bool
- */
- private $hasChanged = \false;
/**
* @readonly
* @var \Rector\Naming\PropertyRenamer\MatchTypePropertyRenamer
@@ -45,6 +41,10 @@ final class RenamePropertyToMatchTypeRector extends AbstractRector
* @var \Rector\Naming\PropertyRenamer\PropertyPromotionRenamer
*/
private $propertyPromotionRenamer;
+ /**
+ * @var bool
+ */
+ private $hasChanged = \false;
public function __construct(MatchTypePropertyRenamer $matchTypePropertyRenamer, PropertyRenameFactory $propertyRenameFactory, MatchPropertyTypeExpectedNameResolver $matchPropertyTypeExpectedNameResolver, PropertyPromotionRenamer $propertyPromotionRenamer)
{
$this->matchTypePropertyRenamer = $matchTypePropertyRenamer;
@@ -113,7 +113,7 @@ private function refactorClassProperties(ClassLike $classLike) : void
if ($expectedPropertyName === null) {
continue;
}
- $propertyRename = $this->propertyRenameFactory->createFromExpectedName($property, $expectedPropertyName);
+ $propertyRename = $this->propertyRenameFactory->createFromExpectedName($classLike, $property, $expectedPropertyName);
if (!$propertyRename instanceof PropertyRename) {
continue;
}
diff --git a/rules/Naming/Rector/Foreach_/RenameForeachValueVariableToMatchMethodCallReturnTypeRector.php b/rules/Naming/Rector/Foreach_/RenameForeachValueVariableToMatchMethodCallReturnTypeRector.php
index 5d2bd0798a32..985110955936 100644
--- a/rules/Naming/Rector/Foreach_/RenameForeachValueVariableToMatchMethodCallReturnTypeRector.php
+++ b/rules/Naming/Rector/Foreach_/RenameForeachValueVariableToMatchMethodCallReturnTypeRector.php
@@ -4,7 +4,12 @@
namespace Rector\Naming\Rector\Foreach_;
use PhpParser\Node;
+use PhpParser\Node\Expr\Closure;
+use PhpParser\Node\Stmt\Class_;
+use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Foreach_;
+use PhpParser\Node\Stmt\Function_;
+use PhpParser\NodeTraverser;
use Rector\Core\Rector\AbstractRector;
use Rector\Naming\Guard\BreakingVariableRenameGuard;
use Rector\Naming\Matcher\ForeachMatcher;
@@ -85,28 +90,46 @@ public function run()
*/
public function getNodeTypes() : array
{
- return [Foreach_::class];
+ return [ClassMethod::class, Closure::class, Function_::class];
}
/**
- * @param Foreach_ $node
+ * @param ClassMethod|Closure|Function_ $node
*/
public function refactor(Node $node) : ?Node
{
- $variableAndCallForeach = $this->foreachMatcher->match($node);
- if (!$variableAndCallForeach instanceof VariableAndCallForeach) {
+ if ($node->stmts === null) {
return null;
}
- $expectedName = $this->expectedNameResolver->resolveForForeach($variableAndCallForeach->getCall());
- if ($expectedName === null) {
+ $hasRenamed = \false;
+ $this->traverseNodesWithCallable($node->stmts, function (Node $subNode) use($node, &$hasRenamed) : ?int {
+ if ($subNode instanceof Class_ || $subNode instanceof Closure || $subNode instanceof Function_) {
+ return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
+ }
+ if (!$subNode instanceof Foreach_) {
+ return null;
+ }
+ $variableAndCallForeach = $this->foreachMatcher->match($subNode, $node);
+ if (!$variableAndCallForeach instanceof VariableAndCallForeach) {
+ return null;
+ }
+ $expectedName = $this->expectedNameResolver->resolveForForeach($variableAndCallForeach);
+ if ($expectedName === null) {
+ return null;
+ }
+ if ($this->isName($variableAndCallForeach->getVariable(), $expectedName)) {
+ return null;
+ }
+ if ($this->shouldSkip($variableAndCallForeach, $expectedName)) {
+ return null;
+ }
+ $hasChanged = $this->variableRenamer->renameVariableInFunctionLike($variableAndCallForeach->getFunctionLike(), $variableAndCallForeach->getVariableName(), $expectedName, null);
+ // use different variable on purpose to avoid variable re-assign back to false
+ // after go to other method
+ if ($hasChanged) {
+ $hasRenamed = \true;
+ }
return null;
- }
- if ($this->isName($variableAndCallForeach->getVariable(), $expectedName)) {
- return null;
- }
- if ($this->shouldSkip($variableAndCallForeach, $expectedName)) {
- return null;
- }
- $hasRenamed = $this->variableRenamer->renameVariableInFunctionLike($variableAndCallForeach->getFunctionLike(), $variableAndCallForeach->getVariableName(), $expectedName, null);
+ });
if ($hasRenamed) {
return $node;
}
diff --git a/rules/Naming/RectorNamingInflector.php b/rules/Naming/RectorNamingInflector.php
index 6f28c448135f..e3372d5016cf 100644
--- a/rules/Naming/RectorNamingInflector.php
+++ b/rules/Naming/RectorNamingInflector.php
@@ -7,16 +7,16 @@
use RectorPrefix202306\Nette\Utils\Strings;
final class RectorNamingInflector
{
- /**
- * @var string
- * @see https://regex101.com/r/VqVvke/3
- */
- private const DATA_INFO_SUFFIX_REGEX = '#^(?.+)(?Data|Info)$#';
/**
* @readonly
* @var \Doctrine\Inflector\Inflector
*/
private $inflector;
+ /**
+ * @var string
+ * @see https://regex101.com/r/VqVvke/3
+ */
+ private const DATA_INFO_SUFFIX_REGEX = '#^(?.+)(?Data|Info)$#';
public function __construct(Inflector $inflector)
{
$this->inflector = $inflector;
diff --git a/rules/Naming/RenameGuard/PropertyRenameGuard.php b/rules/Naming/RenameGuard/PropertyRenameGuard.php
index b73843146320..ceacbacb3d6b 100644
--- a/rules/Naming/RenameGuard/PropertyRenameGuard.php
+++ b/rules/Naming/RenameGuard/PropertyRenameGuard.php
@@ -3,29 +3,45 @@
declare (strict_types=1);
namespace Rector\Naming\RenameGuard;
-use Rector\Naming\Contract\Guard\ConflictingNameGuardInterface;
+use PHPStan\Type\ObjectType;
+use Rector\Naming\Guard\DateTimeAtNamingConventionGuard;
+use Rector\Naming\Guard\HasMagicGetSetGuard;
use Rector\Naming\ValueObject\PropertyRename;
+use Rector\NodeTypeResolver\NodeTypeResolver;
final class PropertyRenameGuard
{
/**
- * @var ConflictingNameGuardInterface[]
* @readonly
+ * @var \Rector\NodeTypeResolver\NodeTypeResolver
*/
- private $conflictingNameGuards;
+ private $nodeTypeResolver;
/**
- * @param ConflictingNameGuardInterface[] $conflictingNameGuards
+ * @readonly
+ * @var \Rector\Naming\Guard\DateTimeAtNamingConventionGuard
+ */
+ private $dateTimeAtNamingConventionGuard;
+ /**
+ * @readonly
+ * @var \Rector\Naming\Guard\HasMagicGetSetGuard
*/
- public function __construct(array $conflictingNameGuards)
+ private $hasMagicGetSetGuard;
+ public function __construct(NodeTypeResolver $nodeTypeResolver, DateTimeAtNamingConventionGuard $dateTimeAtNamingConventionGuard, HasMagicGetSetGuard $hasMagicGetSetGuard)
{
- $this->conflictingNameGuards = $conflictingNameGuards;
+ $this->nodeTypeResolver = $nodeTypeResolver;
+ $this->dateTimeAtNamingConventionGuard = $dateTimeAtNamingConventionGuard;
+ $this->hasMagicGetSetGuard = $hasMagicGetSetGuard;
}
public function shouldSkip(PropertyRename $propertyRename) : bool
{
- foreach ($this->conflictingNameGuards as $conflictingNameGuard) {
- if ($conflictingNameGuard->isConflicting($propertyRename)) {
- return \true;
- }
+ if (!$propertyRename->isPrivateProperty()) {
+ return \true;
+ }
+ if ($this->nodeTypeResolver->isObjectType($propertyRename->getProperty(), new ObjectType('Ramsey\\Uuid\\UuidInterface'))) {
+ return \true;
+ }
+ if ($this->dateTimeAtNamingConventionGuard->isConflicting($propertyRename)) {
+ return \true;
}
- return \false;
+ return $this->hasMagicGetSetGuard->isConflicting($propertyRename);
}
}
diff --git a/rules/Naming/ValueObject/ParamRename.php b/rules/Naming/ValueObject/ParamRename.php
index 935207a959e3..084c7ab4d952 100644
--- a/rules/Naming/ValueObject/ParamRename.php
+++ b/rules/Naming/ValueObject/ParamRename.php
@@ -3,12 +3,9 @@
declare (strict_types=1);
namespace Rector\Naming\ValueObject;
-use PhpParser\Node\Expr\ArrowFunction;
-use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Variable;
+use PhpParser\Node\FunctionLike;
use PhpParser\Node\Param;
-use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\Function_;
use Rector\Naming\Contract\RenameParamValueObjectInterface;
final class ParamRename implements RenameParamValueObjectInterface
{
@@ -34,13 +31,10 @@ final class ParamRename implements RenameParamValueObjectInterface
private $variable;
/**
* @readonly
- * @var \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Expr\ArrowFunction
+ * @var \PhpParser\Node\FunctionLike
*/
private $functionLike;
- /**
- * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Expr\ArrowFunction $functionLike
- */
- public function __construct(string $currentName, string $expectedName, Param $param, Variable $variable, $functionLike)
+ public function __construct(string $currentName, string $expectedName, Param $param, Variable $variable, FunctionLike $functionLike)
{
$this->currentName = $currentName;
$this->expectedName = $expectedName;
@@ -56,10 +50,7 @@ public function getExpectedName() : string
{
return $this->expectedName;
}
- /**
- * @return \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Expr\ArrowFunction
- */
- public function getFunctionLike()
+ public function getFunctionLike() : FunctionLike
{
return $this->functionLike;
}
diff --git a/rules/Naming/ValueObjectFactory/ParamRenameFactory.php b/rules/Naming/ValueObjectFactory/ParamRenameFactory.php
index ed445e664558..9485b7b6d265 100644
--- a/rules/Naming/ValueObjectFactory/ParamRenameFactory.php
+++ b/rules/Naming/ValueObjectFactory/ParamRenameFactory.php
@@ -3,15 +3,9 @@
declare (strict_types=1);
namespace Rector\Naming\ValueObjectFactory;
-use PhpParser\Node\Expr\ArrowFunction;
-use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Error;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Param;
-use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\Function_;
-use Rector\Core\Exception\ShouldNotHappenException;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Naming\ValueObject\ParamRename;
use Rector\NodeNameResolver\NodeNameResolver;
final class ParamRenameFactory
@@ -21,26 +15,15 @@ final class ParamRenameFactory
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- public function __construct(NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder)
+ public function __construct(NodeNameResolver $nodeNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
- $this->betterNodeFinder = $betterNodeFinder;
}
- public function createFromResolvedExpectedName(Param $param, string $expectedName) : ?ParamRename
+ public function createFromResolvedExpectedName(FunctionLike $functionLike, Param $param, string $expectedName) : ?ParamRename
{
if ($param->var instanceof Error) {
return null;
}
- /** @var ClassMethod|Function_|Closure|ArrowFunction|null $functionLike */
- $functionLike = $this->betterNodeFinder->findParentType($param, FunctionLike::class);
- if ($functionLike === null) {
- throw new ShouldNotHappenException("There shouldn't be a param outside of FunctionLike");
- }
$currentName = $this->nodeNameResolver->getName($param->var);
if ($currentName === null) {
return null;
diff --git a/rules/Naming/ValueObjectFactory/PropertyRenameFactory.php b/rules/Naming/ValueObjectFactory/PropertyRenameFactory.php
index 908c10793b4a..ac7bd6e028a7 100644
--- a/rules/Naming/ValueObjectFactory/PropertyRenameFactory.php
+++ b/rules/Naming/ValueObjectFactory/PropertyRenameFactory.php
@@ -5,7 +5,6 @@
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Property;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Naming\ValueObject\PropertyRename;
use Rector\NodeNameResolver\NodeNameResolver;
final class PropertyRenameFactory
@@ -15,23 +14,13 @@ final class PropertyRenameFactory
* @var \Rector\NodeNameResolver\NodeNameResolver
*/
private $nodeNameResolver;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- public function __construct(NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder)
+ public function __construct(NodeNameResolver $nodeNameResolver)
{
$this->nodeNameResolver = $nodeNameResolver;
- $this->betterNodeFinder = $betterNodeFinder;
}
- public function createFromExpectedName(Property $property, string $expectedName) : ?PropertyRename
+ public function createFromExpectedName(ClassLike $classLike, Property $property, string $expectedName) : ?PropertyRename
{
$currentName = $this->nodeNameResolver->getName($property);
- $classLike = $this->betterNodeFinder->findParentType($property, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
- return null;
- }
$className = (string) $this->nodeNameResolver->getName($classLike);
return new PropertyRename($property, $expectedName, $currentName, $classLike, $className, $property->props[0]);
}
diff --git a/rules/Naming/VariableRenamer.php b/rules/Naming/VariableRenamer.php
index eb0fa6f74e08..2e40fc944025 100644
--- a/rules/Naming/VariableRenamer.php
+++ b/rules/Naming/VariableRenamer.php
@@ -4,17 +4,15 @@
namespace Rector\Naming;
use PhpParser\Node;
-use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Variable;
+use PhpParser\Node\FunctionLike;
use PhpParser\Node\Param;
-use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\Function_;
+use PhpParser\Node\Stmt;
use PhpParser\NodeTraverser;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfo;
use Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Naming\PhpDoc\VarTagValueNodeRenamer;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser;
@@ -40,30 +38,23 @@ final class VariableRenamer
* @var \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory
*/
private $phpDocInfoFactory;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- public function __construct(SimpleCallableNodeTraverser $simpleCallableNodeTraverser, NodeNameResolver $nodeNameResolver, VarTagValueNodeRenamer $varTagValueNodeRenamer, PhpDocInfoFactory $phpDocInfoFactory, BetterNodeFinder $betterNodeFinder)
+ public function __construct(SimpleCallableNodeTraverser $simpleCallableNodeTraverser, NodeNameResolver $nodeNameResolver, VarTagValueNodeRenamer $varTagValueNodeRenamer, PhpDocInfoFactory $phpDocInfoFactory)
{
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
$this->nodeNameResolver = $nodeNameResolver;
$this->varTagValueNodeRenamer = $varTagValueNodeRenamer;
$this->phpDocInfoFactory = $phpDocInfoFactory;
- $this->betterNodeFinder = $betterNodeFinder;
}
- /**
- * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Expr\ArrowFunction $functionLike
- */
- public function renameVariableInFunctionLike($functionLike, string $oldName, string $expectedName, ?Assign $assign = null) : bool
+ public function renameVariableInFunctionLike(FunctionLike $functionLike, string $oldName, string $expectedName, ?Assign $assign = null) : bool
{
$isRenamingActive = \false;
if (!$assign instanceof Assign) {
$isRenamingActive = \true;
}
$hasRenamed = \false;
- $this->simpleCallableNodeTraverser->traverseNodesWithCallable((array) $functionLike->getStmts(), function (Node $node) use($oldName, $expectedName, $assign, &$isRenamingActive, &$hasRenamed) {
+ $currentStmt = null;
+ $currentClosure = null;
+ $this->simpleCallableNodeTraverser->traverseNodesWithCallable((array) $functionLike->getStmts(), function (Node $node) use($oldName, $expectedName, $assign, &$isRenamingActive, &$hasRenamed, &$currentStmt, &$currentClosure) {
// skip param names
if ($node instanceof Param) {
return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
@@ -72,18 +63,23 @@ public function renameVariableInFunctionLike($functionLike, string $oldName, str
$isRenamingActive = \true;
return null;
}
+ if ($node instanceof Stmt) {
+ $currentStmt = $node;
+ }
+ if ($node instanceof Closure) {
+ $currentClosure = $node;
+ }
if (!$node instanceof Variable) {
return null;
}
- // TODO: Remove in next PR (with above param check?),
// TODO: Should be implemented in BreakingVariableRenameGuard::shouldSkipParam()
- if ($this->isParamInParentFunction($node)) {
+ if ($this->isParamInParentFunction($node, $currentClosure)) {
return null;
}
if (!$isRenamingActive) {
return null;
}
- $variable = $this->renameVariableIfMatchesName($node, $oldName, $expectedName);
+ $variable = $this->renameVariableIfMatchesName($node, $oldName, $expectedName, $currentStmt);
if ($variable instanceof Variable) {
$hasRenamed = \true;
}
@@ -91,9 +87,8 @@ public function renameVariableInFunctionLike($functionLike, string $oldName, str
});
return $hasRenamed;
}
- private function isParamInParentFunction(Variable $variable) : bool
+ private function isParamInParentFunction(Variable $variable, ?Closure $closure) : bool
{
- $closure = $this->betterNodeFinder->findParentType($variable, Closure::class);
if (!$closure instanceof Closure) {
return \false;
}
@@ -108,23 +103,22 @@ private function isParamInParentFunction(Variable $variable) : bool
}
return \false;
}
- private function renameVariableIfMatchesName(Variable $variable, string $oldName, string $expectedName) : ?Variable
+ private function renameVariableIfMatchesName(Variable $variable, string $oldName, string $expectedName, ?Stmt $currentStmt) : ?Variable
{
if (!$this->nodeNameResolver->isName($variable, $oldName)) {
return null;
}
$variable->name = $expectedName;
- $variablePhpDocInfo = $this->resolvePhpDocInfo($variable);
+ $variablePhpDocInfo = $this->resolvePhpDocInfo($variable, $currentStmt);
$this->varTagValueNodeRenamer->renameAssignVarTagVariableName($variablePhpDocInfo, $oldName, $expectedName);
return $variable;
}
/**
* Expression doc block has higher priority
*/
- private function resolvePhpDocInfo(Variable $variable) : PhpDocInfo
+ private function resolvePhpDocInfo(Variable $variable, ?Stmt $currentStmt) : PhpDocInfo
{
- $currentStmt = $this->betterNodeFinder->resolveCurrentStatement($variable);
- if ($currentStmt instanceof Node) {
+ if ($currentStmt instanceof Stmt) {
return $this->phpDocInfoFactory->createFromNodeOrEmpty($currentStmt);
}
return $this->phpDocInfoFactory->createFromNodeOrEmpty($variable);
diff --git a/rules/PSR4/Composer/PSR4AutoloadPathsProvider.php b/rules/PSR4/Composer/PSR4AutoloadPathsProvider.php
deleted file mode 100644
index 2c0022118b22..000000000000
--- a/rules/PSR4/Composer/PSR4AutoloadPathsProvider.php
+++ /dev/null
@@ -1,43 +0,0 @@
->
- */
- private $cachedComposerJsonPSR4AutoloadPaths = [];
- /**
- * @return array
- */
- public function provide() : array
- {
- if ($this->cachedComposerJsonPSR4AutoloadPaths !== []) {
- return $this->cachedComposerJsonPSR4AutoloadPaths;
- }
- $fileContents = FileSystem::read($this->getComposerJsonPath());
- $composerJson = Json::decode($fileContents, Json::FORCE_ARRAY);
- $psr4Autoloads = \array_merge($composerJson['autoload']['psr-4'] ?? [], $composerJson['autoload-dev']['psr-4'] ?? []);
- $this->cachedComposerJsonPSR4AutoloadPaths = $this->removeEmptyNamespaces($psr4Autoloads);
- return $this->cachedComposerJsonPSR4AutoloadPaths;
- }
- private function getComposerJsonPath() : string
- {
- // assume the project has "composer.json" in root directory
- return \getcwd() . '/composer.json';
- }
- /**
- * @param array> $psr4Autoloads
- * @return array>
- */
- private function removeEmptyNamespaces(array $psr4Autoloads) : array
- {
- return \array_filter($psr4Autoloads, static function (string $psr4Autoload) : bool {
- return $psr4Autoload !== '';
- }, \ARRAY_FILTER_USE_KEY);
- }
-}
diff --git a/rules/PSR4/Composer/PSR4NamespaceMatcher.php b/rules/PSR4/Composer/PSR4NamespaceMatcher.php
deleted file mode 100644
index fc6dc9a49aef..000000000000
--- a/rules/PSR4/Composer/PSR4NamespaceMatcher.php
+++ /dev/null
@@ -1,63 +0,0 @@
-psr4AutoloadPathsProvider = $psr4AutoloadPathsProvider;
- $this->filePathHelper = $filePathHelper;
- }
- public function getExpectedNamespace(File $file, Node $node) : ?string
- {
- $filePath = $file->getFilePath();
- $psr4Autoloads = $this->psr4AutoloadPathsProvider->provide();
- foreach ($psr4Autoloads as $namespace => $path) {
- // remove extra slash
- $paths = \is_array($path) ? $path : [$path];
- foreach ($paths as $path) {
- $relativeFilePath = $this->filePathHelper->relativePath($filePath);
- $relativeDirectoryPath = \dirname($relativeFilePath);
- $path = \rtrim($path, '/');
- if (\strncmp($relativeDirectoryPath, $path, \strlen($path)) !== 0) {
- continue;
- }
- $expectedNamespace = $namespace . $this->resolveExtraNamespace($relativeDirectoryPath, $path);
- if (\strpos($expectedNamespace, '-') !== \false) {
- return null;
- }
- return \rtrim($expectedNamespace, '\\');
- }
- }
- return null;
- }
- /**
- * Get the extra path that is not included in root PSR-4 namespace
- */
- private function resolveExtraNamespace(string $relativeDirectoryPath, string $path) : string
- {
- $extraNamespace = Strings::substring($relativeDirectoryPath, Strings::length($path) + 1);
- $extraNamespace = Strings::replace($extraNamespace, '#/#', '\\');
- return \trim($extraNamespace);
- }
-}
diff --git a/rules/PSR4/Contract/PSR4AutoloadNamespaceMatcherInterface.php b/rules/PSR4/Contract/PSR4AutoloadNamespaceMatcherInterface.php
deleted file mode 100644
index f15c6a7650a4..000000000000
--- a/rules/PSR4/Contract/PSR4AutoloadNamespaceMatcherInterface.php
+++ /dev/null
@@ -1,11 +0,0 @@
-name instanceof Identifier) {
- return \false;
- }
- $classShortName = $classLike->name->toString();
- $baseFilename = \pathinfo($file->getFilePath(), \PATHINFO_FILENAME);
- return $baseFilename === $classShortName;
- }
-}
diff --git a/rules/PSR4/NodeManipulator/FullyQualifyStmtsAnalyzer.php b/rules/PSR4/NodeManipulator/FullyQualifyStmtsAnalyzer.php
deleted file mode 100644
index ba91eb42b21b..000000000000
--- a/rules/PSR4/NodeManipulator/FullyQualifyStmtsAnalyzer.php
+++ /dev/null
@@ -1,95 +0,0 @@
-parameterProvider = $parameterProvider;
- $this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
- $this->nodeNameResolver = $nodeNameResolver;
- $this->reflectionProvider = $reflectionProvider;
- }
- /**
- * @param Stmt[] $stmts
- */
- public function process(array $stmts, Scope $scope) : void
- {
- // no need to
- if ($this->parameterProvider->provideBoolParameter(Option::AUTO_IMPORT_NAMES)) {
- return;
- }
- // FQNize all class names
- $this->simpleCallableNodeTraverser->traverseNodesWithCallable($stmts, function (Node $node) use($scope) : ?FullyQualified {
- if (!$node instanceof Name) {
- return null;
- }
- $name = $this->nodeNameResolver->getName($node);
- if (\in_array($name, [ObjectReference::STATIC, ObjectReference::PARENT, ObjectReference::SELF], \true)) {
- return null;
- }
- if ($this->isNativeConstant($node, $scope)) {
- return null;
- }
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentNode instanceof GroupUse) {
- $parentNode->setAttribute(AttributeKey::ORIGINAL_NODE, null);
- return null;
- }
- if ($parentNode instanceof UseUse) {
- return null;
- }
- return new FullyQualified($name);
- });
- }
- private function isNativeConstant(Name $name, Scope $scope) : bool
- {
- $parentNode = $name->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentNode instanceof ConstFetch) {
- return \false;
- }
- if (!$this->reflectionProvider->hasConstant($name, $scope)) {
- return \false;
- }
- $globalConstantReflection = $this->reflectionProvider->getConstant($name, $scope);
- return $globalConstantReflection instanceof RuntimeConstantReflection;
- }
-}
diff --git a/rules/PSR4/NodeManipulator/NamespaceManipulator.php b/rules/PSR4/NodeManipulator/NamespaceManipulator.php
deleted file mode 100644
index 2a479d8c34be..000000000000
--- a/rules/PSR4/NodeManipulator/NamespaceManipulator.php
+++ /dev/null
@@ -1,19 +0,0 @@
-stmts as $key => $namespaceStatement) {
- if (!$namespaceStatement instanceof ClassLike) {
- continue;
- }
- unset($namespace->stmts[$key]);
- }
- }
-}
diff --git a/rules/PSR4/Rector/FileWithoutNamespace/NormalizeNamespaceByPSR4ComposerAutoloadRector.php b/rules/PSR4/Rector/FileWithoutNamespace/NormalizeNamespaceByPSR4ComposerAutoloadRector.php
deleted file mode 100644
index 605806bcd857..000000000000
--- a/rules/PSR4/Rector/FileWithoutNamespace/NormalizeNamespaceByPSR4ComposerAutoloadRector.php
+++ /dev/null
@@ -1,140 +0,0 @@
-psr4AutoloadNamespaceMatcher = $psr4AutoloadNamespaceMatcher;
- $this->fullyQualifyStmtsAnalyzer = $fullyQualifyStmtsAnalyzer;
- $this->inlineHTMLAnalyzer = $inlineHTMLAnalyzer;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- $description = \sprintf('Adds namespace to namespace-less files or correct namespace to match PSR-4 in `composer.json` autoload section. Run with combination with "%s"', MultipleClassFileToPsr4ClassesRector::class);
- return new RuleDefinition($description, [new ComposerJsonAwareCodeSample(<<<'CODE_SAMPLE'
-// src/SomeClass.php
-
-class SomeClass
-{
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-// src/SomeClass.php
-
-namespace App\CustomNamespace;
-
-class SomeClass
-{
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-{
- "autoload": {
- "psr-4": {
- "App\\CustomNamespace\\": "src"
- }
- }
-}
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [Namespace_::class, FileWithoutNamespace::class];
- }
- /**
- * @param FileWithoutNamespace|Namespace_ $node
- * @return Node|null|Stmt[]
- */
- public function refactorWithScope(Node $node, Scope $scope)
- {
- if ($this->inlineHTMLAnalyzer->hasInlineHTML($node)) {
- return null;
- }
- $expectedNamespace = $this->psr4AutoloadNamespaceMatcher->getExpectedNamespace($this->file, $node);
- if ($expectedNamespace === null) {
- return null;
- }
- // is namespace and already correctly named?
- if ($node instanceof Namespace_ && $this->nodeNameResolver->isCaseSensitiveName($node, $expectedNamespace)) {
- return null;
- }
- if ($node instanceof Namespace_ && $this->hasNamespaceInPreviousNamespace($node)) {
- return null;
- }
- // to put declare_strict types on correct place
- if ($node instanceof FileWithoutNamespace) {
- return $this->refactorFileWithoutNamespace($node, $expectedNamespace, $scope);
- }
- $node->name = new Name($expectedNamespace);
- $this->fullyQualifyStmtsAnalyzer->process($node->stmts, $scope);
- return $node;
- }
- private function hasNamespaceInPreviousNamespace(Namespace_ $namespace) : bool
- {
- return (bool) $this->betterNodeFinder->findFirstPrevious($namespace, static function (Node $node) : bool {
- return $node instanceof Namespace_;
- });
- }
- /**
- * @return Namespace_|Stmt[]
- */
- private function refactorFileWithoutNamespace(FileWithoutNamespace $fileWithoutNamespace, string $expectedNamespace, Scope $scope)
- {
- $nodes = $fileWithoutNamespace->stmts;
- $declare = null;
- foreach ($nodes as $key => $fileWithoutNamespace) {
- if ($key > 0) {
- break;
- }
- if ($fileWithoutNamespace instanceof Declare_) {
- $declare = $fileWithoutNamespace;
- unset($nodes[$key]);
- }
- }
- $namespace = new Namespace_(new Name($expectedNamespace), $nodes);
- $this->fullyQualifyStmtsAnalyzer->process($nodes, $scope);
- if ($declare instanceof Declare_) {
- return [$declare, $namespace];
- }
- return $namespace;
- }
-}
diff --git a/rules/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector.php b/rules/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector.php
deleted file mode 100644
index 0bf6e84949f8..000000000000
--- a/rules/PSR4/Rector/Namespace_/MultipleClassFileToPsr4ClassesRector.php
+++ /dev/null
@@ -1,187 +0,0 @@
-namespaceManipulator = $namespaceManipulator;
- $this->fileInfoDeletionAnalyzer = $fileInfoDeletionAnalyzer;
- $this->neighbourClassLikePrinter = $neighbourClassLikePrinter;
- $this->removedAndAddedFilesCollector = $removedAndAddedFilesCollector;
- $this->classAnalyzer = $classAnalyzer;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Change multiple classes in one file to standalone PSR-4 classes.', [new CodeSample(<<<'CODE_SAMPLE'
-namespace App\Exceptions;
-
-use Exception;
-
-final class FirstException extends Exception
-{
-}
-
-final class SecondException extends Exception
-{
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-// new file: "app/Exceptions/FirstException.php"
-namespace App\Exceptions;
-
-use Exception;
-
-final class FirstException extends Exception
-{
-}
-
-// new file: "app/Exceptions/SecondException.php"
-namespace App\Exceptions;
-
-use Exception;
-
-final class SecondException extends Exception
-{
-}
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [Namespace_::class, FileWithoutNamespace::class];
- }
- /**
- * @param Namespace_|FileWithoutNamespace $node
- */
- public function refactor(Node $node) : ?Node
- {
- if (!$this->hasAtLeastTwoClassLikes($node)) {
- return null;
- }
- $nodeToReturn = null;
- if ($node instanceof Namespace_) {
- $nodeToReturn = $this->refactorNamespace($node);
- }
- if ($node instanceof FileWithoutNamespace) {
- $nodeToReturn = $this->refactorFileWithoutNamespace($node);
- }
- // 1. remove this node
- if ($nodeToReturn instanceof Node) {
- return $nodeToReturn;
- }
- $isInAddedFiles = (bool) \array_filter($this->removedAndAddedFilesCollector->getAddedFilesWithContent(), function (AddedFileWithContent $addedFileWithContent) : bool {
- return $addedFileWithContent->getFilePath() === $this->file->getFilePath();
- });
- if ($isInAddedFiles === \false) {
- // 2. nothing to return - remove the file
- $this->removedAndAddedFilesCollector->removeFile($this->file->getFilePath());
- }
- return $node;
- }
- private function hasAtLeastTwoClassLikes(Node $node) : bool
- {
- $nonAnonymousClassLikes = $this->findNonAnonymousClassLikes($node);
- return \count($nonAnonymousClassLikes) > 1;
- }
- private function refactorNamespace(Namespace_ $namespace) : ?Namespace_
- {
- $classLikes = $this->findNonAnonymousClassLikes($namespace);
- $this->namespaceManipulator->removeClassLikes($namespace);
- $nodeToReturn = null;
- foreach ($classLikes as $classLike) {
- $newNamespace = clone $namespace;
- $newNamespace->stmts[] = $classLike;
- // 1. is the class that will be kept in original file?
- if ($this->fileInfoDeletionAnalyzer->isClassLikeAndFileInfoMatch($this->file, $classLike)) {
- $nodeToReturn = $newNamespace;
- continue;
- }
- $this->printNewNodes($classLike, $newNamespace);
- }
- return $nodeToReturn;
- }
- private function refactorFileWithoutNamespace(FileWithoutNamespace $fileWithoutNamespace) : ?FileWithoutNamespace
- {
- $classLikes = $this->findNonAnonymousClassLikes($fileWithoutNamespace);
- $nodeToReturn = null;
- foreach ($classLikes as $classLike) {
- // 1. is the class that will be kept in original file?
- if ($this->fileInfoDeletionAnalyzer->isClassLikeAndFileInfoMatch($this->file, $classLike)) {
- $nodeToReturn = $fileWithoutNamespace;
- continue;
- }
- // 2. is new file
- $this->printNewNodes($classLike, $fileWithoutNamespace);
- }
- return $nodeToReturn;
- }
- /**
- * @param \PhpParser\Node\Stmt\Namespace_|\Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace $mainNode
- */
- private function printNewNodes(ClassLike $classLike, $mainNode) : void
- {
- $filePath = $this->file->getFilePath();
- $this->neighbourClassLikePrinter->printClassLike($classLike, $mainNode, $filePath, $this->file);
- }
- /**
- * @return ClassLike[]
- */
- private function findNonAnonymousClassLikes(Node $node) : array
- {
- $classLikes = $this->betterNodeFinder->findInstanceOf([$node], ClassLike::class);
- return \array_filter($classLikes, function (ClassLike $classLike) : bool {
- if (!$classLike instanceof Class_) {
- return \true;
- }
- return !$this->classAnalyzer->isAnonymousClass($classLike);
- });
- }
-}
diff --git a/rules/Php53/Rector/FuncCall/DirNameFileConstantToDirConstantRector.php b/rules/Php53/Rector/FuncCall/DirNameFileConstantToDirConstantRector.php
index 563f900aa3ab..d64f720a0cff 100644
--- a/rules/Php53/Rector/FuncCall/DirNameFileConstantToDirConstantRector.php
+++ b/rules/Php53/Rector/FuncCall/DirNameFileConstantToDirConstantRector.php
@@ -54,6 +54,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'dirname')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (\count($node->args) !== 1) {
return null;
}
diff --git a/rules/Php55/Rector/ClassConstFetch/StaticToSelfOnFinalClassRector.php b/rules/Php55/Rector/ClassConstFetch/StaticToSelfOnFinalClassRector.php
index 676768941d58..8d4abb13f47f 100644
--- a/rules/Php55/Rector/ClassConstFetch/StaticToSelfOnFinalClassRector.php
+++ b/rules/Php55/Rector/ClassConstFetch/StaticToSelfOnFinalClassRector.php
@@ -5,8 +5,6 @@
use PhpParser\Node;
use PhpParser\Node\Expr\ClassConstFetch;
-use PhpParser\Node\Identifier;
-use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\Enum\ObjectReference;
use Rector\Core\Rector\AbstractRector;
@@ -48,33 +46,34 @@ public function callOnMe()
*/
public function getNodeTypes() : array
{
- return [ClassConstFetch::class];
+ return [Class_::class];
}
/**
- * @param ClassConstFetch $node
+ * @param Class_ $node
*/
- public function refactor(Node $node) : ?ClassConstFetch
+ public function refactor(Node $node) : ?Class_
{
- if (!$node->class instanceof Name) {
+ if (!$node->isFinal()) {
return null;
}
- if (!$node->name instanceof Identifier) {
- return null;
- }
- if ($node->class->toString() !== ObjectReference::STATIC) {
- return null;
- }
- if ($node->name->toString() !== 'class') {
- return null;
- }
- $class = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$class instanceof Class_) {
- return null;
- }
- if (!$class->isFinal()) {
- return null;
+ $hasChanged = \false;
+ $this->traverseNodesWithCallable($node, function (Node $node) use(&$hasChanged) : ?ClassConstFetch {
+ if (!$node instanceof ClassConstFetch) {
+ return null;
+ }
+ if (!$this->isName($node->class, ObjectReference::STATIC)) {
+ return null;
+ }
+ if (!$this->isName($node->name, 'class')) {
+ return null;
+ }
+ $hasChanged = \true;
+ return $this->nodeFactory->createSelfFetchConstant('class');
+ });
+ if ($hasChanged) {
+ return $node;
}
- return $this->nodeFactory->createSelfFetchConstant('class');
+ return null;
}
public function provideMinPhpVersion() : int
{
diff --git a/rules/Php55/Rector/FuncCall/GetCalledClassToSelfClassRector.php b/rules/Php55/Rector/FuncCall/GetCalledClassToSelfClassRector.php
index cba24509a66f..6d901c621717 100644
--- a/rules/Php55/Rector/FuncCall/GetCalledClassToSelfClassRector.php
+++ b/rules/Php55/Rector/FuncCall/GetCalledClassToSelfClassRector.php
@@ -5,10 +5,9 @@
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
-use PhpParser\Node\Stmt\Class_;
+use PHPStan\Analyser\Scope;
use Rector\Core\Enum\ObjectReference;
-use Rector\Core\NodeAnalyzer\ClassAnalyzer;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -18,17 +17,8 @@
* @changelog https://3v4l.org/GU9dP
* @see \Rector\Tests\Php55\Rector\FuncCall\GetCalledClassToSelfClassRector\GetCalledClassToSelfClassRectorTest
*/
-final class GetCalledClassToSelfClassRector extends AbstractRector implements MinPhpVersionInterface
+final class GetCalledClassToSelfClassRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
- /**
- * @readonly
- * @var \Rector\Core\NodeAnalyzer\ClassAnalyzer
- */
- private $classAnalyzer;
- public function __construct(ClassAnalyzer $classAnalyzer)
- {
- $this->classAnalyzer = $classAnalyzer;
- }
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Change get_called_class() to self::class on final class', [new CodeSample(<<<'CODE_SAMPLE'
@@ -61,19 +51,19 @@ public function getNodeTypes() : array
/**
* @param FuncCall $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
if (!$this->isName($node, 'get_called_class')) {
return null;
}
- $class = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$class instanceof Class_) {
+ if (!$scope->isInClass()) {
return null;
}
- if ($class->isFinal()) {
+ $classReflection = $scope->getClassReflection();
+ if ($classReflection->isFinalByKeyword()) {
return $this->nodeFactory->createClassConstFetch(ObjectReference::SELF, 'class');
}
- if ($this->classAnalyzer->isAnonymousClass($class)) {
+ if ($classReflection->isAnonymous()) {
return $this->nodeFactory->createClassConstFetch(ObjectReference::SELF, 'class');
}
return null;
diff --git a/rules/Php55/Rector/FuncCall/GetCalledClassToStaticClassRector.php b/rules/Php55/Rector/FuncCall/GetCalledClassToStaticClassRector.php
index c3a8cb69434d..c7e0a4868700 100644
--- a/rules/Php55/Rector/FuncCall/GetCalledClassToStaticClassRector.php
+++ b/rules/Php55/Rector/FuncCall/GetCalledClassToStaticClassRector.php
@@ -5,10 +5,9 @@
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
-use PhpParser\Node\Stmt\Class_;
+use PHPStan\Analyser\Scope;
use Rector\Core\Enum\ObjectReference;
-use Rector\Core\NodeAnalyzer\ClassAnalyzer;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -18,17 +17,8 @@
* @changelog https://3v4l.org/dJgXd
* @see \Rector\Tests\Php55\Rector\FuncCall\GetCalledClassToStaticClassRector\GetCalledClassToStaticClassRectorTest
*/
-final class GetCalledClassToStaticClassRector extends AbstractRector implements MinPhpVersionInterface
+final class GetCalledClassToStaticClassRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
- /**
- * @readonly
- * @var \Rector\Core\NodeAnalyzer\ClassAnalyzer
- */
- private $classAnalyzer;
- public function __construct(ClassAnalyzer $classAnalyzer)
- {
- $this->classAnalyzer = $classAnalyzer;
- }
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Change get_called_class() to static::class on non-final class', [new CodeSample(<<<'CODE_SAMPLE'
@@ -61,19 +51,19 @@ public function getNodeTypes() : array
/**
* @param FuncCall $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
if (!$this->isName($node, 'get_called_class')) {
return null;
}
- $class = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$class instanceof Class_) {
- return $this->nodeFactory->createClassConstFetch(ObjectReference::STATIC, 'class');
+ if (!$scope->isInClass()) {
+ return null;
}
- if ($this->classAnalyzer->isAnonymousClass($class)) {
+ $classReflection = $scope->getClassReflection();
+ if ($classReflection->isAnonymous()) {
return null;
}
- if (!$class->isFinal()) {
+ if (!$classReflection->isFinal()) {
return $this->nodeFactory->createClassConstFetch(ObjectReference::STATIC, 'class');
}
return null;
diff --git a/rules/Php55/Rector/String_/StringClassNameToClassConstantRector.php b/rules/Php55/Rector/String_/StringClassNameToClassConstantRector.php
index ad4cfd526f51..5cf78f6e5585 100644
--- a/rules/Php55/Rector/String_/StringClassNameToClassConstantRector.php
+++ b/rules/Php55/Rector/String_/StringClassNameToClassConstantRector.php
@@ -11,10 +11,9 @@
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\ClassConst;
use PhpParser\NodeTraverser;
-use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface;
-use Rector\Core\Rector\AbstractScopeAwareRector;
+use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
@@ -25,17 +24,21 @@
*
* @see \Rector\Tests\Php55\Rector\String_\StringClassNameToClassConstantRector\StringClassNameToClassConstantRectorTest
*/
-final class StringClassNameToClassConstantRector extends AbstractScopeAwareRector implements AllowEmptyConfigurableRectorInterface, MinPhpVersionInterface
+final class StringClassNameToClassConstantRector extends AbstractRector implements AllowEmptyConfigurableRectorInterface, MinPhpVersionInterface
{
- /**
- * @var string[]
- */
- private $classesToSkip = [];
/**
* @readonly
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @var string
+ */
+ private const IS_UNDER_CLASS_CONST = 'is_under_class_const';
+ /**
+ * @var string[]
+ */
+ private $classesToSkip = [];
public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
@@ -75,13 +78,24 @@ public function run()
*/
public function getNodeTypes() : array
{
- return [String_::class, FuncCall::class];
+ return [String_::class, FuncCall::class, ClassConst::class];
}
/**
- * @param String_|FuncCall $node
+ * @param String_|FuncCall|ClassConst $node
+ * @return \PhpParser\Node\Expr\BinaryOp\Concat|\PhpParser\Node\Expr\ClassConstFetch|null|int
*/
- public function refactorWithScope(Node $node, Scope $scope)
+ public function refactor(Node $node)
{
+ // allow class strings to be part of class const arrays, as probably on purpose
+ if ($node instanceof ClassConst) {
+ $this->traverseNodesWithCallable($node->consts, static function (Node $subNode) {
+ if ($subNode instanceof String_) {
+ $subNode->setAttribute(self::IS_UNDER_CLASS_CONST, \true);
+ }
+ return null;
+ });
+ return null;
+ }
// keep allowed string as condition
if ($node instanceof FuncCall) {
if ($this->isName($node, 'is_a')) {
@@ -89,24 +103,26 @@ public function refactorWithScope(Node $node, Scope $scope)
}
return null;
}
+ if ($node->getAttribute(self::IS_UNDER_CLASS_CONST) === \true) {
+ return null;
+ }
$classLikeName = $node->value;
// remove leading slash
$classLikeName = \ltrim($classLikeName, '\\');
if ($classLikeName === '') {
return null;
}
- if ($this->shouldSkip($classLikeName, $node)) {
+ if ($this->shouldSkip($classLikeName)) {
return null;
}
$fullyQualified = new FullyQualified($classLikeName);
- $fullyQualifiedOrAliasName = new FullyQualified($scope->resolveName($fullyQualified));
if ($classLikeName !== $node->value) {
$preSlashCount = \strlen($node->value) - \strlen($classLikeName);
$preSlash = \str_repeat('\\', $preSlashCount);
$string = new String_($preSlash);
- return new Concat($string, new ClassConstFetch($fullyQualifiedOrAliasName, 'class'));
+ return new Concat($string, new ClassConstFetch($fullyQualified, 'class'));
}
- return new ClassConstFetch($fullyQualifiedOrAliasName, 'class');
+ return new ClassConstFetch($fullyQualified, 'class');
}
/**
* @param mixed[] $configuration
@@ -120,15 +136,8 @@ public function provideMinPhpVersion() : int
{
return PhpVersionFeature::CLASSNAME_CONSTANT;
}
- private function shouldSkip(string $classLikeName, String_ $string) : bool
+ private function shouldSkip(string $classLikeName) : bool
{
- if (!$this->reflectionProvider->hasClass($classLikeName)) {
- return \true;
- }
- $classReflection = $this->reflectionProvider->getClass($classLikeName);
- if ($classReflection->getName() !== $classLikeName) {
- return \true;
- }
// skip short class names, mostly invalid use of strings
if (\strpos($classLikeName, '\\') === \false) {
return \true;
@@ -137,13 +146,14 @@ private function shouldSkip(string $classLikeName, String_ $string) : bool
if (\ctype_lower($classLikeName[0])) {
return \true;
}
+ if (!$this->reflectionProvider->hasClass($classLikeName)) {
+ return \true;
+ }
foreach ($this->classesToSkip as $classToSkip) {
if ($this->nodeNameResolver->isStringName($classLikeName, $classToSkip)) {
return \true;
}
}
- // allow class strings to be part of class const arrays, as probably on purpose
- $parentClassConst = $this->betterNodeFinder->findParentType($string, ClassConst::class);
- return $parentClassConst instanceof ClassConst;
+ return \false;
}
}
diff --git a/rules/Php55/RegexMatcher.php b/rules/Php55/RegexMatcher.php
index 2a4eed92e2c7..78a7723aea93 100644
--- a/rules/Php55/RegexMatcher.php
+++ b/rules/Php55/RegexMatcher.php
@@ -10,6 +10,11 @@
use Rector\Core\PhpParser\Node\Value\ValueResolver;
final class RegexMatcher
{
+ /**
+ * @readonly
+ * @var \Rector\Core\PhpParser\Node\Value\ValueResolver
+ */
+ private $valueResolver;
/**
* @var string
* @see https://regex101.com/r/Ok4wuE/1
@@ -25,11 +30,6 @@ final class RegexMatcher
* @see https://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
*/
private const ALL_MODIFIERS_VALUES = ['i', 'm', 's', 'x', 'e', 'A', 'D', 'S', 'U', 'X', 'J', 'u'];
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\Value\ValueResolver
- */
- private $valueResolver;
public function __construct(ValueResolver $valueResolver)
{
$this->valueResolver = $valueResolver;
@@ -45,23 +45,7 @@ public function resolvePatternExpressionWithoutEIfFound(Expr $expr)
return null;
}
$delimiter = $pattern[0];
- switch ($delimiter) {
- case '(':
- $delimiter = ')';
- break;
- case '{':
- $delimiter = '}';
- break;
- case '[':
- $delimiter = ']';
- break;
- case '<':
- $delimiter = '>';
- break;
- default:
- $delimiter = $delimiter;
- break;
- }
+ $delimiter = $delimiter === '(' ? ')' : ($delimiter === '{' ? '}' : ($delimiter === '[' ? ']' : ($delimiter === '<' ? '>' : $delimiter)));
/** @var string $modifiers */
$modifiers = $this->resolveModifiers((string) Strings::after($pattern, $delimiter, -1));
if (\strpos($modifiers, 'e') === \false) {
diff --git a/rules/Php56/NodeAnalyzer/UndefinedVariableResolver.php b/rules/Php56/NodeAnalyzer/UndefinedVariableResolver.php
index d9f5d24465f5..c1fb2d923dbf 100644
--- a/rules/Php56/NodeAnalyzer/UndefinedVariableResolver.php
+++ b/rules/Php56/NodeAnalyzer/UndefinedVariableResolver.php
@@ -5,8 +5,8 @@
use PhpParser\Node;
use PhpParser\Node\Expr\Array_;
+use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\ArrowFunction;
-use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\AssignOp\Coalesce as AssignOpCoalesce;
use PhpParser\Node\Expr\AssignRef;
use PhpParser\Node\Expr\BinaryOp\Coalesce;
@@ -22,13 +22,11 @@
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Foreach_;
use PhpParser\Node\Stmt\Function_;
-use PhpParser\Node\Stmt\Switch_;
use PhpParser\Node\Stmt\Unset_;
use PhpParser\NodeTraverser;
use PHPStan\Analyser\Scope;
use Rector\Core\NodeAnalyzer\VariableAnalyzer;
use Rector\Core\PhpParser\Comparing\NodeComparator;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser;
@@ -49,22 +47,16 @@ final class UndefinedVariableResolver
* @var \Rector\Core\PhpParser\Comparing\NodeComparator
*/
private $nodeComparator;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
/**
* @readonly
* @var \Rector\Core\NodeAnalyzer\VariableAnalyzer
*/
private $variableAnalyzer;
- public function __construct(SimpleCallableNodeTraverser $simpleCallableNodeTraverser, NodeNameResolver $nodeNameResolver, NodeComparator $nodeComparator, BetterNodeFinder $betterNodeFinder, VariableAnalyzer $variableAnalyzer)
+ public function __construct(SimpleCallableNodeTraverser $simpleCallableNodeTraverser, NodeNameResolver $nodeNameResolver, NodeComparator $nodeComparator, VariableAnalyzer $variableAnalyzer)
{
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
$this->nodeNameResolver = $nodeNameResolver;
$this->nodeComparator = $nodeComparator;
- $this->betterNodeFinder = $betterNodeFinder;
$this->variableAnalyzer = $variableAnalyzer;
}
/**
@@ -74,7 +66,9 @@ public function __construct(SimpleCallableNodeTraverser $simpleCallableNodeTrave
public function resolve($node) : array
{
$undefinedVariables = [];
- $this->simpleCallableNodeTraverser->traverseNodesWithCallable((array) $node->stmts, function (Node $node) use(&$undefinedVariables) : ?int {
+ $checkedVariables = [];
+ $currentStmt = null;
+ $this->simpleCallableNodeTraverser->traverseNodesWithCallable((array) $node->stmts, function (Node $node) use(&$undefinedVariables, &$checkedVariables, &$currentStmt) : ?int {
// entering new scope - break!
if ($node instanceof FunctionLike && !$node instanceof ArrowFunction) {
return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
@@ -83,18 +77,28 @@ public function resolve($node) : array
// handled above
return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
}
+ if ($node instanceof Case_) {
+ return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
+ }
+ if ($node instanceof Stmt) {
+ $currentStmt = $node;
+ }
if (!$node instanceof Variable) {
+ $checkedVariables = $this->resolveCheckedVariables($node, $checkedVariables);
return null;
}
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
- if (!$parentNode instanceof Node) {
+ // after variable variable, the variable name got unpredictable, just stop
+ if ($node->name instanceof Variable) {
+ return NodeTraverser::STOP_TRAVERSAL;
+ }
+ if ($node->getAttribute(AttributeKey::IS_BEING_ASSIGNED) === \true) {
return null;
}
- if ($this->shouldSkipVariable($node, $parentNode)) {
+ $variableName = (string) $this->nodeNameResolver->getName($node);
+ if ($this->shouldSkipVariable($node, $variableName, $checkedVariables)) {
return null;
}
- $variableName = $this->nodeNameResolver->getName($node);
- if ($this->hasVariableTypeOrCurrentStmtUnreachable($node, $variableName)) {
+ if ($this->hasVariableTypeOrCurrentStmtUnreachable($node, $variableName, $currentStmt)) {
return null;
}
/** @var string $variableName */
@@ -103,58 +107,88 @@ public function resolve($node) : array
});
return \array_unique($undefinedVariables);
}
- private function hasVariableTypeOrCurrentStmtUnreachable(Variable $variable, ?string $variableName) : bool
+ /**
+ * @param string[] $checkedVariables
+ * @return string[]
+ */
+ private function resolveCheckedVariables(Node $node, array $checkedVariables) : array
{
- if (!\is_string($variableName)) {
- return \true;
+ if ($node instanceof Empty_ && $node->expr instanceof Variable) {
+ $checkedVariables[] = (string) $this->nodeNameResolver->getName($node->expr);
+ return $checkedVariables;
}
- // defined 100 %
- /** @var Scope $scope */
- $scope = $variable->getAttribute(AttributeKey::SCOPE);
- if ($scope->hasVariableType($variableName)->yes()) {
- return \true;
+ if ($node instanceof Isset_ || $node instanceof Unset_) {
+ return $this->resolveCheckedVariablesFromIssetOrUnset($node, $checkedVariables);
}
- $currentStmt = $this->betterNodeFinder->resolveCurrentStatement($variable);
- return $currentStmt instanceof Stmt && $currentStmt->getAttribute(AttributeKey::IS_UNREACHABLE) === \true;
- }
- private function shouldSkipWithParent(Node $parentNode) : bool
- {
- if (\in_array(\get_class($parentNode), [Unset_::class, UnsetCast::class, Isset_::class, Empty_::class], \true)) {
- return \true;
+ if ($node instanceof UnsetCast && $node->expr instanceof Variable) {
+ $checkedVariables[] = (string) $this->nodeNameResolver->getName($node->expr);
+ return $checkedVariables;
}
- // when parent Node origNode is null, it means parent Node just reprinted, so it can't be verified
- // so skip it
- return !$parentNode->getAttribute(AttributeKey::ORIGINAL_NODE) instanceof Node;
- }
- private function isAsCoalesceLeftOrAssignOpCoalesceVar(Node $parentNode, Variable $variable) : bool
- {
- if ($parentNode instanceof Coalesce && $parentNode->left === $variable) {
- return \true;
+ if ($node instanceof Coalesce && $node->left instanceof Variable) {
+ $checkedVariables[] = (string) $this->nodeNameResolver->getName($node->left);
+ return $checkedVariables;
+ }
+ if ($node instanceof AssignOpCoalesce && $node->var instanceof Variable) {
+ $checkedVariables[] = (string) $this->nodeNameResolver->getName($node->var);
+ return $checkedVariables;
}
- if (!$parentNode instanceof AssignOpCoalesce) {
- return \false;
+ if ($node instanceof AssignRef && $node->var instanceof Variable) {
+ $checkedVariables[] = (string) $this->nodeNameResolver->getName($node->var);
}
- return $parentNode->var === $variable;
+ return $this->resolveCheckedVariablesFromArrayOrList($node, $checkedVariables);
}
- private function isAssign(Node $parentNode) : bool
+ /**
+ * @param string[] $checkedVariables
+ * @return string[]
+ * @param \PhpParser\Node\Expr\Isset_|\PhpParser\Node\Stmt\Unset_ $node
+ */
+ private function resolveCheckedVariablesFromIssetOrUnset($node, array $checkedVariables) : array
{
- return \in_array(\get_class($parentNode), [Assign::class, AssignRef::class], \true);
+ foreach ($node->vars as $expr) {
+ if ($expr instanceof Variable) {
+ $checkedVariables[] = (string) $this->nodeNameResolver->getName($expr);
+ }
+ }
+ return $checkedVariables;
}
- private function shouldSkipVariable(Variable $variable, Node $parentNode) : bool
+ /**
+ * @param string[] $checkedVariables
+ * @return string[]
+ */
+ private function resolveCheckedVariablesFromArrayOrList(Node $node, array $checkedVariables) : array
{
- if ($this->isAsCoalesceLeftOrAssignOpCoalesceVar($parentNode, $variable)) {
- return \true;
+ if (!$node instanceof Array_ && !$node instanceof List_) {
+ return $checkedVariables;
}
- if ($this->isAssign($parentNode)) {
- return \true;
+ foreach ($node->items as $item) {
+ if (!$item instanceof ArrayItem) {
+ continue;
+ }
+ if (!$item->value instanceof Variable) {
+ continue;
+ }
+ $checkedVariables[] = (string) $this->nodeNameResolver->getName($item->value);
}
- if ($this->shouldSkipWithParent($parentNode)) {
+ return $checkedVariables;
+ }
+ private function hasVariableTypeOrCurrentStmtUnreachable(Variable $variable, ?string $variableName, ?Stmt $currentStmt) : bool
+ {
+ if (!\is_string($variableName)) {
return \true;
}
- // list() = | [$values] = defines variables as null
- if ($this->isListAssign($parentNode)) {
+ // defined 100 %
+ /** @var Scope $scope */
+ $scope = $variable->getAttribute(AttributeKey::SCOPE);
+ if ($scope->hasVariableType($variableName)->yes()) {
return \true;
}
+ return $currentStmt instanceof Stmt && $currentStmt->getAttribute(AttributeKey::IS_UNREACHABLE) === \true;
+ }
+ /**
+ * @param string[] $checkedVariables
+ */
+ private function shouldSkipVariable(Variable $variable, string $variableName, array &$checkedVariables) : bool
+ {
$variableName = $this->nodeNameResolver->getName($variable);
// skip $this, as probably in outer scope
if ($variableName === 'this') {
@@ -169,22 +203,7 @@ private function shouldSkipVariable(Variable $variable, Node $parentNode) : bool
if ($this->variableAnalyzer->isStaticOrGlobal($variable)) {
return \true;
}
- if ($this->hasPreviousCheckedWithIsset($variable)) {
- return \true;
- }
- if ($this->hasPreviousCheckedWithEmpty($variable)) {
- return \true;
- }
- return $this->isAfterSwitchCaseWithParentCase($variable);
- }
- private function isAfterSwitchCaseWithParentCase(Variable $variable) : bool
- {
- $previousSwitch = $this->betterNodeFinder->findFirstPreviousOfTypes($variable, [Switch_::class]);
- if (!$previousSwitch instanceof Switch_) {
- return \false;
- }
- $parentNode = $previousSwitch->getAttribute(AttributeKey::PARENT_NODE);
- return $parentNode instanceof Case_;
+ return \in_array($variableName, $checkedVariables, \true);
}
private function isDifferentWithOriginalNodeOrNoScope(Variable $variable) : bool
{
@@ -195,37 +214,4 @@ private function isDifferentWithOriginalNodeOrNoScope(Variable $variable) : bool
$nodeScope = $variable->getAttribute(AttributeKey::SCOPE);
return !$nodeScope instanceof Scope;
}
- private function hasPreviousCheckedWithIsset(Variable $variable) : bool
- {
- return (bool) $this->betterNodeFinder->findFirstPrevious($variable, function (Node $subNode) use($variable) : bool {
- if (!$subNode instanceof Isset_) {
- return \false;
- }
- $vars = $subNode->vars;
- foreach ($vars as $var) {
- if ($this->nodeComparator->areNodesEqual($variable, $var)) {
- return \true;
- }
- }
- return \false;
- });
- }
- private function hasPreviousCheckedWithEmpty(Variable $variable) : bool
- {
- return (bool) $this->betterNodeFinder->findFirstPrevious($variable, function (Node $subNode) use($variable) : bool {
- if (!$subNode instanceof Empty_) {
- return \false;
- }
- $subNodeExpr = $subNode->expr;
- return $this->nodeComparator->areNodesEqual($subNodeExpr, $variable);
- });
- }
- private function isListAssign(Node $node) : bool
- {
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentNode instanceof List_) {
- return \true;
- }
- return $parentNode instanceof Array_;
- }
}
diff --git a/rules/Php56/Rector/FunctionLike/AddDefaultValueForUndefinedVariableRector.php b/rules/Php56/Rector/FunctionLike/AddDefaultValueForUndefinedVariableRector.php
index 5b75660d567b..604886b554d5 100644
--- a/rules/Php56/Rector/FunctionLike/AddDefaultValueForUndefinedVariableRector.php
+++ b/rules/Php56/Rector/FunctionLike/AddDefaultValueForUndefinedVariableRector.php
@@ -13,7 +13,6 @@
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Function_;
-use Rector\Core\NodeAnalyzer\InlineHTMLAnalyzer;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\Php56\NodeAnalyzer\UndefinedVariableResolver;
@@ -33,15 +32,9 @@ final class AddDefaultValueForUndefinedVariableRector extends AbstractRector imp
* @var \Rector\Php56\NodeAnalyzer\UndefinedVariableResolver
*/
private $undefinedVariableResolver;
- /**
- * @readonly
- * @var \Rector\Core\NodeAnalyzer\InlineHTMLAnalyzer
- */
- private $inlineHTMLAnalyzer;
- public function __construct(UndefinedVariableResolver $undefinedVariableResolver, InlineHTMLAnalyzer $inlineHTMLAnalyzer)
+ public function __construct(UndefinedVariableResolver $undefinedVariableResolver)
{
$this->undefinedVariableResolver = $undefinedVariableResolver;
- $this->inlineHTMLAnalyzer = $inlineHTMLAnalyzer;
}
public function provideMinPhpVersion() : int
{
@@ -88,9 +81,6 @@ public function getNodeTypes() : array
*/
public function refactor(Node $node) : ?Node
{
- if ($this->inlineHTMLAnalyzer->hasInlineHTML($node)) {
- return null;
- }
if ($node->stmts === null) {
return null;
}
diff --git a/rules/Php70/EregToPcreTransformer.php b/rules/Php70/EregToPcreTransformer.php
index 47127c1510e6..d9fa8fffbed1 100644
--- a/rules/Php70/EregToPcreTransformer.php
+++ b/rules/Php70/EregToPcreTransformer.php
@@ -12,6 +12,11 @@
*/
final class EregToPcreTransformer
{
+ /**
+ * @readonly
+ * @var string
+ */
+ private $pcreDelimiter = '#';
/**
* @var array
*/
@@ -54,11 +59,6 @@ final class EregToPcreTransformer
* @var array
*/
private $cache = [];
- /**
- * @readonly
- * @var string
- */
- private $pcreDelimiter = '#';
/**
* Change this via services configuratoin in rector.php if you need it
* Single type is chosen to prevent every regular with different delimiter.
diff --git a/rules/Php70/Rector/Assign/ListSwapArrayOrderRector.php b/rules/Php70/Rector/Assign/ListSwapArrayOrderRector.php
index 92903d3c6ab4..e5c1a775d496 100644
--- a/rules/Php70/Rector/Assign/ListSwapArrayOrderRector.php
+++ b/rules/Php70/Rector/Assign/ListSwapArrayOrderRector.php
@@ -10,7 +10,7 @@
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\List_;
-use Rector\Core\Contract\PhpParser\NodePrinterInterface;
+use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
@@ -24,12 +24,12 @@ final class ListSwapArrayOrderRector extends AbstractRector implements MinPhpVer
{
/**
* @readonly
- * @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
+ * @var \Rector\Core\PhpParser\Printer\BetterStandardPrinter
*/
- private $nodePrinter;
- public function __construct(NodePrinterInterface $nodePrinter)
+ private $betterStandardPrinter;
+ public function __construct(BetterStandardPrinter $betterStandardPrinter)
{
- $this->nodePrinter = $nodePrinter;
+ $this->betterStandardPrinter = $betterStandardPrinter;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -58,7 +58,7 @@ public function refactor(Node $node) : ?Node
continue;
}
if ($arrayItem->value instanceof ArrayDimFetch && !$arrayItem->value->dim instanceof Expr) {
- $printedVariables[] = $this->nodePrinter->print($arrayItem->value->var);
+ $printedVariables[] = $this->betterStandardPrinter->print($arrayItem->value->var);
} else {
return null;
}
diff --git a/rules/Php70/Rector/Break_/BreakNotInLoopOrSwitchToReturnRector.php b/rules/Php70/Rector/Break_/BreakNotInLoopOrSwitchToReturnRector.php
index 90a460b8a6d8..009e51aae2e2 100644
--- a/rules/Php70/Rector/Break_/BreakNotInLoopOrSwitchToReturnRector.php
+++ b/rules/Php70/Rector/Break_/BreakNotInLoopOrSwitchToReturnRector.php
@@ -4,8 +4,13 @@
namespace Rector\Php70\Rector\Break_;
use PhpParser\Node;
+use PhpParser\Node\Expr\ArrowFunction;
+use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt\Break_;
+use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Return_;
+use PhpParser\Node\Stmt\Switch_;
+use PhpParser\NodeTraverser;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeNestingScope\ContextAnalyzer;
@@ -25,6 +30,10 @@ final class BreakNotInLoopOrSwitchToReturnRector extends AbstractRector implemen
* @var \Rector\NodeNestingScope\ContextAnalyzer
*/
private $contextAnalyzer;
+ /**
+ * @var string
+ */
+ private const IS_BREAK_IN_SWITCH = 'is_break_in_switch';
public function __construct(ContextAnalyzer $contextAnalyzer)
{
$this->contextAnalyzer = $contextAnalyzer;
@@ -68,23 +77,36 @@ public function run()
*/
public function getNodeTypes() : array
{
- return [Break_::class];
+ return [Switch_::class, Break_::class];
}
/**
- * @param Break_ $node
+ * @param Switch_|Break_ $node
+ * @return \PhpParser\Node\Stmt\Return_|null|int
*/
- public function refactor(Node $node) : ?Node
+ public function refactor(Node $node)
{
+ if ($node instanceof Switch_) {
+ $this->traverseNodesWithCallable($node->cases, static function (Node $subNode) : ?int {
+ if ($subNode instanceof Class_ || $subNode instanceof FunctionLike && !$subNode instanceof ArrowFunction) {
+ return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
+ }
+ if (!$subNode instanceof Break_) {
+ return null;
+ }
+ $subNode->setAttribute(self::IS_BREAK_IN_SWITCH, \true);
+ return null;
+ });
+ return null;
+ }
if ($this->contextAnalyzer->isInLoop($node)) {
return null;
}
- if ($this->contextAnalyzer->isInSwitch($node)) {
+ if ($node->getAttribute(self::IS_BREAK_IN_SWITCH) === \true) {
return null;
}
if ($this->contextAnalyzer->isInIf($node)) {
return new Return_();
}
- $this->removeNode($node);
- return null;
+ return NodeTraverser::REMOVE_NODE;
}
}
diff --git a/rules/Php70/Rector/ClassMethod/Php4ConstructorRector.php b/rules/Php70/Rector/ClassMethod/Php4ConstructorRector.php
index f84d99283d0a..004b773d2eef 100644
--- a/rules/Php70/Rector/ClassMethod/Php4ConstructorRector.php
+++ b/rules/Php70/Rector/ClassMethod/Php4ConstructorRector.php
@@ -9,9 +9,9 @@
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
-use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
+use PhpParser\NodeTraverser;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use Rector\Core\Enum\ObjectReference;
@@ -77,40 +77,38 @@ public function getNodeTypes() : array
}
/**
* @param ClassMethod $node
+ * @return \PhpParser\Node\Stmt\ClassMethod|int|null
*/
- public function refactorWithScope(Node $node, Scope $scope) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope)
{
- if (!$this->php4ConstructorClassMethodAnalyzer->detect($node, $scope)) {
+ if (!$scope->isInClass()) {
return null;
}
- $classLike = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$classLike instanceof Class_) {
+ if (!$this->php4ConstructorClassMethodAnalyzer->detect($node, $scope)) {
return null;
}
+ $classReflection = $scope->getClassReflection();
// process parent call references first
$this->processClassMethodStatementsForParentConstructorCalls($node, $scope);
// not PSR-4 constructor
- if (!$this->nodeNameResolver->areNamesEqual($classLike, $node)) {
+ if (!$this->nodeNameResolver->isName($node, $classReflection->getName())) {
return null;
}
- $classMethod = $classLike->getMethod(MethodName::CONSTRUCT);
// does it already have a __construct method?
- if (!$classMethod instanceof ClassMethod) {
+ if (!$classReflection->hasConstructor()) {
$node->name = new Identifier(MethodName::CONSTRUCT);
}
- $stmts = $node->stmts;
- if ($stmts === null) {
+ $classMethodStmts = $node->stmts;
+ if ($classMethodStmts === null) {
return null;
}
- if (\count($stmts) === 1) {
- /** @var Expression|Expr $stmt */
- $stmt = $stmts[0];
+ if (\count($classMethodStmts) === 1) {
+ $stmt = $node->stmts[0];
if (!$stmt instanceof Expression) {
return null;
}
if ($this->isLocalMethodCallNamed($stmt->expr, MethodName::CONSTRUCT)) {
- $this->removeNode($node);
- return null;
+ return NodeTraverser::REMOVE_NODE;
}
}
return $node;
diff --git a/rules/Php70/Rector/FuncCall/EregToPregMatchRector.php b/rules/Php70/Rector/FuncCall/EregToPregMatchRector.php
index 69be18ddcc49..14986ab4d0fc 100644
--- a/rules/Php70/Rector/FuncCall/EregToPregMatchRector.php
+++ b/rules/Php70/Rector/FuncCall/EregToPregMatchRector.php
@@ -28,15 +28,15 @@
*/
final class EregToPregMatchRector extends AbstractRector implements MinPhpVersionInterface
{
- /**
- * @var array
- */
- private const OLD_NAMES_TO_NEW_ONES = ['ereg' => 'preg_match', 'eregi' => 'preg_match', 'ereg_replace' => 'preg_replace', 'eregi_replace' => 'preg_replace', 'split' => 'preg_split', 'spliti' => 'preg_split'];
/**
* @readonly
* @var \Rector\Php70\EregToPcreTransformer
*/
private $eregToPcreTransformer;
+ /**
+ * @var array
+ */
+ private const OLD_NAMES_TO_NEW_ONES = ['ereg' => 'preg_match', 'eregi' => 'preg_match', 'ereg_replace' => 'preg_replace', 'eregi_replace' => 'preg_replace', 'split' => 'preg_split', 'spliti' => 'preg_split'];
public function __construct(EregToPcreTransformer $eregToPcreTransformer)
{
$this->eregToPcreTransformer = $eregToPcreTransformer;
@@ -81,6 +81,9 @@ private function shouldSkipFuncCall(FuncCall $funcCall) : bool
if (!isset(self::OLD_NAMES_TO_NEW_ONES[$functionName])) {
return \true;
}
+ if ($funcCall->isFirstClassCallable()) {
+ return \true;
+ }
return !isset($funcCall->getArgs()[0]);
}
private function processStringPattern(FuncCall $funcCall, String_ $string, string $functionName) : void
diff --git a/rules/Php70/Rector/FuncCall/MultiDirnameRector.php b/rules/Php70/Rector/FuncCall/MultiDirnameRector.php
index 3521eedfb330..72bd6ef5b788 100644
--- a/rules/Php70/Rector/FuncCall/MultiDirnameRector.php
+++ b/rules/Php70/Rector/FuncCall/MultiDirnameRector.php
@@ -71,6 +71,9 @@ private function matchNestedDirnameFuncCall(FuncCall $funcCall) : ?FuncCall
if (!$this->isName($funcCall, self::DIRNAME)) {
return null;
}
+ if ($funcCall->isFirstClassCallable()) {
+ return null;
+ }
$args = $funcCall->getArgs();
if (\count($args) >= 3) {
return null;
diff --git a/rules/Php70/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php b/rules/Php70/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php
index 21ec0e1df296..719d0885ac0b 100644
--- a/rules/Php70/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php
+++ b/rules/Php70/Rector/MethodCall/ThisCallOnStaticMethodToStaticCallRector.php
@@ -5,15 +5,15 @@
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
+use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassLike;
+use PHPStan\Analyser\Scope;
+use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\Php\PhpMethodReflection;
-use PHPStan\Reflection\ReflectionProvider;
-use PHPStan\Type\ObjectType;
use Rector\Core\Enum\ObjectReference;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeCollector\StaticAnalyzer;
@@ -24,7 +24,7 @@
* @changelog https://3v4l.org/rkiSC
* @see \Rector\Tests\Php70\Rector\MethodCall\ThisCallOnStaticMethodToStaticCallRector\ThisCallOnStaticMethodToStaticCallRectorTest
*/
-final class ThisCallOnStaticMethodToStaticCallRector extends AbstractRector implements MinPhpVersionInterface
+final class ThisCallOnStaticMethodToStaticCallRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -36,16 +36,10 @@ final class ThisCallOnStaticMethodToStaticCallRector extends AbstractRector impl
* @var \Rector\Core\Reflection\ReflectionResolver
*/
private $reflectionResolver;
- /**
- * @readonly
- * @var \PHPStan\Reflection\ReflectionProvider
- */
- private $reflectionProvider;
- public function __construct(StaticAnalyzer $staticAnalyzer, ReflectionResolver $reflectionResolver, ReflectionProvider $reflectionProvider)
+ public function __construct(StaticAnalyzer $staticAnalyzer, ReflectionResolver $reflectionResolver)
{
$this->staticAnalyzer = $staticAnalyzer;
$this->reflectionResolver = $reflectionResolver;
- $this->reflectionProvider = $reflectionProvider;
}
public function provideMinPhpVersion() : int
{
@@ -86,59 +80,61 @@ public static function eat()
*/
public function getNodeTypes() : array
{
- return [MethodCall::class];
+ return [Class_::class];
}
/**
- * @param MethodCall $node
+ * @param Class_ $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
- if (!$node->var instanceof Variable) {
- return null;
- }
- if (!$this->nodeNameResolver->isName($node->var, 'this')) {
- return null;
- }
- if (!$node->name instanceof Identifier) {
- return null;
- }
- $methodName = $this->getName($node->name);
- if ($methodName === null) {
+ if (!$scope->isInClass()) {
return null;
}
+ $classReflection = $scope->getClassReflection();
// skip PHPUnit calls, as they accept both self:: and $this-> formats
- if ($this->isObjectType($node->var, new ObjectType('PHPUnit\\Framework\\TestCase'))) {
+ if ($classReflection->isSubclassOf('PHPUnit\\Framework\\TestCase')) {
return null;
}
- $classLike = $this->betterNodeFinder->findParentType($node, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
- return null;
- }
- $className = (string) $this->nodeNameResolver->getName($classLike);
- if (!$this->reflectionProvider->hasClass($className)) {
- return null;
- }
- $classReflection = $this->reflectionProvider->getClass($className);
- $isStaticMethod = $this->staticAnalyzer->isStaticMethod($classReflection, $methodName);
- if (!$isStaticMethod) {
- return null;
+ $hasChanged = \false;
+ $this->traverseNodesWithCallable($node, function (Node $node) use($classReflection, &$hasChanged) : ?StaticCall {
+ if (!$node instanceof MethodCall) {
+ return null;
+ }
+ if (!$node->var instanceof Variable) {
+ return null;
+ }
+ if (!$this->nodeNameResolver->isName($node->var, 'this')) {
+ return null;
+ }
+ if (!$node->name instanceof Identifier) {
+ return null;
+ }
+ $methodName = $this->getName($node->name);
+ if ($methodName === null) {
+ return null;
+ }
+ $isStaticMethod = $this->staticAnalyzer->isStaticMethod($classReflection, $methodName);
+ if (!$isStaticMethod) {
+ return null;
+ }
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
+ $hasChanged = \true;
+ $objectReference = $this->resolveClassSelf($classReflection, $node);
+ return $this->nodeFactory->createStaticCall($objectReference, $methodName, $node->args);
+ });
+ if ($hasChanged) {
+ return $node;
}
- if ($node->isFirstClassCallable()) {
- return null;
- }
- $objectReference = $this->resolveClassSelf($node);
- return $this->nodeFactory->createStaticCall($objectReference, $methodName, $node->args);
+ return null;
}
/**
* @return ObjectReference::STATIC|ObjectReference::SELF
*/
- private function resolveClassSelf(MethodCall $methodCall) : string
+ private function resolveClassSelf(ClassReflection $classReflection, MethodCall $methodCall) : string
{
- $classLike = $this->betterNodeFinder->findParentType($methodCall, Class_::class);
- if (!$classLike instanceof Class_) {
- return ObjectReference::STATIC;
- }
- if ($classLike->isFinal()) {
+ if ($classReflection->isFinalByKeyword()) {
return ObjectReference::SELF;
}
$methodReflection = $this->reflectionResolver->resolveMethodReflectionFromMethodCall($methodCall);
diff --git a/rules/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php b/rules/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php
index 63d2066908c8..295660e3f78b 100644
--- a/rules/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php
+++ b/rules/Php70/Rector/StaticCall/StaticCallOnNonStaticToInstanceCallRector.php
@@ -10,6 +10,7 @@
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
+use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ObjectType;
@@ -160,6 +161,10 @@ private function shouldSkip(string $methodName, string $className, StaticCall $s
if ($isStaticMethod) {
return \true;
}
+ $reflection = $scope->getClassReflection();
+ if ($reflection instanceof ClassReflection && $reflection->isSubclassOf($className)) {
+ return \true;
+ }
$className = $this->getName($staticCall->class);
if (\in_array($className, [ObjectReference::PARENT, ObjectReference::SELF, ObjectReference::STATIC], \true)) {
return \true;
diff --git a/rules/Php70/Rector/Switch_/ReduceMultipleDefaultSwitchRector.php b/rules/Php70/Rector/Switch_/ReduceMultipleDefaultSwitchRector.php
index 434fbdde14f3..9bc9ab533adc 100644
--- a/rules/Php70/Rector/Switch_/ReduceMultipleDefaultSwitchRector.php
+++ b/rules/Php70/Rector/Switch_/ReduceMultipleDefaultSwitchRector.php
@@ -5,7 +5,6 @@
use PhpParser\Node;
use PhpParser\Node\Expr;
-use PhpParser\Node\Stmt\Case_;
use PhpParser\Node\Stmt\Switch_;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
@@ -65,37 +64,20 @@ public function refactor(Node $node) : ?Node
}
$defaultCases[$key] = $case;
}
- if (\count($defaultCases) < 2) {
+ $defaultCaseCount = \count($defaultCases);
+ if ($defaultCaseCount < 2) {
return null;
}
- $this->removeExtraDefaultCases($node->cases, $defaultCases);
- return $node;
- }
- /**
- * @param Case_[] $cases
- * @param Case_[] $defaultCases
- */
- private function removeExtraDefaultCases(array $cases, array $defaultCases) : void
- {
- // keep only last
- \array_pop($defaultCases);
- foreach ($defaultCases as $key => $defaultCase) {
- $this->keepStatementsToParentCase($cases, $defaultCase, $key);
- $this->removeNode($defaultCase);
- }
- }
- /**
- * @param Case_[] $cases
- */
- private function keepStatementsToParentCase(array $cases, Case_ $case, int $key) : void
- {
- if (!isset($cases[$key - 1])) {
- return;
- }
- $previousCase = $cases[$key - 1];
- if ($previousCase->stmts === []) {
- $previousCase->stmts = $case->stmts;
- $case->stmts = [];
+ foreach ($node->cases as $key => $case) {
+ if ($case->cond instanceof Expr) {
+ continue;
+ }
+ // remove previous default cases
+ if ($defaultCaseCount > 1) {
+ unset($node->cases[$key]);
+ --$defaultCaseCount;
+ }
}
+ return $node;
}
}
diff --git a/rules/Php71/IsArrayAndDualCheckToAble.php b/rules/Php71/IsArrayAndDualCheckToAble.php
index b169370f370a..e52ffbb15ea7 100644
--- a/rules/Php71/IsArrayAndDualCheckToAble.php
+++ b/rules/Php71/IsArrayAndDualCheckToAble.php
@@ -56,6 +56,9 @@ public function processBooleanOr(BooleanOr $booleanOr, string $type, string $new
if (!$this->nodeNameResolver->isName($funcCallExpr, 'is_array')) {
return null;
}
+ if ($funcCallExpr->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($funcCallExpr->getArgs()[0])) {
return null;
}
diff --git a/rules/Php71/NodeAnalyzer/CountableAnalyzer.php b/rules/Php71/NodeAnalyzer/CountableAnalyzer.php
index e8e6768ab86c..4f3a4651e516 100644
--- a/rules/Php71/NodeAnalyzer/CountableAnalyzer.php
+++ b/rules/Php71/NodeAnalyzer/CountableAnalyzer.php
@@ -10,6 +10,7 @@
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Analyser\Scope;
+use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\Php\PhpPropertyReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ArrayType;
@@ -18,7 +19,8 @@
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\UnionType;
use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
+use Rector\Core\PhpParser\ClassLikeAstResolver;
+use Rector\Core\Reflection\ReflectionResolver;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\TypeDeclaration\AlreadyAssignDetector\ConstructorAssignDetector;
@@ -39,11 +41,6 @@ final class CountableAnalyzer
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
/**
* @readonly
* @var \Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer
@@ -54,14 +51,25 @@ final class CountableAnalyzer
* @var \Rector\TypeDeclaration\AlreadyAssignDetector\ConstructorAssignDetector
*/
private $constructorAssignDetector;
- public function __construct(NodeTypeResolver $nodeTypeResolver, NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider, BetterNodeFinder $betterNodeFinder, PropertyFetchAnalyzer $propertyFetchAnalyzer, ConstructorAssignDetector $constructorAssignDetector)
+ /**
+ * @readonly
+ * @var \Rector\Core\Reflection\ReflectionResolver
+ */
+ private $reflectionResolver;
+ /**
+ * @readonly
+ * @var \Rector\Core\PhpParser\ClassLikeAstResolver
+ */
+ private $classLikeAstResolver;
+ public function __construct(NodeTypeResolver $nodeTypeResolver, NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider, PropertyFetchAnalyzer $propertyFetchAnalyzer, ConstructorAssignDetector $constructorAssignDetector, ReflectionResolver $reflectionResolver, ClassLikeAstResolver $classLikeAstResolver)
{
$this->nodeTypeResolver = $nodeTypeResolver;
$this->nodeNameResolver = $nodeNameResolver;
$this->reflectionProvider = $reflectionProvider;
- $this->betterNodeFinder = $betterNodeFinder;
$this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
$this->constructorAssignDetector = $constructorAssignDetector;
+ $this->reflectionResolver = $reflectionResolver;
+ $this->classLikeAstResolver = $classLikeAstResolver;
}
public function isCastableArrayType(Expr $expr, ArrayType $arrayType, Scope $scope) : bool
{
@@ -119,11 +127,15 @@ private function isIterableOrFilledAtConstruct(Type $nativeType, $propertyFetch)
if ($nativeType->isIterable()->yes()) {
return \true;
}
- $classLike = $this->betterNodeFinder->findParentType($propertyFetch, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
+ if ($propertyFetch->name instanceof Expr) {
return \false;
}
- if ($propertyFetch->name instanceof Expr) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($propertyFetch);
+ if (!$classReflection instanceof ClassReflection) {
+ return \false;
+ }
+ $classLike = $this->classLikeAstResolver->resolveClassFromClassReflection($classReflection);
+ if (!$classLike instanceof ClassLike) {
return \false;
}
$propertyName = (string) $this->nodeNameResolver->getName($propertyFetch->name);
diff --git a/rules/Php71/Rector/Assign/AssignArrayToStringRector.php b/rules/Php71/Rector/Assign/AssignArrayToStringRector.php
index a29fd30d0ac9..36e0ee426dad 100644
--- a/rules/Php71/Rector/Assign/AssignArrayToStringRector.php
+++ b/rules/Php71/Rector/Assign/AssignArrayToStringRector.php
@@ -8,14 +8,16 @@
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
+use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Scalar\String_;
-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\Node\Stmt\Property;
+use PhpParser\NodeTraverser;
+use Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace;
use Rector\Core\PhpParser\NodeFinder\PropertyFetchFinder;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
@@ -59,17 +61,37 @@ public function getRuleDefinition() : RuleDefinition
*/
public function getNodeTypes() : array
{
- return [Assign::class, Class_::class];
+ return [Namespace_::class, FileWithoutNamespace::class, Class_::class, ClassMethod::class, Function_::class, Closure::class];
}
/**
- * @param Assign|Class_ $node
+ * @param Namespace_|FileWithoutNamespace|Class_|ClassMethod|Function_|Closure $node
*/
public function refactor(Node $node) : ?Node
{
if ($node instanceof Class_) {
return $this->refactorClass($node);
}
- return $this->refactorAssign($node);
+ if ($node->stmts === null) {
+ return null;
+ }
+ $hasChanged = \false;
+ $this->traverseNodesWithCallable($node->stmts, function (Node $subNode) use(&$hasChanged, $node) : ?int {
+ if ($subNode instanceof Class_ || $subNode instanceof Function_ || $subNode instanceof Closure) {
+ return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
+ }
+ if ($subNode instanceof Assign) {
+ $assign = $this->refactorAssign($subNode, $node);
+ if ($assign instanceof Assign) {
+ $hasChanged = \true;
+ return null;
+ }
+ }
+ return null;
+ });
+ if ($hasChanged) {
+ return $node;
+ }
+ return null;
}
private function isEmptyString(Expr $expr) : bool
{
@@ -109,12 +131,11 @@ private function hasPropertyDefaultEmptyString(Property $property) : bool
}
/**
* @return ArrayDimFetch[]
+ * @param \PhpParser\Node\Stmt\Namespace_|\Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace|\PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node
*/
- private function findSameNamedVariableAssigns(Variable $variable) : array
+ private function findSameNamedVariableAssigns(Variable $variable, $node) : array
{
- // assign of empty string to something
- $scopeStmt = $this->findParentScope($variable);
- if (!$scopeStmt instanceof Stmt) {
+ if ($node->stmts === null) {
return [];
}
$variableName = $this->nodeNameResolver->getName($variable);
@@ -122,7 +143,7 @@ private function findSameNamedVariableAssigns(Variable $variable) : array
return [];
}
$assignedArrayDimFetches = [];
- $this->traverseNodesWithCallable($scopeStmt, function (Node $node) use($variableName, &$assignedArrayDimFetches) {
+ $this->traverseNodesWithCallable($node->stmts, function (Node $node) use($variableName, &$assignedArrayDimFetches) {
if (!$node instanceof Assign) {
return null;
}
@@ -141,13 +162,9 @@ private function findSameNamedVariableAssigns(Variable $variable) : array
return $assignedArrayDimFetches;
}
/**
- * @return Function_|ClassMethod|Class_|Namespace_|null
+ * @param \PhpParser\Node\Stmt\Namespace_|\Rector\Core\PhpParser\Node\CustomNode\FileWithoutNamespace|\PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node
*/
- private function findParentScope(Variable $variable)
- {
- return $this->betterNodeFinder->findParentByTypes($variable, [Function_::class, ClassMethod::class, Class_::class, Namespace_::class]);
- }
- private function refactorAssign(Assign $assign) : ?Assign
+ private function refactorAssign(Assign $assign, $node) : ?Assign
{
if (!$this->isEmptyString($assign->expr)) {
return null;
@@ -155,7 +172,7 @@ private function refactorAssign(Assign $assign) : ?Assign
if (!$assign->var instanceof Variable) {
return null;
}
- $variableAssignArrayDimFetches = $this->findSameNamedVariableAssigns($assign->var);
+ $variableAssignArrayDimFetches = $this->findSameNamedVariableAssigns($assign->var, $node);
$shouldRetype = \false;
// detect if is part of variable assign?
foreach ($variableAssignArrayDimFetches as $variableAssignArrayDimFetch) {
diff --git a/rules/Php71/Rector/FuncCall/CountOnNullRector.php b/rules/Php71/Rector/FuncCall/CountOnNullRector.php
index 7e3d7bb7b0a4..0612305f1dab 100644
--- a/rules/Php71/Rector/FuncCall/CountOnNullRector.php
+++ b/rules/Php71/Rector/FuncCall/CountOnNullRector.php
@@ -16,7 +16,6 @@
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Scalar\LNumber;
-use PhpParser\Node\Stmt\Trait_;
use PhpParser\NodeTraverser;
use PHPStan\Analyser\Scope;
use PHPStan\Type\ArrayType;
@@ -149,9 +148,7 @@ private function shouldSkipFuncCall(FuncCall $funcCall) : bool
if (!$this->isName($funcCall, 'count')) {
return \true;
}
- // skip ternary in trait, as impossible to analyse
- $trait = $this->betterNodeFinder->findParentType($funcCall, Trait_::class);
- if ($trait instanceof Trait_) {
+ if ($funcCall->isFirstClassCallable()) {
return \true;
}
$firstArg = $funcCall->getArgs()[0];
diff --git a/rules/Php71/Rector/TryCatch/MultiExceptionCatchRector.php b/rules/Php71/Rector/TryCatch/MultiExceptionCatchRector.php
index f2f9d86e877d..929c9a549907 100644
--- a/rules/Php71/Rector/TryCatch/MultiExceptionCatchRector.php
+++ b/rules/Php71/Rector/TryCatch/MultiExceptionCatchRector.php
@@ -4,10 +4,8 @@
namespace Rector\Php71\Rector\TryCatch;
use PhpParser\Node;
-use PhpParser\Node\Name;
-use PhpParser\Node\Stmt\Catch_;
use PhpParser\Node\Stmt\TryCatch;
-use Rector\Core\Contract\PhpParser\NodePrinterInterface;
+use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
@@ -22,12 +20,12 @@ final class MultiExceptionCatchRector extends AbstractRector implements MinPhpVe
{
/**
* @readonly
- * @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
+ * @var \Rector\Core\PhpParser\Printer\BetterStandardPrinter
*/
- private $nodePrinter;
- public function __construct(NodePrinterInterface $nodePrinter)
+ private $betterStandardPrinter;
+ public function __construct(BetterStandardPrinter $betterStandardPrinter)
{
- $this->nodePrinter = $nodePrinter;
+ $this->betterStandardPrinter = $betterStandardPrinter;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -64,55 +62,28 @@ public function refactor(Node $node) : ?Node
if (\count($node->catches) < 2) {
return null;
}
- $catchKeysByContent = $this->collectCatchKeysByContent($node);
- $hasRemovedCatch = \false;
- /** @var Catch_[] $catchKeys */
- foreach ($catchKeysByContent as $catchKeys) {
- // no duplicates
- $count = \count($catchKeys);
- if ($count < 2) {
+ $printedCatches = [];
+ $hasChanged = \false;
+ foreach ($node->catches as $key => $catch) {
+ $currentPrintedCatch = $this->betterStandardPrinter->print($catch->stmts);
+ // already duplicated catch → remove it and join the type
+ if (\in_array($currentPrintedCatch, $printedCatches, \true)) {
+ // merge type to existing type
+ $existingCatchKey = \array_search($currentPrintedCatch, $printedCatches, \true);
+ $node->catches[$existingCatchKey]->types[] = $catch->types[0];
+ unset($node->catches[$key]);
+ $hasChanged = \true;
continue;
}
- $collectedTypes = $this->collectTypesFromCatchedByIds($catchKeys);
- /** @var Catch_ $firstCatch */
- $firstCatch = \array_shift($catchKeys);
- $firstCatch->types = $collectedTypes;
- foreach ($catchKeys as $catchKey) {
- $this->removeNode($catchKey);
- $hasRemovedCatch = \true;
- }
+ $printedCatches[$key] = $currentPrintedCatch;
}
- if (!$hasRemovedCatch) {
- return null;
+ if ($hasChanged) {
+ return $node;
}
- return $node;
+ return null;
}
public function provideMinPhpVersion() : int
{
return PhpVersionFeature::MULTI_EXCEPTION_CATCH;
}
- /**
- * @return array
- */
- private function collectCatchKeysByContent(TryCatch $tryCatch) : array
- {
- $catchKeysByContent = [];
- foreach ($tryCatch->catches as $catch) {
- $catchContent = $this->nodePrinter->print($catch->stmts);
- $catchKeysByContent[$catchContent][] = $catch;
- }
- return $catchKeysByContent;
- }
- /**
- * @param Catch_[] $catches
- * @return Name[]
- */
- private function collectTypesFromCatchedByIds(array $catches) : array
- {
- $collectedTypes = [];
- foreach ($catches as $catch) {
- $collectedTypes = \array_merge($collectedTypes, $catch->types);
- }
- return $collectedTypes;
- }
}
diff --git a/rules/Php72/NodeFactory/AnonymousFunctionFactory.php b/rules/Php72/NodeFactory/AnonymousFunctionFactory.php
index 8270571ede94..9e8b7c09f42c 100644
--- a/rules/Php72/NodeFactory/AnonymousFunctionFactory.php
+++ b/rules/Php72/NodeFactory/AnonymousFunctionFactory.php
@@ -50,11 +50,6 @@
use ReflectionParameter;
final class AnonymousFunctionFactory
{
- /**
- * @var string
- * @see https://regex101.com/r/jkLLlM/2
- */
- private const DIM_FETCH_REGEX = '#(\\$|\\\\|\\x0)(?\\d+)#';
/**
* @readonly
* @var \Rector\NodeNameResolver\NodeNameResolver
@@ -105,6 +100,11 @@ final class AnonymousFunctionFactory
* @var \Rector\Core\PhpParser\Parser\InlineCodeParser
*/
private $inlineCodeParser;
+ /**
+ * @var string
+ * @see https://regex101.com/r/jkLLlM/2
+ */
+ private const DIM_FETCH_REGEX = '#(\\$|\\\\|\\x0)(?\\d+)#';
public function __construct(NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder, NodeFactory $nodeFactory, StaticTypeMapper $staticTypeMapper, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, SimplePhpParser $simplePhpParser, ClosureNestedUsesDecorator $closureNestedUsesDecorator, AstResolver $astResolver, PrivatesAccessor $privatesAccessor, InlineCodeParser $inlineCodeParser)
{
$this->nodeNameResolver = $nodeNameResolver;
diff --git a/rules/Php72/Rector/Assign/ReplaceEachAssignmentWithKeyCurrentRector.php b/rules/Php72/Rector/Assign/ReplaceEachAssignmentWithKeyCurrentRector.php
index 51e0cacbfcbc..f70cd425d37d 100644
--- a/rules/Php72/Rector/Assign/ReplaceEachAssignmentWithKeyCurrentRector.php
+++ b/rules/Php72/Rector/Assign/ReplaceEachAssignmentWithKeyCurrentRector.php
@@ -72,6 +72,9 @@ public function refactor(Node $node) : ?array
}
/** @var FuncCall $eachFuncCall */
$eachFuncCall = $assign->expr;
+ if ($eachFuncCall->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($eachFuncCall->getArgs()[0])) {
return null;
}
diff --git a/rules/Php72/Rector/FuncCall/GetClassOnNullRector.php b/rules/Php72/Rector/FuncCall/GetClassOnNullRector.php
index edf724e0f0d8..c5629d1e0c97 100644
--- a/rules/Php72/Rector/FuncCall/GetClassOnNullRector.php
+++ b/rules/Php72/Rector/FuncCall/GetClassOnNullRector.php
@@ -80,6 +80,9 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
if (!$this->isName($node, 'get_class')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
$firstArg = $node->getArgs()[0] ?? null;
if (!$firstArg instanceof Arg) {
return null;
diff --git a/rules/Php72/Rector/FuncCall/StringifyDefineRector.php b/rules/Php72/Rector/FuncCall/StringifyDefineRector.php
index 3ae057cd5a71..91cb088f3251 100644
--- a/rules/Php72/Rector/FuncCall/StringifyDefineRector.php
+++ b/rules/Php72/Rector/FuncCall/StringifyDefineRector.php
@@ -71,6 +71,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'define')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($node->getArgs()[0])) {
return null;
}
diff --git a/rules/Php72/Rector/FuncCall/StringsAssertNakedRector.php b/rules/Php72/Rector/FuncCall/StringsAssertNakedRector.php
index d7048a02c23f..7ceb4e599135 100644
--- a/rules/Php72/Rector/FuncCall/StringsAssertNakedRector.php
+++ b/rules/Php72/Rector/FuncCall/StringsAssertNakedRector.php
@@ -67,6 +67,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node, 'assert')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
$firstArg = $node->getArgs()[0];
$firstArgValue = $firstArg->value;
if (!$firstArgValue instanceof String_) {
diff --git a/rules/Php72/Rector/Unset_/UnsetCastRector.php b/rules/Php72/Rector/Unset_/UnsetCastRector.php
index d496155e7150..b71be9b90d8b 100644
--- a/rules/Php72/Rector/Unset_/UnsetCastRector.php
+++ b/rules/Php72/Rector/Unset_/UnsetCastRector.php
@@ -8,6 +8,7 @@
use PhpParser\Node\Expr\Cast\Unset_;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Stmt\Expression;
+use PhpParser\NodeTraverser;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
@@ -45,8 +46,9 @@ public function getNodeTypes() : array
}
/**
* @param Unset_|Assign|Expression $node
+ * @return int|null|\PhpParser\Node
*/
- public function refactor(Node $node) : ?Node
+ public function refactor(Node $node)
{
if ($node instanceof Assign) {
return $this->refactorAssign($node);
@@ -55,8 +57,7 @@ public function refactor(Node $node) : ?Node
if (!$node->expr instanceof Unset_) {
return null;
}
- $this->removeNode($node);
- return null;
+ return NodeTraverser::REMOVE_NODE;
}
return $this->nodeFactory->createNull();
}
diff --git a/rules/Php72/Rector/While_/WhileEachToForeachRector.php b/rules/Php72/Rector/While_/WhileEachToForeachRector.php
index 32a4682e873a..d12f4cb8d837 100644
--- a/rules/Php72/Rector/While_/WhileEachToForeachRector.php
+++ b/rules/Php72/Rector/While_/WhileEachToForeachRector.php
@@ -82,6 +82,9 @@ public function refactor(Node $node) : ?Node
}
/** @var FuncCall $eachFuncCall */
$eachFuncCall = $assignNode->expr;
+ if ($eachFuncCall->isFirstClassCallable()) {
+ return null;
+ }
/** @var List_ $listNode */
$listNode = $assignNode->var;
if (!isset($eachFuncCall->getArgs()[0])) {
diff --git a/rules/Php73/Rector/ConstFetch/SensitiveConstantNameRector.php b/rules/Php73/Rector/ConstFetch/SensitiveConstantNameRector.php
index 25d2a22d4202..2c2a35d9ab1f 100644
--- a/rules/Php73/Rector/ConstFetch/SensitiveConstantNameRector.php
+++ b/rules/Php73/Rector/ConstFetch/SensitiveConstantNameRector.php
@@ -21,16 +21,16 @@
*/
final class SensitiveConstantNameRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
- /**
- * @see http://php.net/manual/en/reserved.constants.php
- * @var string[]
- */
- private const PHP_RESERVED_CONSTANTS = ['PHP_VERSION', 'PHP_MAJOR_VERSION', 'PHP_MINOR_VERSION', 'PHP_RELEASE_VERSION', 'PHP_VERSION_ID', 'PHP_EXTRA_VERSION', 'PHP_ZTS', 'PHP_DEBUG', 'PHP_MAXPATHLEN', 'PHP_OS', 'PHP_OS_FAMILY', 'PHP_SAPI', 'PHP_EOL', 'PHP_INT_MAX', 'PHP_INT_MIN', 'PHP_INT_SIZE', 'PHP_FLOAT_DIG', 'PHP_FLOAT_EPSILON', 'PHP_FLOAT_MIN', 'PHP_FLOAT_MAX', 'DEFAULT_INCLUDE_PATH', 'PEAR_INSTALL_DIR', 'PEAR_EXTENSION_DIR', 'PHP_EXTENSION_DIR', 'PHP_PREFIX', 'PHP_BINDIR', 'PHP_BINARY', 'PHP_MANDIR', 'PHP_LIBDIR', 'PHP_DATADIR', 'PHP_SYSCONFDIR', 'PHP_LOCALSTATEDIR', 'PHP_CONFIG_FILE_PATH', 'PHP_CONFIG_FILE_SCAN_DIR', 'PHP_SHLIB_SUFFIX', 'PHP_FD_SETSIZE', 'E_ERROR', 'E_WARNING', 'E_PARSE', 'E_NOTICE', 'E_CORE_ERROR', 'E_CORE_WARNING', 'E_COMPILE_ERROR', 'E_COMPILE_WARNING', 'E_USER_ERROR', 'E_USER_WARNING', 'E_USER_NOTICE', 'E_RECOVERABLE_ERROR', 'E_DEPRECATED', 'E_USER_DEPRECATED', 'E_ALL', 'E_STRICT', '__COMPILER_HALT_OFFSET__', 'TRUE', 'FALSE', 'NULL'];
/**
* @readonly
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @see http://php.net/manual/en/reserved.constants.php
+ * @var string[]
+ */
+ private const PHP_RESERVED_CONSTANTS = ['PHP_VERSION', 'PHP_MAJOR_VERSION', 'PHP_MINOR_VERSION', 'PHP_RELEASE_VERSION', 'PHP_VERSION_ID', 'PHP_EXTRA_VERSION', 'PHP_ZTS', 'PHP_DEBUG', 'PHP_MAXPATHLEN', 'PHP_OS', 'PHP_OS_FAMILY', 'PHP_SAPI', 'PHP_EOL', 'PHP_INT_MAX', 'PHP_INT_MIN', 'PHP_INT_SIZE', 'PHP_FLOAT_DIG', 'PHP_FLOAT_EPSILON', 'PHP_FLOAT_MIN', 'PHP_FLOAT_MAX', 'DEFAULT_INCLUDE_PATH', 'PEAR_INSTALL_DIR', 'PEAR_EXTENSION_DIR', 'PHP_EXTENSION_DIR', 'PHP_PREFIX', 'PHP_BINDIR', 'PHP_BINARY', 'PHP_MANDIR', 'PHP_LIBDIR', 'PHP_DATADIR', 'PHP_SYSCONFDIR', 'PHP_LOCALSTATEDIR', 'PHP_CONFIG_FILE_PATH', 'PHP_CONFIG_FILE_SCAN_DIR', 'PHP_SHLIB_SUFFIX', 'PHP_FD_SETSIZE', 'E_ERROR', 'E_WARNING', 'E_PARSE', 'E_NOTICE', 'E_CORE_ERROR', 'E_CORE_WARNING', 'E_COMPILE_ERROR', 'E_COMPILE_WARNING', 'E_USER_ERROR', 'E_USER_WARNING', 'E_USER_NOTICE', 'E_RECOVERABLE_ERROR', 'E_DEPRECATED', 'E_USER_DEPRECATED', 'E_ALL', 'E_STRICT', '__COMPILER_HALT_OFFSET__', 'TRUE', 'FALSE', 'NULL'];
public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
diff --git a/rules/Php73/Rector/FuncCall/ArrayKeyFirstLastRector.php b/rules/Php73/Rector/FuncCall/ArrayKeyFirstLastRector.php
index a79c55508df7..361d59a846ea 100644
--- a/rules/Php73/Rector/FuncCall/ArrayKeyFirstLastRector.php
+++ b/rules/Php73/Rector/FuncCall/ArrayKeyFirstLastRector.php
@@ -25,6 +25,11 @@
*/
final class ArrayKeyFirstLastRector extends AbstractRector implements MinPhpVersionInterface
{
+ /**
+ * @readonly
+ * @var \PHPStan\Reflection\ReflectionProvider
+ */
+ private $reflectionProvider;
/**
* @var string
*/
@@ -37,11 +42,6 @@ final class ArrayKeyFirstLastRector extends AbstractRector implements MinPhpVers
* @var array
*/
private const PREVIOUS_TO_NEW_FUNCTIONS = ['reset' => self::ARRAY_KEY_FIRST, 'end' => self::ARRAY_KEY_LAST];
- /**
- * @readonly
- * @var \PHPStan\Reflection\ReflectionProvider
- */
- private $reflectionProvider;
public function __construct(ReflectionProvider $reflectionProvider)
{
$this->reflectionProvider = $reflectionProvider;
@@ -126,6 +126,9 @@ private function processArrayKeyFirstLast(StmtsAwareInterface $stmtsAware, bool
}
private function resolveKeyFuncCall(Stmt $nextStmt, FuncCall $resetOrEndFuncCall) : ?FuncCall
{
+ if ($resetOrEndFuncCall->isFirstClassCallable()) {
+ return null;
+ }
/** @var FuncCall|null */
return $this->betterNodeFinder->findFirst($nextStmt, function (Node $subNode) use($resetOrEndFuncCall) : bool {
if (!$subNode instanceof FuncCall) {
@@ -134,6 +137,9 @@ private function resolveKeyFuncCall(Stmt $nextStmt, FuncCall $resetOrEndFuncCall
if (!$this->isName($subNode, 'key')) {
return \false;
}
+ if ($subNode->isFirstClassCallable()) {
+ return \false;
+ }
return $this->nodeComparator->areNodesEqual($resetOrEndFuncCall->getArgs()[0], $subNode->getArgs()[0]);
});
}
diff --git a/rules/Php73/Rector/FuncCall/JsonThrowOnErrorRector.php b/rules/Php73/Rector/FuncCall/JsonThrowOnErrorRector.php
index 86ea0f080f79..cbce3e873c9d 100644
--- a/rules/Php73/Rector/FuncCall/JsonThrowOnErrorRector.php
+++ b/rules/Php73/Rector/FuncCall/JsonThrowOnErrorRector.php
@@ -66,6 +66,9 @@ private function shouldSkip(FuncCall $funcCall) : bool
if (!$this->isNames($funcCall, ['json_encode', 'json_decode'])) {
return \true;
}
+ if ($funcCall->isFirstClassCallable()) {
+ return \true;
+ }
if ($funcCall->args === null) {
return \true;
}
diff --git a/rules/Php73/Rector/FuncCall/RegexDashEscapeRector.php b/rules/Php73/Rector/FuncCall/RegexDashEscapeRector.php
index a5bd19b19087..00d09581e543 100644
--- a/rules/Php73/Rector/FuncCall/RegexDashEscapeRector.php
+++ b/rules/Php73/Rector/FuncCall/RegexDashEscapeRector.php
@@ -5,10 +5,7 @@
use RectorPrefix202306\Nette\Utils\Strings;
use PhpParser\Node;
-use PhpParser\Node\Expr\FuncCall;
-use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Scalar\String_;
-use Rector\Core\Php\Regex\RegexPatternArgumentManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\StringUtils;
use Rector\Core\ValueObject\PhpVersionFeature;
@@ -39,19 +36,6 @@ final class RegexDashEscapeRector extends AbstractRector implements MinPhpVersio
* @see https://regex101.com/r/TBVme9/9
*/
private const RIGHT_HAND_UNESCAPED_DASH_REGEX = '#(?regexPatternArgumentManipulator = $regexPatternArgumentManipulator;
- }
public function provideMinPhpVersion() : int
{
return PhpVersionFeature::ESCAPE_DASH_IN_REGEX;
@@ -71,43 +55,33 @@ public function getRuleDefinition() : RuleDefinition
*/
public function getNodeTypes() : array
{
- return [FuncCall::class, StaticCall::class];
+ return [String_::class];
}
/**
- * @param FuncCall|StaticCall $node
+ * @param String_ $node
*/
public function refactor(Node $node) : ?Node
{
- $regexArguments = $this->regexPatternArgumentManipulator->matchCallArgumentWithRegexPattern($node);
- if ($regexArguments === []) {
+ $stringKind = $node->getAttribute(AttributeKey::KIND);
+ if (\in_array($stringKind, [String_::KIND_HEREDOC, String_::KIND_NOWDOC], \true)) {
return null;
}
- foreach ($regexArguments as $regexArgument) {
- if (StringUtils::isMatch($regexArgument->value, self::THREE_BACKSLASH_FOR_ESCAPE_NEXT_REGEX)) {
- continue;
- }
- $this->escapeStringNode($regexArgument);
- }
- if (!$this->hasChanged) {
+ if (StringUtils::isMatch($node->value, self::THREE_BACKSLASH_FOR_ESCAPE_NEXT_REGEX)) {
return null;
}
- return $node;
- }
- private function escapeStringNode(String_ $string) : void
- {
- $stringValue = $string->value;
+ $stringValue = $node->value;
if (StringUtils::isMatch($stringValue, self::LEFT_HAND_UNESCAPED_DASH_REGEX)) {
- $string->value = Strings::replace($stringValue, self::LEFT_HAND_UNESCAPED_DASH_REGEX, '$1\\-');
+ $node->value = Strings::replace($stringValue, self::LEFT_HAND_UNESCAPED_DASH_REGEX, '$1\\-');
// helped needed to skip re-escaping regular expression
- $string->setAttribute(AttributeKey::IS_REGULAR_PATTERN, \true);
- $this->hasChanged = \true;
- return;
+ $node->setAttribute(AttributeKey::IS_REGULAR_PATTERN, \true);
+ return $node;
}
if (StringUtils::isMatch($stringValue, self::RIGHT_HAND_UNESCAPED_DASH_REGEX)) {
- $string->value = Strings::replace($stringValue, self::RIGHT_HAND_UNESCAPED_DASH_REGEX, '\\-$1]');
+ $node->value = Strings::replace($stringValue, self::RIGHT_HAND_UNESCAPED_DASH_REGEX, '\\-$1]');
// helped needed to skip re-escaping regular expression
- $string->setAttribute(AttributeKey::IS_REGULAR_PATTERN, \true);
- $this->hasChanged = \true;
+ $node->setAttribute(AttributeKey::IS_REGULAR_PATTERN, \true);
+ return $node;
}
+ return null;
}
}
diff --git a/rules/Php73/Rector/FuncCall/SetCookieRector.php b/rules/Php73/Rector/FuncCall/SetCookieRector.php
index 9c24eca790ea..c13c708ff4ab 100644
--- a/rules/Php73/Rector/FuncCall/SetCookieRector.php
+++ b/rules/Php73/Rector/FuncCall/SetCookieRector.php
@@ -72,6 +72,9 @@ private function shouldSkip(FuncCall $funcCall) : bool
if (!$this->isNames($funcCall, ['setcookie', 'setrawcookie'])) {
return \true;
}
+ if ($funcCall->isFirstClassCallable()) {
+ return \true;
+ }
$argsCount = \count($funcCall->args);
if ($argsCount <= 2) {
return \true;
diff --git a/rules/Php74/Rector/FuncCall/ArraySpreadInsteadOfArrayMergeRector.php b/rules/Php74/Rector/FuncCall/ArraySpreadInsteadOfArrayMergeRector.php
index fb39f5c13bb1..f39dee4f6767 100644
--- a/rules/Php74/Rector/FuncCall/ArraySpreadInsteadOfArrayMergeRector.php
+++ b/rules/Php74/Rector/FuncCall/ArraySpreadInsteadOfArrayMergeRector.php
@@ -110,9 +110,7 @@ private function refactorArray(FuncCall $funcCall) : ?Array_
return null;
}
if ($value instanceof Array_) {
- $item0Unpacked = $array->items;
- $item1Unpacked = $value->items;
- $array->items = \array_merge($item0Unpacked, $item1Unpacked);
+ $array->items = \array_merge($array->items, $value->items);
continue;
}
$value = $this->resolveValue($value);
@@ -176,6 +174,9 @@ private function isIteratorToArrayFuncCall(Expr $expr) : bool
if (!$this->nodeNameResolver->isName($expr, 'iterator_to_array')) {
return \false;
}
+ if ($expr->isFirstClassCallable()) {
+ return \false;
+ }
return isset($expr->getArgs()[0]);
}
}
diff --git a/rules/Php74/Rector/FuncCall/MoneyFormatToNumberFormatRector.php b/rules/Php74/Rector/FuncCall/MoneyFormatToNumberFormatRector.php
index d0747f7f06e8..6df09ccc5b55 100644
--- a/rules/Php74/Rector/FuncCall/MoneyFormatToNumberFormatRector.php
+++ b/rules/Php74/Rector/FuncCall/MoneyFormatToNumberFormatRector.php
@@ -81,6 +81,9 @@ public function refactorWithScope(Node $node, Scope $scope) : ?array
if (!$this->isName($funcCall, 'money_format')) {
return null;
}
+ if ($funcCall->isFirstClassCallable()) {
+ return null;
+ }
$args = $funcCall->getArgs();
if ($this->argsAnalyzer->hasNamedArg($args)) {
return null;
diff --git a/rules/Php74/Rector/Property/RestoreDefaultNullToNullableTypePropertyRector.php b/rules/Php74/Rector/Property/RestoreDefaultNullToNullableTypePropertyRector.php
index 2833c00a0f84..61c449b8936b 100644
--- a/rules/Php74/Rector/Property/RestoreDefaultNullToNullableTypePropertyRector.php
+++ b/rules/Php74/Rector/Property/RestoreDefaultNullToNullableTypePropertyRector.php
@@ -48,25 +48,32 @@ class SomeClass
*/
public function getNodeTypes() : array
{
- return [Property::class];
+ return [Class_::class];
}
/**
- * @param Property $node
+ * @param Class_ $node
*/
public function refactor(Node $node) : ?Node
{
- if ($this->shouldSkip($node)) {
- return null;
+ $hasChanged = \false;
+ foreach ($node->getProperties() as $property) {
+ if ($this->shouldSkip($property, $node)) {
+ continue;
+ }
+ $onlyProperty = $property->props[0];
+ $onlyProperty->default = $this->nodeFactory->createNull();
+ $hasChanged = \true;
}
- $onlyProperty = $node->props[0];
- $onlyProperty->default = $this->nodeFactory->createNull();
- return $node;
+ if ($hasChanged) {
+ return $node;
+ }
+ return null;
}
public function provideMinPhpVersion() : int
{
return PhpVersionFeature::TYPED_PROPERTIES;
}
- private function shouldSkip(Property $property) : bool
+ private function shouldSkip(Property $property, Class_ $class) : bool
{
if ($property->type === null) {
return \true;
@@ -86,12 +93,6 @@ private function shouldSkip(Property $property) : bool
}
// is variable assigned in constructor
$propertyName = $this->getName($property);
- $classLike = $this->betterNodeFinder->findParentType($property, Class_::class);
- // a trait can be used in multiple context, we don't know whether it is assigned in __construct or not
- // so it needs to has null default
- if (!$classLike instanceof Class_) {
- return \false;
- }
- return $this->constructorAssignDetector->isPropertyAssigned($classLike, $propertyName);
+ return $this->constructorAssignDetector->isPropertyAssigned($class, $propertyName);
}
}
diff --git a/rules/Php74/Rector/StaticCall/ExportToReflectionFunctionRector.php b/rules/Php74/Rector/StaticCall/ExportToReflectionFunctionRector.php
index c9d924ff302b..640f88b6089f 100644
--- a/rules/Php74/Rector/StaticCall/ExportToReflectionFunctionRector.php
+++ b/rules/Php74/Rector/StaticCall/ExportToReflectionFunctionRector.php
@@ -60,6 +60,9 @@ public function refactor(Node $node) : ?Node
if (!$this->isName($node->name, 'export')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
$firstArg = $node->getArgs()[0] ?? null;
if (!$firstArg instanceof Arg) {
return null;
diff --git a/rules/Php80/AttributeDecorator/JMSAccesorOrderAttributeDecorator.php b/rules/Php80/AttributeDecorator/JMSAccesorOrderAttributeDecorator.php
deleted file mode 100644
index e4de5a00b41d..000000000000
--- a/rules/Php80/AttributeDecorator/JMSAccesorOrderAttributeDecorator.php
+++ /dev/null
@@ -1,24 +0,0 @@
-args[0];
- if ($firstArg->name instanceof Identifier) {
- return;
- }
- $firstArg->name = new Identifier('order');
- }
-}
diff --git a/rules/Php80/AttributeDecorator/JMSAccessTypeAttributeDecorator.php b/rules/Php80/AttributeDecorator/JMSAccessTypeAttributeDecorator.php
deleted file mode 100644
index 7d2c8a80df78..000000000000
--- a/rules/Php80/AttributeDecorator/JMSAccessTypeAttributeDecorator.php
+++ /dev/null
@@ -1,34 +0,0 @@
-args;
- if (\count($args) !== 1) {
- return;
- }
- $currentArg = $args[0];
- if ($currentArg->name instanceof Identifier) {
- return;
- }
- if (!$currentArg->value instanceof String_) {
- return;
- }
- $currentArg->name = new Identifier('type');
- }
-}
diff --git a/rules/Php80/AttributeDecorator/SensioParamConverterAttributeDecorator.php b/rules/Php80/AttributeDecorator/SensioParamConverterAttributeDecorator.php
index 3fbabe0e25c8..cff6828e3e66 100644
--- a/rules/Php80/AttributeDecorator/SensioParamConverterAttributeDecorator.php
+++ b/rules/Php80/AttributeDecorator/SensioParamConverterAttributeDecorator.php
@@ -4,8 +4,7 @@
namespace Rector\Php80\AttributeDecorator;
use PhpParser\Node\Attribute;
-use Rector\Php80\Contract\AttributeDecoratorInterface;
-final class SensioParamConverterAttributeDecorator implements AttributeDecoratorInterface
+final class SensioParamConverterAttributeDecorator
{
public function getAttributeName() : string
{
diff --git a/rules/Php80/Contract/AttributeDecoratorInterface.php b/rules/Php80/Contract/AttributeDecoratorInterface.php
deleted file mode 100644
index a0910367caa8..000000000000
--- a/rules/Php80/Contract/AttributeDecoratorInterface.php
+++ /dev/null
@@ -1,11 +0,0 @@
-nodeNameResolver = $nodeNameResolver;
diff --git a/rules/Php80/MatchAndRefactor/StrStartsWithMatchAndRefactor/SubstrMatchAndRefactor.php b/rules/Php80/MatchAndRefactor/StrStartsWithMatchAndRefactor/SubstrMatchAndRefactor.php
index 8760ce82d068..140e15bb9f3f 100644
--- a/rules/Php80/MatchAndRefactor/StrStartsWithMatchAndRefactor/SubstrMatchAndRefactor.php
+++ b/rules/Php80/MatchAndRefactor/StrStartsWithMatchAndRefactor/SubstrMatchAndRefactor.php
@@ -79,6 +79,9 @@ public function refactorStrStartsWith(StrStartsWith $strStartsWith) : ?Node
private function isStrlenWithNeedleExpr(StrStartsWith $strStartsWith) : bool
{
$substrFuncCall = $strStartsWith->getFuncCall();
+ if ($substrFuncCall->isFirstClassCallable()) {
+ return \false;
+ }
$firstArg = $substrFuncCall->getArgs()[1];
if (!$this->valueResolver->isValue($firstArg->value, 0)) {
return \false;
@@ -98,6 +101,9 @@ private function isStrlenWithNeedleExpr(StrStartsWith $strStartsWith) : bool
private function isHardcodedStringWithLNumberLength(StrStartsWith $strStartsWith) : bool
{
$substrFuncCall = $strStartsWith->getFuncCall();
+ if ($substrFuncCall->isFirstClassCallable()) {
+ return \false;
+ }
$secondArg = $substrFuncCall->getArgs()[1];
if (!$this->valueResolver->isValue($secondArg->value, 0)) {
return \false;
@@ -106,9 +112,6 @@ private function isHardcodedStringWithLNumberLength(StrStartsWith $strStartsWith
if (!$hardcodedStringNeedle instanceof String_) {
return \false;
}
- if ($substrFuncCall->isFirstClassCallable()) {
- return \false;
- }
if (\count($substrFuncCall->getArgs()) < 3) {
return \false;
}
diff --git a/rules/Php80/NodeAnalyzer/AnnotationTargetResolver.php b/rules/Php80/NodeAnalyzer/AnnotationTargetResolver.php
deleted file mode 100644
index 0377b86bf565..000000000000
--- a/rules/Php80/NodeAnalyzer/AnnotationTargetResolver.php
+++ /dev/null
@@ -1,50 +0,0 @@
-
- */
- private const TARGET_TO_CONSTANT_MAP = [
- 'METHOD' => 'TARGET_METHOD',
- 'PROPERTY' => 'TARGET_PROPERTY',
- 'CLASS' => 'TARGET_CLASS',
- 'FUNCTION' => 'TARGET_FUNCTION',
- 'ALL' => 'TARGET_ALL',
- // special case
- 'ANNOTATION' => 'TARGET_CLASS',
- ];
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\NodeFactory
- */
- private $nodeFactory;
- public function __construct(NodeFactory $nodeFactory)
- {
- $this->nodeFactory = $nodeFactory;
- }
- /**
- * @param ArrayItemNode[] $targetValues
- * @return ClassConstFetch[]
- */
- public function resolveFlagClassConstFetches(array $targetValues) : array
- {
- $classConstFetches = [];
- foreach ($targetValues as $targetValue) {
- foreach (self::TARGET_TO_CONSTANT_MAP as $target => $constant) {
- if ($target !== $targetValue->value) {
- continue;
- }
- $classConstFetches[] = $this->nodeFactory->createClassConstFetch('Attribute', $constant);
- }
- }
- return $classConstFetches;
- }
-}
diff --git a/rules/Php80/NodeAnalyzer/EnumParamAnalyzer.php b/rules/Php80/NodeAnalyzer/EnumParamAnalyzer.php
deleted file mode 100644
index fc0984576f03..000000000000
--- a/rules/Php80/NodeAnalyzer/EnumParamAnalyzer.php
+++ /dev/null
@@ -1,82 +0,0 @@
-reflectionProvider = $reflectionProvider;
- }
- public function matchParameterClassName(ParameterReflection $parameterReflection, PhpDocInfo $phpDocInfo) : ?ClassNameAndTagValueNode
- {
- $paramTagValueNode = $phpDocInfo->getParamTagValueByName($parameterReflection->getName());
- if (!$paramTagValueNode instanceof ParamTagValueNode) {
- return null;
- }
- $className = $this->resolveClassFromConstType($paramTagValueNode->type);
- if ($className === null) {
- return null;
- }
- if (!$this->reflectionProvider->hasClass($className)) {
- return null;
- }
- return new ClassNameAndTagValueNode($className, $paramTagValueNode);
- }
- public function matchReturnClassName(PhpDocInfo $phpDocInfo) : ?ClassNameAndTagValueNode
- {
- $returnTagValueNode = $phpDocInfo->getReturnTagValue();
- if (!$returnTagValueNode instanceof ReturnTagValueNode) {
- return null;
- }
- $className = $this->resolveClassFromConstType($returnTagValueNode->type);
- if (!\is_string($className)) {
- return null;
- }
- return new ClassNameAndTagValueNode($className, $returnTagValueNode);
- }
- public function matchPropertyClassName(PhpDocInfo $phpDocInfo) : ?ClassNameAndTagValueNode
- {
- $varTagValueNode = $phpDocInfo->getVarTagValueNode();
- if (!$varTagValueNode instanceof VarTagValueNode) {
- return null;
- }
- $className = $this->resolveClassFromConstType($varTagValueNode->type);
- if (!\is_string($className)) {
- return null;
- }
- return new ClassNameAndTagValueNode($className, $varTagValueNode);
- }
- private function resolveClassFromConstType(TypeNode $typeNode) : ?string
- {
- if (!$typeNode instanceof ConstTypeNode) {
- return null;
- }
- if (!$typeNode->constExpr instanceof ConstFetchNode) {
- return null;
- }
- $constExpr = $typeNode->constExpr;
- return $constExpr->getAttribute(PhpDocAttributeKey::RESOLVED_CLASS);
- }
-}
diff --git a/rules/Php80/NodeAnalyzer/PhpAttributeAnalyzer.php b/rules/Php80/NodeAnalyzer/PhpAttributeAnalyzer.php
index 8a8cc8ef9a5d..4cbb25b52569 100644
--- a/rules/Php80/NodeAnalyzer/PhpAttributeAnalyzer.php
+++ b/rules/Php80/NodeAnalyzer/PhpAttributeAnalyzer.php
@@ -14,16 +14,16 @@
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use PHPStan\Reflection\ReflectionProvider;
-use Rector\Core\PhpParser\AstResolver;
+use Rector\Core\PhpParser\ClassLikeAstResolver;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\PhpAttribute\Enum\DocTagNodeState;
final class PhpAttributeAnalyzer
{
/**
* @readonly
- * @var \Rector\Core\PhpParser\AstResolver
+ * @var \Rector\Core\PhpParser\ClassLikeAstResolver
*/
- private $astResolver;
+ private $classLikeAstResolver;
/**
* @readonly
* @var \Rector\NodeNameResolver\NodeNameResolver
@@ -34,9 +34,9 @@ final class PhpAttributeAnalyzer
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
- public function __construct(AstResolver $astResolver, NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider)
+ public function __construct(ClassLikeAstResolver $classLikeAstResolver, NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider)
{
- $this->astResolver = $astResolver;
+ $this->classLikeAstResolver = $classLikeAstResolver;
$this->nodeNameResolver = $nodeNameResolver;
$this->reflectionProvider = $reflectionProvider;
}
@@ -64,8 +64,7 @@ public function hasInheritedPhpAttribute(Class_ $class, string $attributeClass)
$classReflection = $this->reflectionProvider->getClass($className);
$ancestorClassReflections = \array_merge($classReflection->getParents(), $classReflection->getInterfaces());
foreach ($ancestorClassReflections as $ancestorClassReflection) {
- $ancestorClassName = $ancestorClassReflection->getName();
- $resolvedClass = $this->astResolver->resolveClassFromName($ancestorClassName);
+ $resolvedClass = $this->classLikeAstResolver->resolveClassFromClassReflection($ancestorClassReflection);
if (!$resolvedClass instanceof Class_) {
continue;
}
diff --git a/rules/Php80/NodeAnalyzer/PromotedPropertyCandidateResolver.php b/rules/Php80/NodeAnalyzer/PromotedPropertyCandidateResolver.php
index e8366d18b8e0..cde81954eeb5 100644
--- a/rules/Php80/NodeAnalyzer/PromotedPropertyCandidateResolver.php
+++ b/rules/Php80/NodeAnalyzer/PromotedPropertyCandidateResolver.php
@@ -15,7 +15,6 @@
use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
use Rector\Core\PhpParser\Comparing\NodeComparator;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
-use Rector\Core\ValueObject\MethodName;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\Php80\ValueObject\PropertyPromotionCandidate;
final class PromotedPropertyCandidateResolver
@@ -50,12 +49,8 @@ public function __construct(NodeNameResolver $nodeNameResolver, BetterNodeFinder
/**
* @return PropertyPromotionCandidate[]
*/
- public function resolveFromClass(Class_ $class) : array
+ public function resolveFromClass(Class_ $class, ClassMethod $constructClassMethod) : array
{
- $constructClassMethod = $class->getMethod(MethodName::CONSTRUCT);
- if (!$constructClassMethod instanceof ClassMethod) {
- return [];
- }
$propertyPromotionCandidates = [];
foreach ($class->getProperties() as $property) {
$propertyCount = \count($property->props);
@@ -77,13 +72,13 @@ private function matchPropertyPromotionCandidate(Property $property, ClassMethod
$firstParamAsVariable = $this->resolveFirstParamUses($constructClassMethod);
// match property name to assign in constructor
foreach ((array) $constructClassMethod->stmts as $stmt) {
- if ($stmt instanceof Expression) {
- $stmt = $stmt->expr;
+ if (!$stmt instanceof Expression) {
+ continue;
}
- if (!$stmt instanceof Assign) {
+ if (!$stmt->expr instanceof Assign) {
continue;
}
- $assign = $stmt;
+ $assign = $stmt->expr;
// promoted property must use non-static property only
if (!$assign->var instanceof PropertyFetch) {
continue;
@@ -103,7 +98,7 @@ private function matchPropertyPromotionCandidate(Property $property, ClassMethod
if ($this->shouldSkipParam($matchedParam, $assignedExpr, $firstParamAsVariable)) {
continue;
}
- return new PropertyPromotionCandidate($property, $assign, $matchedParam);
+ return new PropertyPromotionCandidate($property, $matchedParam, $stmt);
}
return null;
}
diff --git a/rules/Php80/NodeFactory/AttributeFlagFactory.php b/rules/Php80/NodeFactory/AttributeFlagFactory.php
deleted file mode 100644
index e67fcb0c3957..000000000000
--- a/rules/Php80/NodeFactory/AttributeFlagFactory.php
+++ /dev/null
@@ -1,26 +0,0 @@
-attributeDecorators = $attributeDecorators;
+ $this->sensioParamConverterAttributeDecorator = $sensioParamConverterAttributeDecorator;
}
/**
* @param AttributeGroup[] $attributeGroups
@@ -28,12 +25,10 @@ public function decorate(array $attributeGroups) : void
foreach ($attributeGroups as $attributeGroup) {
foreach ($attributeGroup->attrs as $attr) {
$phpAttributeName = $attr->name->getAttribute(AttributeKey::PHP_ATTRIBUTE_NAME);
- foreach ($this->attributeDecorators as $attributeDecorator) {
- if ($attributeDecorator->getAttributeName() !== $phpAttributeName) {
- continue;
- }
- $attributeDecorator->decorate($attr);
+ if ($this->sensioParamConverterAttributeDecorator->getAttributeName() !== $phpAttributeName) {
+ continue;
}
+ $this->sensioParamConverterAttributeDecorator->decorate($attr);
}
}
}
diff --git a/rules/Php80/NodeManipulator/ResourceReturnToObject.php b/rules/Php80/NodeManipulator/ResourceReturnToObject.php
index c82ce280ba1f..eca85c6cff9c 100644
--- a/rules/Php80/NodeManipulator/ResourceReturnToObject.php
+++ b/rules/Php80/NodeManipulator/ResourceReturnToObject.php
@@ -195,6 +195,9 @@ private function shouldSkip(FuncCall $funcCall) : bool
if (!$this->nodeNameResolver->isName($funcCall, 'is_resource')) {
return \true;
}
+ if ($funcCall->isFirstClassCallable()) {
+ return \true;
+ }
if (!isset($funcCall->getArgs()[0])) {
return \true;
}
diff --git a/rules/Php80/Rector/ClassConstFetch/ClassOnThisVariableObjectRector.php b/rules/Php80/Rector/ClassConstFetch/ClassOnThisVariableObjectRector.php
index ca77a1a56f20..d28230d452d8 100644
--- a/rules/Php80/Rector/ClassConstFetch/ClassOnThisVariableObjectRector.php
+++ b/rules/Php80/Rector/ClassConstFetch/ClassOnThisVariableObjectRector.php
@@ -9,7 +9,8 @@
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Class_;
-use Rector\Core\Rector\AbstractRector;
+use PHPStan\Analyser\Scope;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -23,7 +24,7 @@
*
* @see \Rector\Tests\Php80\Rector\ClassConstFetch\ClassOnThisVariableObjectRector\ClassOnThisVariableObjectRectorTest
*/
-final class ClassOnThisVariableObjectRector extends AbstractRector implements MinPhpVersionInterface
+final class ClassOnThisVariableObjectRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
public function getRuleDefinition() : RuleDefinition
{
@@ -52,23 +53,30 @@ public function run()
*/
public function getNodeTypes() : array
{
- return [ClassConstFetch::class];
+ return [Class_::class];
}
/**
- * @param ClassConstFetch $node
+ * @param Class_ $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
- if ($this->shouldSkip($node)) {
- return null;
+ $className = $node->isFinal() ? 'self' : 'static';
+ $hasChanged = \false;
+ $this->traverseNodesWithCallable($node, function (Node $node) use(&$hasChanged, $className) : ?ClassConstFetch {
+ if (!$node instanceof ClassConstFetch) {
+ return null;
+ }
+ if ($this->shouldSkip($node)) {
+ return null;
+ }
+ $node->class = new Name($className);
+ $hasChanged = \true;
+ return $node;
+ });
+ if ($hasChanged) {
+ return $node;
}
- $class = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$class instanceof Class_) {
- return null;
- }
- $className = $class->isFinal() ? 'self' : 'static';
- $node->class = new Name($className);
- return $node;
+ return null;
}
public function provideMinPhpVersion() : int
{
diff --git a/rules/Php80/Rector/ClassMethod/AddParamBasedOnParentClassMethodRector.php b/rules/Php80/Rector/ClassMethod/AddParamBasedOnParentClassMethodRector.php
index 5460c878dd8d..c84515408dff 100644
--- a/rules/Php80/Rector/ClassMethod/AddParamBasedOnParentClassMethodRector.php
+++ b/rules/Php80/Rector/ClassMethod/AddParamBasedOnParentClassMethodRector.php
@@ -14,8 +14,8 @@
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Reflection\MethodReflection;
-use Rector\Core\Contract\PhpParser\NodePrinterInterface;
use Rector\Core\PhpParser\AstResolver;
+use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\MethodName;
use Rector\Core\ValueObject\PhpVersionFeature;
@@ -42,14 +42,14 @@ final class AddParamBasedOnParentClassMethodRector extends AbstractRector implem
private $astResolver;
/**
* @readonly
- * @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
+ * @var \Rector\Core\PhpParser\Printer\BetterStandardPrinter
*/
- private $nodePrinter;
- public function __construct(ParentClassMethodTypeOverrideGuard $parentClassMethodTypeOverrideGuard, AstResolver $astResolver, NodePrinterInterface $nodePrinter)
+ private $betterStandardPrinter;
+ public function __construct(ParentClassMethodTypeOverrideGuard $parentClassMethodTypeOverrideGuard, AstResolver $astResolver, BetterStandardPrinter $betterStandardPrinter)
{
$this->parentClassMethodTypeOverrideGuard = $parentClassMethodTypeOverrideGuard;
$this->astResolver = $astResolver;
- $this->nodePrinter = $nodePrinter;
+ $this->betterStandardPrinter = $betterStandardPrinter;
}
public function provideMinPhpVersion() : int
{
@@ -179,14 +179,14 @@ private function processReplaceClassMethodParams(ClassMethod $node, ClassMethod
}
$paramDefault = $parentClassMethodParam->default;
if ($paramDefault instanceof Expr) {
- $printParamDefault = $this->nodePrinter->print($paramDefault);
+ $printParamDefault = $this->betterStandardPrinter->print($paramDefault);
$paramDefault = new ConstFetch(new Name($printParamDefault));
}
$paramName = $this->nodeNameResolver->getName($parentClassMethodParam);
$paramType = $this->resolveParamType($parentClassMethodParam);
$node->params[$key] = new Param(new Variable($paramName), $paramDefault, $paramType, $parentClassMethodParam->byRef, $parentClassMethodParam->variadic, [], $parentClassMethodParam->flags);
if ($parentClassMethodParam->attrGroups !== []) {
- $attrGroupsAsComment = $this->nodePrinter->print($parentClassMethodParam->attrGroups);
+ $attrGroupsAsComment = $this->betterStandardPrinter->print($parentClassMethodParam->attrGroups);
$node->params[$key]->setAttribute(AttributeKey::COMMENTS, [new Comment($attrGroupsAsComment)]);
}
}
diff --git a/rules/Php80/Rector/Class_/AnnotationToAttributeRector.php b/rules/Php80/Rector/Class_/AnnotationToAttributeRector.php
index 0cc5b2327a4a..058fe9888a9a 100644
--- a/rules/Php80/Rector/Class_/AnnotationToAttributeRector.php
+++ b/rules/Php80/Rector/Class_/AnnotationToAttributeRector.php
@@ -42,10 +42,6 @@
*/
final class AnnotationToAttributeRector extends AbstractRector implements ConfigurableRectorInterface, MinPhpVersionInterface
{
- /**
- * @var AnnotationToAttribute[]
- */
- private $annotationsToAttributes = [];
/**
* @readonly
* @var \Rector\PhpAttribute\NodeFactory\PhpAttributeGroupFactory
@@ -76,6 +72,10 @@ final class AnnotationToAttributeRector extends AbstractRector implements Config
* @var \Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer
*/
private $phpAttributeAnalyzer;
+ /**
+ * @var AnnotationToAttribute[]
+ */
+ private $annotationsToAttributes = [];
public function __construct(PhpAttributeGroupFactory $phpAttributeGroupFactory, AttrGroupsFactory $attrGroupsFactory, PhpDocTagRemover $phpDocTagRemover, AttributeGroupNamedArgumentManipulator $attributeGroupNamedArgumentManipulator, UseImportsResolver $useImportsResolver, PhpAttributeAnalyzer $phpAttributeAnalyzer)
{
$this->phpAttributeGroupFactory = $phpAttributeGroupFactory;
@@ -129,7 +129,7 @@ public function refactor(Node $node) : ?Node
if (!$phpDocInfo instanceof PhpDocInfo) {
return null;
}
- $uses = $this->useImportsResolver->resolveBareUsesForNode($node);
+ $uses = $this->useImportsResolver->resolveBareUses();
// 1. bare tags without annotation class, e.g. "@inject"
$genericAttributeGroups = $this->processGenericTags($phpDocInfo);
// 2. Doctrine annotation classes
diff --git a/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php b/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php
index f8c34ee788a9..9eade1747d1d 100644
--- a/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php
+++ b/rules/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector.php
@@ -15,6 +15,8 @@
use PhpParser\Node\UnionType;
use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
+use PHPStan\Type\MixedType;
+use PHPStan\Type\TypeCombinator;
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
use Rector\BetterPhpDocParser\ValueObject\PhpDocAttributeKey;
use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface;
@@ -25,6 +27,7 @@
use Rector\DeadCode\PhpDoc\TagRemover\VarTagRemover;
use Rector\Naming\VariableRenamer;
use Rector\NodeTypeResolver\Node\AttributeKey;
+use Rector\NodeTypeResolver\TypeComparator\TypeComparator;
use Rector\Php80\Guard\MakePropertyPromotionGuard;
use Rector\Php80\NodeAnalyzer\PromotedPropertyCandidateResolver;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
@@ -38,21 +41,6 @@
*/
final class ClassPropertyAssignToConstructorPromotionRector extends AbstractRector implements MinPhpVersionInterface, AllowEmptyConfigurableRectorInterface
{
- /**
- * @api
- * @var string
- */
- public const INLINE_PUBLIC = 'inline_public';
- /**
- * Default to false, which only apply changes:
- *
- * – private modifier property
- * - protected/public modifier property when property typed
- *
- * Set to true will allow change whether property is typed or not as far as not forbidden, eg: callable type, null type, etc.
- * @var bool
- */
- private $inlinePublic = \false;
/**
* @readonly
* @var \Rector\Php80\NodeAnalyzer\PromotedPropertyCandidateResolver
@@ -83,7 +71,27 @@ final class ClassPropertyAssignToConstructorPromotionRector extends AbstractRect
* @var \Rector\Php80\Guard\MakePropertyPromotionGuard
*/
private $makePropertyPromotionGuard;
- public function __construct(PromotedPropertyCandidateResolver $promotedPropertyCandidateResolver, VariableRenamer $variableRenamer, VarTagRemover $varTagRemover, ParamAnalyzer $paramAnalyzer, PhpDocTypeChanger $phpDocTypeChanger, MakePropertyPromotionGuard $makePropertyPromotionGuard)
+ /**
+ * @readonly
+ * @var \Rector\NodeTypeResolver\TypeComparator\TypeComparator
+ */
+ private $typeComparator;
+ /**
+ * @api
+ * @var string
+ */
+ public const INLINE_PUBLIC = 'inline_public';
+ /**
+ * Default to false, which only apply changes:
+ *
+ * – private modifier property
+ * - protected/public modifier property when property typed
+ *
+ * Set to true will allow change whether property is typed or not as far as not forbidden, eg: callable type, null type, etc.
+ * @var bool
+ */
+ private $inlinePublic = \false;
+ public function __construct(PromotedPropertyCandidateResolver $promotedPropertyCandidateResolver, VariableRenamer $variableRenamer, VarTagRemover $varTagRemover, ParamAnalyzer $paramAnalyzer, PhpDocTypeChanger $phpDocTypeChanger, MakePropertyPromotionGuard $makePropertyPromotionGuard, TypeComparator $typeComparator)
{
$this->promotedPropertyCandidateResolver = $promotedPropertyCandidateResolver;
$this->variableRenamer = $variableRenamer;
@@ -91,6 +99,7 @@ public function __construct(PromotedPropertyCandidateResolver $promotedPropertyC
$this->paramAnalyzer = $paramAnalyzer;
$this->phpDocTypeChanger = $phpDocTypeChanger;
$this->makePropertyPromotionGuard = $makePropertyPromotionGuard;
+ $this->typeComparator = $typeComparator;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -133,12 +142,14 @@ public function getNodeTypes() : array
*/
public function refactor(Node $node) : ?Node
{
- $promotionCandidates = $this->promotedPropertyCandidateResolver->resolveFromClass($node);
+ $constructClassMethod = $node->getMethod(MethodName::CONSTRUCT);
+ if (!$constructClassMethod instanceof ClassMethod) {
+ return null;
+ }
+ $promotionCandidates = $this->promotedPropertyCandidateResolver->resolveFromClass($node, $constructClassMethod);
if ($promotionCandidates === []) {
return null;
}
- /** @var ClassMethod $constructClassMethod */
- $constructClassMethod = $node->getMethod(MethodName::CONSTRUCT);
$classMethodPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($constructClassMethod);
foreach ($promotionCandidates as $promotionCandidate) {
// does property have some useful annotations?
@@ -150,8 +161,11 @@ public function refactor(Node $node) : ?Node
if (!$this->makePropertyPromotionGuard->isLegal($node, $property, $param, $this->inlinePublic)) {
continue;
}
- $this->removeNode($property);
- $this->removeNode($promotionCandidate->getAssign());
+ $propertyStmtKey = $property->getAttribute(AttributeKey::STMT_KEY);
+ unset($node->stmts[$propertyStmtKey]);
+ // remove assign
+ $assignStmtPosition = $promotionCandidate->getStmtPosition();
+ unset($constructClassMethod->stmts[$assignStmtPosition]);
$property = $promotionCandidate->getProperty();
$paramName = $this->getName($param);
// rename also following calls
@@ -172,7 +186,7 @@ public function refactor(Node $node) : ?Node
$param->flags = $property->flags;
// Copy over attributes of the "old" property
$param->attrGroups = \array_merge($param->attrGroups, $property->attrGroups);
- $this->processNullableType($property, $param);
+ $this->processUnionType($property, $param);
$this->phpDocTypeChanger->copyPropertyDocToParam($constructClassMethod, $property, $param);
}
return $node;
@@ -181,16 +195,31 @@ public function provideMinPhpVersion() : int
{
return PhpVersionFeature::PROPERTY_PROMOTION;
}
- private function processNullableType(Property $property, Param $param) : void
+ private function processUnionType(Property $property, Param $param) : void
{
- if ($this->nodeTypeResolver->isNullableType($property)) {
- $objectType = $this->getType($property);
- $param->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($objectType, TypeKind::PARAM);
+ if ($property->type instanceof Node) {
+ $param->type = $property->type;
+ return;
+ }
+ if (!$param->default instanceof Expr) {
+ return;
+ }
+ if (!$param->type instanceof Node) {
+ return;
+ }
+ $defaultType = $this->getType($param->default);
+ $paramType = $this->getType($param->type);
+ if ($this->typeComparator->isSubtype($defaultType, $paramType)) {
+ return;
+ }
+ if ($this->typeComparator->areTypesEqual($defaultType, $paramType)) {
+ return;
}
- if ($param->default instanceof Expr && $this->valueResolver->isNull($param->default)) {
- $paramType = $this->getType($param);
- $param->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($paramType, TypeKind::PARAM);
+ if ($paramType instanceof MixedType) {
+ return;
}
+ $paramType = TypeCombinator::union($paramType, $defaultType);
+ $param->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($paramType, TypeKind::PARAM);
}
private function decorateParamWithPropertyPhpDocInfo(ClassMethod $classMethod, Property $property, Param $param, string $paramName) : void
{
@@ -205,7 +234,7 @@ private function decorateParamWithPropertyPhpDocInfo(ClassMethod $classMethod, P
}
$paramType = $this->staticTypeMapper->mapPHPStanPhpDocTypeToPHPStanType($varTagValueNode, $property);
$classMethodPhpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($classMethod);
- $this->phpDocTypeChanger->changeParamType($classMethodPhpDocInfo, $paramType, $param, $paramName);
+ $this->phpDocTypeChanger->changeParamType($classMethod, $classMethodPhpDocInfo, $paramType, $param, $paramName);
} else {
$paramType = $this->staticTypeMapper->mapPhpParserNodePHPStanType($param->type);
}
diff --git a/rules/Php80/Rector/Class_/DoctrineAnnotationClassToAttributeRector.php b/rules/Php80/Rector/Class_/DoctrineAnnotationClassToAttributeRector.php
deleted file mode 100644
index c0bc97a8d692..000000000000
--- a/rules/Php80/Rector/Class_/DoctrineAnnotationClassToAttributeRector.php
+++ /dev/null
@@ -1,214 +0,0 @@
-phpDocTagRemover = $phpDocTagRemover;
- $this->attributeFlagFactory = $attributeFlagFactory;
- $this->phpAttributeGroupFactory = $phpAttributeGroupFactory;
- $this->phpAttributeAnalyzer = $phpAttributeAnalyzer;
- $this->propertyToAddCollector = $propertyToAddCollector;
- $this->annotationTargetResolver = $annotationTargetResolver;
- }
- public function provideMinPhpVersion() : int
- {
- return PhpVersionFeature::ATTRIBUTES;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Refactor Doctrine @annotation annotated class to a PHP 8.0 attribute class', [new ConfiguredCodeSample(<<<'CODE_SAMPLE'
-use Doctrine\Common\Annotations\Annotation\Target;
-
-/**
- * @Annotation
- * @Target({"METHOD"})
- */
-class SomeAnnotation
-{
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-use Attribute;
-
-#[Attribute(Attribute::TARGET_METHOD)]
-class SomeAnnotation
-{
-}
-CODE_SAMPLE
-, [self::REMOVE_ANNOTATIONS => \true])]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [Class_::class];
- }
- /**
- * @param Class_ $node
- */
- public function refactor(Node $node) : ?Node
- {
- $phpDocInfo = $this->phpDocInfoFactory->createFromNode($node);
- if (!$phpDocInfo instanceof PhpDocInfo) {
- return null;
- }
- if ($this->shouldSkipClass($phpDocInfo, $node)) {
- return null;
- }
- if ($this->shouldRemoveAnnotations) {
- $this->phpDocTagRemover->removeByName($phpDocInfo, 'annotation');
- $this->phpDocTagRemover->removeByName($phpDocInfo, 'Annotation');
- }
- $attributeGroup = $this->phpAttributeGroupFactory->createFromClass(AttributeName::ATTRIBUTE);
- $this->decorateTarget($phpDocInfo, $attributeGroup);
- foreach ($node->getProperties() as $property) {
- $propertyPhpDocInfo = $this->phpDocInfoFactory->createFromNode($property);
- if (!$propertyPhpDocInfo instanceof PhpDocInfo) {
- continue;
- }
- $requiredDoctrineAnnotationTagValueNode = $propertyPhpDocInfo->findOneByAnnotationClass('Doctrine\\Common\\Annotations\\Annotation\\Required');
- if (!$requiredDoctrineAnnotationTagValueNode instanceof DoctrineAnnotationTagValueNode) {
- continue;
- }
- if ($this->shouldRemoveAnnotations) {
- $this->phpDocTagRemover->removeTagValueFromNode($propertyPhpDocInfo, $requiredDoctrineAnnotationTagValueNode);
- }
- // require in constructor
- $propertyName = $this->getName($property);
- $propertyMetadata = new PropertyMetadata($propertyName, new MixedType(), Class_::MODIFIER_PUBLIC);
- $this->propertyToAddCollector->addPropertyToClass($node, $propertyMetadata);
- if ($this->shouldRemoveAnnotations) {
- $this->removeNode($property);
- }
- }
- $node->attrGroups[] = $attributeGroup;
- return $node;
- }
- /**
- * @param mixed[] $configuration
- */
- public function configure(array $configuration) : void
- {
- $shouldRemoveAnnotations = $configuration[self::REMOVE_ANNOTATIONS] ?? (bool) \current($configuration);
- Assert::boolean($shouldRemoveAnnotations);
- $this->shouldRemoveAnnotations = $shouldRemoveAnnotations;
- }
- private function decorateTarget(PhpDocInfo $phpDocInfo, AttributeGroup $attributeGroup) : void
- {
- $targetDoctrineAnnotationTagValueNode = $phpDocInfo->findOneByAnnotationClasses(['Doctrine\\Common\\Annotations\\Annotation\\Target', 'Target']);
- if (!$targetDoctrineAnnotationTagValueNode instanceof DoctrineAnnotationTagValueNode) {
- return;
- }
- if ($this->shouldRemoveAnnotations) {
- $this->phpDocTagRemover->removeTagValueFromNode($phpDocInfo, $targetDoctrineAnnotationTagValueNode);
- }
- $targetValues = $this->resolveTargetValues($targetDoctrineAnnotationTagValueNode);
- if ($targetValues === []) {
- return;
- }
- $flagClassConstFetches = $this->annotationTargetResolver->resolveFlagClassConstFetches($targetValues);
- $flagCollection = $this->attributeFlagFactory->createFlagCollection($flagClassConstFetches);
- if ($flagCollection === null) {
- return;
- }
- $attributeGroup->attrs[0]->args[] = new Arg($flagCollection);
- }
- private function shouldSkipClass(PhpDocInfo $phpDocInfo, Class_ $class) : bool
- {
- if (!$phpDocInfo->hasByNames(['Annotation', 'annotation'])) {
- return \true;
- }
- // has attribute? skip it
- return $this->phpAttributeAnalyzer->hasPhpAttribute($class, AttributeName::ATTRIBUTE);
- }
- /**
- * @return ArrayItemNode[]
- */
- private function resolveTargetValues(DoctrineAnnotationTagValueNode $targetDoctrineAnnotationTagValueNode) : array
- {
- $silentTargetsArrayItemNode = $targetDoctrineAnnotationTagValueNode->getSilentValue();
- if ($silentTargetsArrayItemNode instanceof ArrayItemNode) {
- if ($silentTargetsArrayItemNode->value instanceof CurlyListNode) {
- return $silentTargetsArrayItemNode->value->getValues();
- }
- return [$silentTargetsArrayItemNode];
- }
- return [];
- }
-}
diff --git a/rules/Php80/Rector/Class_/StringableForToStringRector.php b/rules/Php80/Rector/Class_/StringableForToStringRector.php
index aa5ce04f9149..9173cab35738 100644
--- a/rules/Php80/Rector/Class_/StringableForToStringRector.php
+++ b/rules/Php80/Rector/Class_/StringableForToStringRector.php
@@ -28,10 +28,6 @@
*/
final class StringableForToStringRector extends AbstractRector implements MinPhpVersionInterface
{
- /**
- * @var string
- */
- private const STRINGABLE = 'Stringable';
/**
* @readonly
* @var \Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer
@@ -47,6 +43,10 @@ final class StringableForToStringRector extends AbstractRector implements MinPhp
* @var \Rector\Core\NodeAnalyzer\ClassAnalyzer
*/
private $classAnalyzer;
+ /**
+ * @var string
+ */
+ private const STRINGABLE = 'Stringable';
public function __construct(FamilyRelationsAnalyzer $familyRelationsAnalyzer, ReturnTypeInferer $returnTypeInferer, ClassAnalyzer $classAnalyzer)
{
$this->familyRelationsAnalyzer = $familyRelationsAnalyzer;
diff --git a/rules/Php80/Rector/FuncCall/ClassOnObjectRector.php b/rules/Php80/Rector/FuncCall/ClassOnObjectRector.php
index 1b2d6af31761..1a4de0138fa1 100644
--- a/rules/Php80/Rector/FuncCall/ClassOnObjectRector.php
+++ b/rules/Php80/Rector/FuncCall/ClassOnObjectRector.php
@@ -56,6 +56,9 @@ public function refactor(Node $node) : ?Node
if (!$this->nodeNameResolver->isName($node, 'get_class')) {
return null;
}
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
if (!isset($node->getArgs()[0])) {
return new ClassConstFetch(new Name('self'), 'class');
}
diff --git a/rules/Php80/Rector/FuncCall/Php8ResourceReturnToObjectRector.php b/rules/Php80/Rector/FuncCall/Php8ResourceReturnToObjectRector.php
index af40fc7c1345..b647943870b0 100644
--- a/rules/Php80/Rector/FuncCall/Php8ResourceReturnToObjectRector.php
+++ b/rules/Php80/Rector/FuncCall/Php8ResourceReturnToObjectRector.php
@@ -19,6 +19,11 @@
*/
final class Php8ResourceReturnToObjectRector extends AbstractRector implements MinPhpVersionInterface
{
+ /**
+ * @readonly
+ * @var \Rector\Php80\NodeManipulator\ResourceReturnToObject
+ */
+ private $resourceReturnToObject;
/**
* @var array
*/
@@ -78,11 +83,6 @@ final class Php8ResourceReturnToObjectRector extends AbstractRector implements M
'inflate_init' => 'InflateContext',
'deflate_init' => 'DeflateContext',
];
- /**
- * @readonly
- * @var \Rector\Php80\NodeManipulator\ResourceReturnToObject
- */
- private $resourceReturnToObject;
public function __construct(ResourceReturnToObject $resourceReturnToObject)
{
$this->resourceReturnToObject = $resourceReturnToObject;
diff --git a/rules/Php80/Rector/FunctionLike/MixedTypeRector.php b/rules/Php80/Rector/FunctionLike/MixedTypeRector.php
index 76889d45ea20..b01878e6b7e1 100644
--- a/rules/Php80/Rector/FunctionLike/MixedTypeRector.php
+++ b/rules/Php80/Rector/FunctionLike/MixedTypeRector.php
@@ -27,10 +27,6 @@
*/
final class MixedTypeRector extends AbstractRector implements MinPhpVersionInterface
{
- /**
- * @var bool
- */
- private $hasChanged = \false;
/**
* @readonly
* @var \Rector\Core\Reflection\ReflectionResolver
@@ -46,6 +42,10 @@ final class MixedTypeRector extends AbstractRector implements MinPhpVersionInter
* @var \Rector\DeadCode\PhpDoc\TagRemover\ParamTagRemover
*/
private $paramTagRemover;
+ /**
+ * @var bool
+ */
+ private $hasChanged = \false;
public function __construct(ReflectionResolver $reflectionResolver, ClassChildAnalyzer $classChildAnalyzer, ParamTagRemover $paramTagRemover)
{
$this->reflectionResolver = $reflectionResolver;
diff --git a/rules/Php80/Rector/FunctionLike/UnionTypesRector.php b/rules/Php80/Rector/FunctionLike/UnionTypesRector.php
deleted file mode 100644
index 6f0a9a0f8649..000000000000
--- a/rules/Php80/Rector/FunctionLike/UnionTypesRector.php
+++ /dev/null
@@ -1,66 +0,0 @@
->
- */
- 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
- {
- $errorMessage = \sprintf('Rule "%s" is deprecated, as dangerous to move docblocks for type declarations. Use strict type rules instead', self::class);
- \trigger_error($errorMessage, \E_USER_WARNING);
- \sleep(3);
- return null;
- }
- public function provideMinPhpVersion() : int
- {
- return PhpVersionFeature::UNION_TYPES;
- }
-}
diff --git a/rules/Php80/Rector/Identical/StrStartsWithRector.php b/rules/Php80/Rector/Identical/StrStartsWithRector.php
index fda1a07992bb..42792e08e497 100644
--- a/rules/Php80/Rector/Identical/StrStartsWithRector.php
+++ b/rules/Php80/Rector/Identical/StrStartsWithRector.php
@@ -11,6 +11,9 @@
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\Php80\Contract\StrStartWithMatchAndRefactorInterface;
+use Rector\Php80\MatchAndRefactor\StrStartsWithMatchAndRefactor\StrncmpMatchAndRefactor;
+use Rector\Php80\MatchAndRefactor\StrStartsWithMatchAndRefactor\StrposMatchAndRefactor;
+use Rector\Php80\MatchAndRefactor\StrStartsWithMatchAndRefactor\SubstrMatchAndRefactor;
use Rector\Php80\ValueObject\StrStartsWith;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -27,15 +30,11 @@ final class StrStartsWithRector extends AbstractRector implements MinPhpVersionI
{
/**
* @var StrStartWithMatchAndRefactorInterface[]
- * @readonly
*/
- private $strStartWithMatchAndRefactors;
- /**
- * @param StrStartWithMatchAndRefactorInterface[] $strStartWithMatchAndRefactors
- */
- public function __construct(array $strStartWithMatchAndRefactors)
+ private $strStartWithMatchAndRefactors = [];
+ public function __construct(StrncmpMatchAndRefactor $strncmpMatchAndRefactor, SubstrMatchAndRefactor $substrMatchAndRefactor, StrposMatchAndRefactor $strposMatchAndRefactor)
{
- $this->strStartWithMatchAndRefactors = $strStartWithMatchAndRefactors;
+ $this->strStartWithMatchAndRefactors = [$strncmpMatchAndRefactor, $substrMatchAndRefactor, $strposMatchAndRefactor];
}
public function provideMinPhpVersion() : int
{
diff --git a/rules/Php80/Rector/NotIdentical/StrContainsRector.php b/rules/Php80/Rector/NotIdentical/StrContainsRector.php
index fc3eadeac521..963570870bf0 100644
--- a/rules/Php80/Rector/NotIdentical/StrContainsRector.php
+++ b/rules/Php80/Rector/NotIdentical/StrContainsRector.php
@@ -72,6 +72,9 @@ public function refactor(Node $node) : ?Node
if (!$funcCall instanceof FuncCall) {
return null;
}
+ if ($funcCall->isFirstClassCallable()) {
+ return null;
+ }
if (isset($funcCall->getArgs()[2])) {
$secondArg = $funcCall->getArgs()[2];
if ($this->isName($funcCall->name, 'strpos') && $this->isPositiveInteger($secondArg->value)) {
diff --git a/rules/Php80/Rector/Property/NestedAnnotationToAttributeRector.php b/rules/Php80/Rector/Property/NestedAnnotationToAttributeRector.php
index a9b9a411714c..76cff762e76a 100644
--- a/rules/Php80/Rector/Property/NestedAnnotationToAttributeRector.php
+++ b/rules/Php80/Rector/Property/NestedAnnotationToAttributeRector.php
@@ -35,10 +35,6 @@
*/
final class NestedAnnotationToAttributeRector extends AbstractRector implements ConfigurableRectorInterface, MinPhpVersionInterface
{
- /**
- * @var NestedAnnotationToAttribute[]
- */
- private $nestedAnnotationsToAttributes = [];
/**
* @readonly
* @var \Rector\Naming\Naming\UseImportsResolver
@@ -59,6 +55,10 @@ final class NestedAnnotationToAttributeRector extends AbstractRector implements
* @var \Rector\PostRector\Collector\UseNodesToAddCollector
*/
private $useNodesToAddCollector;
+ /**
+ * @var NestedAnnotationToAttribute[]
+ */
+ private $nestedAnnotationsToAttributes = [];
public function __construct(UseImportsResolver $useImportsResolver, PhpDocTagRemover $phpDocTagRemover, NestedAttrGroupsFactory $nestedAttrGroupsFactory, UseNodesToAddCollector $useNodesToAddCollector)
{
$this->useImportsResolver = $useImportsResolver;
@@ -111,7 +111,7 @@ public function refactor(Node $node) : ?Node
if (!$phpDocInfo instanceof PhpDocInfo) {
return null;
}
- $uses = $this->useImportsResolver->resolveBareUsesForNode($node);
+ $uses = $this->useImportsResolver->resolveBareUses();
$attributeGroups = $this->transformDoctrineAnnotationClassesToAttributeGroups($phpDocInfo, $uses);
if ($attributeGroups === []) {
return null;
diff --git a/rules/Php80/Rector/Ternary/GetDebugTypeRector.php b/rules/Php80/Rector/Ternary/GetDebugTypeRector.php
index 5142de5a4378..0a082a1de1f0 100644
--- a/rules/Php80/Rector/Ternary/GetDebugTypeRector.php
+++ b/rules/Php80/Rector/Ternary/GetDebugTypeRector.php
@@ -112,6 +112,9 @@ private function areValuesIdentical(Ternary $ternary) : bool
{
/** @var FuncCall $isObjectFuncCall */
$isObjectFuncCall = $ternary->cond;
+ if ($isObjectFuncCall->isFirstClassCallable()) {
+ return \false;
+ }
$firstExpr = $isObjectFuncCall->getArgs()[0]->value;
/** @var FuncCall|ClassConstFetch $getClassFuncCallOrClassConstFetchClass */
$getClassFuncCallOrClassConstFetchClass = $ternary->if;
diff --git a/rules/Php80/ValueObject/ClassNameAndTagValueNode.php b/rules/Php80/ValueObject/ClassNameAndTagValueNode.php
deleted file mode 100644
index b4d7f2c45b5e..000000000000
--- a/rules/Php80/ValueObject/ClassNameAndTagValueNode.php
+++ /dev/null
@@ -1,40 +0,0 @@
-enumClass = $enumClass;
- $this->tagValueNode = $tagValueNode;
- }
- public function getEnumClass() : string
- {
- return $this->enumClass;
- }
- /**
- * @return \PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode|\PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode|\PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode
- */
- public function getTagValueNode()
- {
- return $this->tagValueNode;
- }
-}
diff --git a/rules/Php80/ValueObject/NestedAnnotationToAttribute.php b/rules/Php80/ValueObject/NestedAnnotationToAttribute.php
index 73912fb28c57..8f7962580933 100644
--- a/rules/Php80/ValueObject/NestedAnnotationToAttribute.php
+++ b/rules/Php80/ValueObject/NestedAnnotationToAttribute.php
@@ -7,10 +7,6 @@
use Rector\Php80\Contract\ValueObject\AnnotationToAttributeInterface;
final class NestedAnnotationToAttribute implements AnnotationToAttributeInterface
{
- /**
- * @var AnnotationPropertyToAttributeClass[]
- */
- private $annotationPropertiesToAttributeClasses = [];
/**
* @readonly
* @var string
@@ -21,6 +17,10 @@ final class NestedAnnotationToAttribute implements AnnotationToAttributeInterfac
* @var bool
*/
private $removeOriginal = \false;
+ /**
+ * @var AnnotationPropertyToAttributeClass[]
+ */
+ private $annotationPropertiesToAttributeClasses = [];
/**
* @param array|string[]|AnnotationPropertyToAttributeClass[] $annotationPropertiesToAttributeClasses
*/
diff --git a/rules/Php80/ValueObject/PropertyPromotionCandidate.php b/rules/Php80/ValueObject/PropertyPromotionCandidate.php
index 3808a79da33e..3f95f34e69b2 100644
--- a/rules/Php80/ValueObject/PropertyPromotionCandidate.php
+++ b/rules/Php80/ValueObject/PropertyPromotionCandidate.php
@@ -3,9 +3,10 @@
declare (strict_types=1);
namespace Rector\Php80\ValueObject;
-use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Param;
+use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Property;
+use Rector\NodeTypeResolver\Node\AttributeKey;
final class PropertyPromotionCandidate
{
/**
@@ -15,30 +16,30 @@ final class PropertyPromotionCandidate
private $property;
/**
* @readonly
- * @var \PhpParser\Node\Expr\Assign
+ * @var \PhpParser\Node\Param
*/
- private $assign;
+ private $param;
/**
* @readonly
- * @var \PhpParser\Node\Param
+ * @var \PhpParser\Node\Stmt\Expression
*/
- private $param;
- public function __construct(Property $property, Assign $assign, Param $param)
+ private $expression;
+ public function __construct(Property $property, Param $param, Expression $expression)
{
$this->property = $property;
- $this->assign = $assign;
$this->param = $param;
+ $this->expression = $expression;
}
public function getProperty() : Property
{
return $this->property;
}
- public function getAssign() : Assign
- {
- return $this->assign;
- }
public function getParam() : Param
{
return $this->param;
}
+ public function getStmtPosition() : int
+ {
+ return $this->expression->getAttribute(AttributeKey::STMT_KEY);
+ }
}
diff --git a/rules/Php80/ValueObjectFactory/StrStartsWithFactory.php b/rules/Php80/ValueObjectFactory/StrStartsWithFactory.php
index 7d37c631434b..83b01903a4e4 100644
--- a/rules/Php80/ValueObjectFactory/StrStartsWithFactory.php
+++ b/rules/Php80/ValueObjectFactory/StrStartsWithFactory.php
@@ -9,6 +9,9 @@ final class StrStartsWithFactory
{
public function createFromFuncCall(FuncCall $funcCall, bool $isPositive) : ?StrStartsWith
{
+ if ($funcCall->isFirstClassCallable()) {
+ return null;
+ }
if (\count($funcCall->getArgs()) < 2) {
return null;
}
diff --git a/rules/Php81/Enum/AttributeName.php b/rules/Php81/Enum/AttributeName.php
index 74c02d851633..66104059075a 100644
--- a/rules/Php81/Enum/AttributeName.php
+++ b/rules/Php81/Enum/AttributeName.php
@@ -11,10 +11,6 @@ final class AttributeName
* @var string
*/
public const RETURN_TYPE_WILL_CHANGE = 'ReturnTypeWillChange';
- /**
- * @var string
- */
- public const ATTRIBUTE = 'Attribute';
/**
* @var string
*/
diff --git a/rules/Php81/NodeAnalyzer/CoalesePropertyAssignMatcher.php b/rules/Php81/NodeAnalyzer/CoalesePropertyAssignMatcher.php
new file mode 100644
index 000000000000..3e1667eff514
--- /dev/null
+++ b/rules/Php81/NodeAnalyzer/CoalesePropertyAssignMatcher.php
@@ -0,0 +1,70 @@
+complexNewAnalyzer = $complexNewAnalyzer;
+ $this->nodeNameResolver = $nodeNameResolver;
+ }
+ /**
+ * Matches
+ *
+ * $this->value = $param ?? 'default';
+ */
+ public function matchCoalesceAssignsToLocalPropertyNamed(Stmt $stmt, string $propertyName) : ?Coalesce
+ {
+ if (!$stmt instanceof Expression) {
+ return null;
+ }
+ if (!$stmt->expr instanceof Assign) {
+ return null;
+ }
+ $assign = $stmt->expr;
+ if (!$assign->expr instanceof Coalesce) {
+ return null;
+ }
+ $coalesce = $assign->expr;
+ if (!$coalesce->right instanceof New_) {
+ return null;
+ }
+ if ($this->complexNewAnalyzer->isDynamic($coalesce->right)) {
+ return null;
+ }
+ if (!$this->isLocalPropertyFetchNamed($assign->var, $propertyName)) {
+ return null;
+ }
+ return $assign->expr;
+ }
+ private function isLocalPropertyFetchNamed(Expr $expr, string $propertyName) : bool
+ {
+ if (!$expr instanceof PropertyFetch) {
+ return \false;
+ }
+ if (!$this->nodeNameResolver->isName($expr->var, 'this')) {
+ return \false;
+ }
+ return $this->nodeNameResolver->isName($expr->name, $propertyName);
+ }
+}
diff --git a/rules/Php81/NodeAnalyzer/ComplexNewAnalyzer.php b/rules/Php81/NodeAnalyzer/ComplexNewAnalyzer.php
index e2df97fef56a..08248004c910 100644
--- a/rules/Php81/NodeAnalyzer/ComplexNewAnalyzer.php
+++ b/rules/Php81/NodeAnalyzer/ComplexNewAnalyzer.php
@@ -32,6 +32,9 @@ public function isDynamic(New_ $new) : bool
if (!$new->class instanceof FullyQualified) {
return \true;
}
+ if ($new->isFirstClassCallable()) {
+ return \false;
+ }
$args = $new->getArgs();
foreach ($args as $arg) {
$value = $arg->value;
diff --git a/rules/Php81/NodeAnalyzer/EnumConstListClassDetector.php b/rules/Php81/NodeAnalyzer/EnumConstListClassDetector.php
deleted file mode 100644
index f14e8effb746..000000000000
--- a/rules/Php81/NodeAnalyzer/EnumConstListClassDetector.php
+++ /dev/null
@@ -1,81 +0,0 @@
-nodeTypeResolver = $nodeTypeResolver;
- }
- public function detect(Class_ $class) : bool
- {
- $classConstants = $class->getConstants();
- // must have at least 2 constants, otherwise probably not enum
- if (\count($classConstants) < 2) {
- return \false;
- }
- // only constants are allowed, nothing else
- if (\count($class->stmts) !== \count($classConstants)) {
- return \false;
- }
- // all constant must be public
- if (!$this->hasExclusivelyPublicClassConsts($classConstants)) {
- return \false;
- }
- // all constants must have exactly 1 value
- foreach ($classConstants as $classConstant) {
- if (\count($classConstant->consts) !== 1) {
- return \false;
- }
- }
- // only scalar values are allowed
- foreach ($classConstants as $classConstant) {
- $onlyConstConst = $classConstant->consts[0];
- if (!$onlyConstConst->value instanceof Scalar) {
- return \false;
- }
- }
- $uniqueTypeClasses = $this->resolveClassConstTypes($classConstants);
- // must be exactly 1 type
- return \count($uniqueTypeClasses) === 1;
- }
- /**
- * @param ClassConst[] $classConsts
- * @return array>
- */
- private function resolveClassConstTypes(array $classConsts) : array
- {
- $typeClasses = [];
- // all constants must have same type
- foreach ($classConsts as $classConst) {
- $const = $classConst->consts[0];
- $type = $this->nodeTypeResolver->getType($const->value);
- $typeClasses[] = \get_class($type);
- }
- return \array_unique($typeClasses);
- }
- /**
- * @param ClassConst[] $classConsts
- */
- private function hasExclusivelyPublicClassConsts(array $classConsts) : bool
- {
- foreach ($classConsts as $classConst) {
- if (!$classConst->isPublic()) {
- return \false;
- }
- }
- return \true;
- }
-}
diff --git a/rules/Php81/Rector/ClassConst/FinalizePublicClassConstantRector.php b/rules/Php81/Rector/ClassConst/FinalizePublicClassConstantRector.php
index 114357b33236..ddf1fa46abbc 100644
--- a/rules/Php81/Rector/ClassConst/FinalizePublicClassConstantRector.php
+++ b/rules/Php81/Rector/ClassConst/FinalizePublicClassConstantRector.php
@@ -5,10 +5,9 @@
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassConst;
+use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ReflectionProvider;
-use Rector\Core\NodeAnalyzer\ClassAnalyzer;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
use Rector\Privatization\NodeManipulator\VisibilityManipulator;
@@ -20,7 +19,7 @@
*
* @see \Rector\Tests\Php81\Rector\ClassConst\FinalizePublicClassConstantRector\FinalizePublicClassConstantRectorTest
*/
-final class FinalizePublicClassConstantRector extends AbstractRector implements MinPhpVersionInterface
+final class FinalizePublicClassConstantRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -32,21 +31,15 @@ final class FinalizePublicClassConstantRector extends AbstractRector implements
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
- /**
- * @readonly
- * @var \Rector\Core\NodeAnalyzer\ClassAnalyzer
- */
- private $classAnalyzer;
/**
* @readonly
* @var \Rector\Privatization\NodeManipulator\VisibilityManipulator
*/
private $visibilityManipulator;
- public function __construct(FamilyRelationsAnalyzer $familyRelationsAnalyzer, ReflectionProvider $reflectionProvider, ClassAnalyzer $classAnalyzer, VisibilityManipulator $visibilityManipulator)
+ public function __construct(FamilyRelationsAnalyzer $familyRelationsAnalyzer, ReflectionProvider $reflectionProvider, VisibilityManipulator $visibilityManipulator)
{
$this->familyRelationsAnalyzer = $familyRelationsAnalyzer;
$this->reflectionProvider = $reflectionProvider;
- $this->classAnalyzer = $classAnalyzer;
$this->visibilityManipulator = $visibilityManipulator;
}
public function getRuleDefinition() : RuleDefinition
@@ -70,34 +63,41 @@ class SomeClass
*/
public function getNodeTypes() : array
{
- return [ClassConst::class];
+ return [Class_::class];
}
/**
- * @param ClassConst $node
+ * @param Class_ $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
- $class = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$class instanceof Class_) {
- return null;
- }
- if ($class->isFinal()) {
+ if ($node->isFinal()) {
return null;
}
- if (!$node->isPublic()) {
+ if (!$scope->isInClass()) {
return null;
}
- if ($node->isFinal()) {
+ $classReflection = $scope->getClassReflection();
+ if ($classReflection->isAnonymous()) {
return null;
}
- if ($this->classAnalyzer->isAnonymousClass($class)) {
- return null;
+ $hasChanged = \false;
+ foreach ($node->getConstants() as $classConst) {
+ if (!$classConst->isPublic()) {
+ continue;
+ }
+ if ($classConst->isFinal()) {
+ continue;
+ }
+ if ($this->isClassHasChildren($node)) {
+ continue;
+ }
+ $hasChanged = \true;
+ $this->visibilityManipulator->makeFinal($classConst);
}
- if ($this->isClassHasChildren($class)) {
- return null;
+ if ($hasChanged) {
+ return $node;
}
- $this->visibilityManipulator->makeFinal($node);
- return $node;
+ return null;
}
public function provideMinPhpVersion() : int
{
diff --git a/rules/Php81/Rector/ClassMethod/NewInInitializerRector.php b/rules/Php81/Rector/ClassMethod/NewInInitializerRector.php
index 75cf1fcfcac9..f240f8dc0c40 100644
--- a/rules/Php81/Rector/ClassMethod/NewInInitializerRector.php
+++ b/rules/Php81/Rector/ClassMethod/NewInInitializerRector.php
@@ -4,15 +4,11 @@
namespace Rector\Php81\Rector\ClassMethod;
use PhpParser\Node;
-use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\BinaryOp\Coalesce;
-use PhpParser\Node\Expr\New_;
use PhpParser\Node\NullableType;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Property;
use PHPStan\Reflection\ClassReflection;
use Rector\Core\Rector\AbstractRector;
@@ -20,7 +16,7 @@
use Rector\Core\ValueObject\MethodName;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\FamilyTree\NodeAnalyzer\ClassChildAnalyzer;
-use Rector\Php81\NodeAnalyzer\ComplexNewAnalyzer;
+use Rector\Php81\NodeAnalyzer\CoalesePropertyAssignMatcher;
use Rector\VersionBonding\Contract\MinPhpVersionInterface;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
@@ -31,11 +27,6 @@
*/
final class NewInInitializerRector extends AbstractRector implements MinPhpVersionInterface
{
- /**
- * @readonly
- * @var \Rector\Php81\NodeAnalyzer\ComplexNewAnalyzer
- */
- private $complexNewAnalyzer;
/**
* @readonly
* @var \Rector\Core\Reflection\ReflectionResolver
@@ -46,11 +37,16 @@ final class NewInInitializerRector extends AbstractRector implements MinPhpVersi
* @var \Rector\FamilyTree\NodeAnalyzer\ClassChildAnalyzer
*/
private $classChildAnalyzer;
- public function __construct(ComplexNewAnalyzer $complexNewAnalyzer, ReflectionResolver $reflectionResolver, ClassChildAnalyzer $classChildAnalyzer)
+ /**
+ * @readonly
+ * @var \Rector\Php81\NodeAnalyzer\CoalesePropertyAssignMatcher
+ */
+ private $coalesePropertyAssignMatcher;
+ public function __construct(ReflectionResolver $reflectionResolver, ClassChildAnalyzer $classChildAnalyzer, CoalesePropertyAssignMatcher $coalesePropertyAssignMatcher)
{
- $this->complexNewAnalyzer = $complexNewAnalyzer;
$this->reflectionResolver = $reflectionResolver;
$this->classChildAnalyzer = $classChildAnalyzer;
+ $this->coalesePropertyAssignMatcher = $coalesePropertyAssignMatcher;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -82,39 +78,40 @@ public function __construct(
*/
public function getNodeTypes() : array
{
- return [ClassMethod::class];
+ return [Class_::class];
}
/**
- * @param ClassMethod $node
+ * @param Class_ $node
*/
public function refactor(Node $node) : ?Node
{
- $params = $this->resolveParams($node);
+ if ($node->stmts === null || $node->stmts === []) {
+ return null;
+ }
+ if ($node->isAbstract() || $node->isAnonymous()) {
+ return null;
+ }
+ $constructClassMethod = $node->getMethod(MethodName::CONSTRUCT);
+ if (!$constructClassMethod instanceof ClassMethod) {
+ return null;
+ }
+ $params = $this->resolveParams($constructClassMethod);
if ($params === []) {
return null;
}
$hasChanged = \false;
- foreach ($params as $param) {
- /** @var string $paramName */
- $paramName = $this->getName($param->var);
- $toPropertyAssigns = $this->betterNodeFinder->findClassMethodAssignsToLocalProperty($node, $paramName);
- $toPropertyAssigns = \array_filter($toPropertyAssigns, static function (Assign $assign) : bool {
- return $assign->expr instanceof Coalesce;
- });
- foreach ($toPropertyAssigns as $toPropertyAssign) {
- /** @var Coalesce $coalesce */
- $coalesce = $toPropertyAssign->expr;
- if (!$coalesce->right instanceof New_) {
- continue;
- }
- if ($this->complexNewAnalyzer->isDynamic($coalesce->right)) {
+ foreach ((array) $constructClassMethod->stmts as $key => $stmt) {
+ foreach ($params as $param) {
+ $paramName = $this->getName($param);
+ $coalesce = $this->coalesePropertyAssignMatcher->matchCoalesceAssignsToLocalPropertyNamed($stmt, $paramName);
+ if (!$coalesce instanceof Coalesce) {
continue;
}
/** @var NullableType $currentParamType */
$currentParamType = $param->type;
$param->type = $currentParamType->type;
$param->default = $coalesce->right;
- $this->removeNode($toPropertyAssign);
+ unset($constructClassMethod->stmts[$key]);
$this->processPropertyPromotion($node, $param, $paramName);
$hasChanged = \true;
}
@@ -133,9 +130,6 @@ public function provideMinPhpVersion() : int
*/
private function resolveParams(ClassMethod $classMethod) : array
{
- if (!$this->isLegalClass($classMethod)) {
- return [];
- }
$params = $this->matchConstructorParams($classMethod);
if ($params === []) {
return [];
@@ -151,43 +145,28 @@ private function isOverrideAbstractMethod(ClassMethod $classMethod) : bool
$methodName = $this->nodeNameResolver->getName($classMethod);
return $classReflection instanceof ClassReflection && $this->classChildAnalyzer->hasAbstractParentClassMethod($classReflection, $methodName);
}
- private function processPropertyPromotion(ClassMethod $classMethod, Param $param, string $paramName) : void
+ private function processPropertyPromotion(Class_ $class, Param $param, string $paramName) : void
{
- $classLike = $this->betterNodeFinder->findParentType($classMethod, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
- return;
- }
- $property = $classLike->getProperty($paramName);
- if (!$property instanceof Property) {
- return;
- }
- $param->flags = $property->flags;
- $param->attrGroups = \array_merge($property->attrGroups, $param->attrGroups);
- $this->removeNode($property);
- }
- private function isLegalClass(ClassMethod $classMethod) : bool
- {
- $classLike = $this->betterNodeFinder->findParentType($classMethod, ClassLike::class);
- if ($classLike instanceof Interface_) {
- return \false;
- }
- if ($classLike instanceof Class_) {
- return !$classLike->isAbstract();
+ foreach ($class->stmts as $key => $stmt) {
+ if (!$stmt instanceof Property) {
+ continue;
+ }
+ $property = $stmt;
+ if (!$this->isName($stmt, $paramName)) {
+ continue;
+ }
+ $param->flags = $property->flags;
+ $param->attrGroups = \array_merge($property->attrGroups, $param->attrGroups);
+ unset($class->stmts[$key]);
}
- return \true;
}
/**
* @return Param[]
*/
private function matchConstructorParams(ClassMethod $classMethod) : array
{
- if (!$this->isName($classMethod, MethodName::CONSTRUCT)) {
- return [];
- }
- if ($classMethod->params === []) {
- return [];
- }
- if ((array) $classMethod->stmts === []) {
+ // skip empty constructor assigns, as we need those here
+ if ($classMethod->stmts === null || $classMethod->stmts === []) {
return [];
}
return \array_filter($classMethod->params, static function (Param $param) : bool {
diff --git a/rules/Php81/Rector/Class_/ConstantListClassToEnumRector.php b/rules/Php81/Rector/Class_/ConstantListClassToEnumRector.php
deleted file mode 100644
index 6da71d4bbafe..000000000000
--- a/rules/Php81/Rector/Class_/ConstantListClassToEnumRector.php
+++ /dev/null
@@ -1,181 +0,0 @@
-enumConstListClassDetector = $enumConstListClassDetector;
- $this->enumFactory = $enumFactory;
- $this->enumParamAnalyzer = $enumParamAnalyzer;
- $this->reflectionResolver = $reflectionResolver;
- $this->phpDocTagRemover = $phpDocTagRemover;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Upgrade constant list classes to full blown enum', [new CodeSample(<<<'CODE_SAMPLE'
-class Direction
-{
- public const LEFT = 'left';
-
- public const RIGHT = 'right';
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-enum Direction
-{
- case LEFT;
-
- case RIGHT;
-}
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [Class_::class, ClassMethod::class, Property::class];
- }
- /**
- * @param Class_|ClassMethod|Property $node
- */
- public function refactor(Node $node) : ?Node
- {
- if ($node instanceof Class_) {
- if (!$this->enumConstListClassDetector->detect($node)) {
- return null;
- }
- return $this->enumFactory->createFromClass($node);
- }
- if ($node instanceof ClassMethod) {
- return $this->refactorClassMethod($node);
- }
- return $this->refactorProperty($node);
- }
- private function refactorClassMethod(ClassMethod $classMethod) : ?ClassMethod
- {
- // enum param types doc requires a docblock
- $phpDocInfo = $this->phpDocInfoFactory->createFromNode($classMethod);
- if (!$phpDocInfo instanceof PhpDocInfo) {
- return null;
- }
- $methodReflection = $this->reflectionResolver->resolveMethodReflectionFromClassMethod($classMethod);
- if (!$methodReflection instanceof MethodReflection) {
- return null;
- }
- // refactor params
- $haveParamsChanged = $this->refactorParams($methodReflection, $phpDocInfo, $classMethod);
- $hasReturnChanged = $this->refactorReturn($phpDocInfo, $classMethod);
- if ($haveParamsChanged) {
- return $classMethod;
- }
- if ($hasReturnChanged) {
- return $classMethod;
- }
- return null;
- }
- private function getParamByName(ClassMethod $classMethod, string $desiredParamName) : ?Param
- {
- foreach ($classMethod->params as $param) {
- if (!$this->nodeNameResolver->isName($param, $desiredParamName)) {
- continue;
- }
- return $param;
- }
- return null;
- }
- private function refactorParams(MethodReflection $methodReflection, PhpDocInfo $phpDocInfo, ClassMethod $classMethod) : bool
- {
- $hasNodeChanged = \false;
- $parametersAcceptor = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants());
- foreach ($parametersAcceptor->getParameters() as $parameterReflection) {
- $classNameAndTagValueNode = $this->enumParamAnalyzer->matchParameterClassName($parameterReflection, $phpDocInfo);
- if (!$classNameAndTagValueNode instanceof ClassNameAndTagValueNode) {
- continue;
- }
- $param = $this->getParamByName($classMethod, $parameterReflection->getName());
- if (!$param instanceof Param) {
- continue;
- }
- // change and remove
- $param->type = new FullyQualified($classNameAndTagValueNode->getEnumClass());
- $hasNodeChanged = \true;
- $this->phpDocTagRemover->removeTagValueFromNode($phpDocInfo, $classNameAndTagValueNode->getTagValueNode());
- }
- return $hasNodeChanged;
- }
- private function refactorReturn(PhpDocInfo $phpDocInfo, ClassMethod $classMethod) : bool
- {
- $classNameAndTagValueNode = $this->enumParamAnalyzer->matchReturnClassName($phpDocInfo);
- if (!$classNameAndTagValueNode instanceof ClassNameAndTagValueNode) {
- return \false;
- }
- $classMethod->returnType = new FullyQualified($classNameAndTagValueNode->getEnumClass());
- $this->phpDocTagRemover->removeTagValueFromNode($phpDocInfo, $classNameAndTagValueNode->getTagValueNode());
- return \true;
- }
- private function refactorProperty(Property $property) : ?Property
- {
- $phpDocInfo = $this->phpDocInfoFactory->createFromNode($property);
- if (!$phpDocInfo instanceof PhpDocInfo) {
- return null;
- }
- $classNameAndTagValueNode = $this->enumParamAnalyzer->matchPropertyClassName($phpDocInfo);
- if (!$classNameAndTagValueNode instanceof ClassNameAndTagValueNode) {
- return null;
- }
- $property->type = new FullyQualified($classNameAndTagValueNode->getEnumClass());
- $this->phpDocTagRemover->removeTagValueFromNode($phpDocInfo, $classNameAndTagValueNode->getTagValueNode());
- return $property;
- }
-}
diff --git a/rules/Php81/Rector/FuncCall/NullToStrictStringFuncCallArgRector.php b/rules/Php81/Rector/FuncCall/NullToStrictStringFuncCallArgRector.php
index 8e573b0fb73c..8ea6509efa6d 100644
--- a/rules/Php81/Rector/FuncCall/NullToStrictStringFuncCallArgRector.php
+++ b/rules/Php81/Rector/FuncCall/NullToStrictStringFuncCallArgRector.php
@@ -6,7 +6,6 @@
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
-use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Cast\String_ as CastString_;
use PhpParser\Node\Expr\ConstFetch;
use PhpParser\Node\Expr\FuncCall;
@@ -35,10 +34,6 @@
*/
final class NullToStrictStringFuncCallArgRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
- /**
- * @var array
- */
- private const ARG_POSITION_NAME_NULL_TO_STRICT_STRING = ['preg_split' => ['subject'], 'preg_match' => ['subject'], 'preg_match_all' => ['subject'], 'preg_filter' => ['replacement', 'subject'], 'preg_replace' => ['replacement', 'subject'], 'preg_replace_callback' => ['subject'], 'preg_replace_callback_array' => ['subject'], 'explode' => ['string'], 'strlen' => ['string'], 'str_contains' => ['haystack', 'needle'], 'strtotime' => ['datetime'], 'str_replace' => ['subject'], 'substr_replace' => ['string', 'replace'], 'str_ireplace' => ['search', 'replace', 'subject'], 'substr' => ['string'], 'str_starts_with' => ['haystack', 'needle'], 'strtoupper' => ['string'], 'strtolower' => ['string'], 'strpos' => ['haystack', 'needle'], 'stripos' => ['haystack', 'needle'], 'json_decode' => ['json'], 'urlencode' => ['string'], 'urldecode' => ['string'], 'rawurlencode' => ['string'], 'rawurldecode' => ['string'], 'base64_encode' => ['string'], 'base64_decode' => ['string'], 'utf8_encode' => ['string'], 'utf8_decode' => ['string'], 'bin2hex' => ['string'], 'hex2bin' => ['string'], 'hexdec' => ['hex_string'], 'octdec' => ['octal_string'], 'base_convert' => ['num'], 'htmlspecialchars' => ['string'], 'htmlspecialchars_decode' => ['string'], 'html_entity_decode' => ['string'], 'htmlentities' => ['string'], 'addslashes' => ['string'], 'addcslashes' => ['string', 'characters'], 'stripslashes' => ['string'], 'stripcslashes' => ['string'], 'quotemeta' => ['string'], 'quoted_printable_decode' => ['string'], 'quoted_printable_encode' => ['string'], 'escapeshellarg' => ['arg'], 'curl_escape' => ['string'], 'curl_unescape' => ['string'], 'convert_uuencode' => ['string'], 'setcookie' => ['value', 'path', 'domain'], 'setrawcookie' => ['value', 'path', 'domain'], 'zlib_encode' => ['data'], 'gzdeflate' => ['data'], 'gzencode' => ['data'], 'gzcompress' => ['data'], 'gzwrite' => ['data'], 'gzputs' => ['data'], 'deflate_add' => ['data'], 'inflate_add' => ['data'], 'unpack' => ['format', 'string'], 'iconv_mime_encode' => ['field_name', 'field_value'], 'iconv_mime_decode' => ['string'], 'iconv' => ['from_encoding', 'to_encoding', 'string'], 'sodium_bin2hex' => ['string'], 'sodium_hex2bin' => ['string', 'ignore'], 'sodium_bin2base64' => ['string'], 'sodium_base642bin' => ['string', 'ignore'], 'mb_detect_encoding' => ['string'], 'mb_encode_mimeheader' => ['string'], 'mb_decode_mimeheader' => ['string'], 'mb_encode_numericentity' => ['string'], 'mb_decode_numericentity' => ['string'], 'transliterator_transliterate' => ['string'], 'mysqli_real_escape_string' => ['string'], 'mysqli_escape_string' => ['string'], 'pg_escape_bytea' => ['string'], 'pg_escape_literal' => ['string'], 'pg_escape_string' => ['string'], 'pg_unescape_bytea' => ['string'], 'ucfirst' => ['string'], 'lcfirst' => ['string'], 'ucwords' => ['string'], 'trim' => ['string'], 'ltrim' => ['string'], 'rtrim' => ['string'], 'chop' => ['string'], 'str_rot13' => ['string'], 'str_shuffle' => ['string'], 'substr_count' => ['haystack', 'needle'], 'strcoll' => ['string1', 'string2'], 'str_split' => ['string'], 'chunk_split' => ['string'], 'wordwrap' => ['string'], 'strrev' => ['string'], 'str_repeat' => ['string'], 'str_pad' => ['string'], 'nl2br' => ['string'], 'strip_tags' => ['string'], 'hebrev' => ['string'], 'iconv_substr' => ['string'], 'mb_strtoupper' => ['string'], 'mb_strtolower' => ['string'], 'mb_convert_case' => ['string'], 'mb_convert_kana' => ['string'], 'mb_convert_encoding' => ['string'], 'mb_scrub' => ['string'], 'mb_substr' => ['string'], 'mb_substr_count' => ['haystack', 'needle'], 'mb_str_split' => ['string'], 'mb_split' => ['pattern', 'string'], 'sodium_pad' => ['string'], 'grapheme_substr' => ['string'], 'strrpos' => ['haystack', 'needle'], 'strripos' => ['haystack', 'needle'], 'iconv_strpos' => ['haystack', 'needle'], 'iconv_strrpos' => ['haystack', 'needle'], 'mb_strpos' => ['haystack', 'needle'], 'mb_strrpos' => ['haystack', 'needle'], 'mb_stripos' => ['haystack', 'needle'], 'mb_strripos' => ['haystack', 'needle'], 'grapheme_extract' => ['haystack'], 'grapheme_strpos' => ['haystack', 'needle'], 'grapheme_strrpos' => ['haystack', 'needle'], 'grapheme_stripos' => ['haystack', 'needle'], 'grapheme_strripos' => ['haystack', 'needle'], 'strcmp' => ['string1', 'string2'], 'strncmp' => ['string1', 'string2'], 'strcasecmp' => ['string1', 'string2'], 'strncasecmp' => ['string1', 'string2'], 'strnatcmp' => ['string1', 'string2'], 'strnatcasecmp' => ['string1', 'string2'], 'substr_compare' => ['haystack', 'needle'], 'str_ends_with' => ['haystack', 'needle'], 'collator_compare' => ['string1', 'string2'], 'collator_get_sort_key' => ['string'], 'metaphone' => ['string'], 'soundex' => ['string'], 'levenshtein' => ['string1', 'string2'], 'similar_text' => ['string1', 'string2'], 'sodium_compare' => ['string1', 'string2'], 'sodium_memcmp' => ['string1', 'string2'], 'strstr' => ['haystack', 'needle'], 'strchr' => ['haystack', 'needle'], 'stristr' => ['haystack', 'needle'], 'strrchr' => ['haystack', 'needle'], 'strpbrk' => ['string', 'characters'], 'strspn' => ['string', 'characters'], 'strcspn' => ['string', 'characters'], 'strtr' => ['string'], 'strtok' => ['string'], 'str_word_count' => ['string'], 'count_chars' => ['string'], 'iconv_strlen' => ['string'], 'mb_strlen' => ['string'], 'mb_strstr' => ['haystack', 'needle'], 'mb_strrchr' => ['haystack', 'needle'], 'mb_stristr' => ['haystack', 'needle'], 'mb_strrichr' => ['haystack', 'needle'], 'mb_strcut' => ['string'], 'mb_strwidth' => ['string'], 'mb_strimwidth' => ['string', 'trim_marker'], 'grapheme_strlen' => ['string'], 'grapheme_strstr' => ['haystack', 'needle'], 'grapheme_stristr' => ['haystack', 'needle'], 'preg_quote' => ['str'], 'mb_ereg' => ['pattern', 'string'], 'mb_eregi' => ['pattern', 'string'], 'mb_ereg_replace' => ['pattern', 'replacement', 'string'], 'mb_eregi_replace' => ['pattern', 'replacement', 'string'], 'mb_ereg_replace_callback' => ['pattern', 'string'], 'mb_ereg_match' => ['pattern', 'string'], 'mb_ereg_search_init' => ['string'], 'normalizer_normalize' => ['string'], 'normalizer_is_normalized' => ['string'], 'normalizer_get_raw_decomposition' => ['string'], 'numfmt_parse' => ['string'], 'hash' => ['algo', 'data'], 'hash_hmac' => ['algo', 'data', 'key'], 'hash_update' => ['data'], 'hash_pbkdf2' => ['algo', 'password', 'salt'], 'crc32' => ['string'], 'md5' => ['string'], 'sha1' => ['string'], 'crypt' => ['string', 'salt'], 'basename' => ['path'], 'dirname' => ['path'], 'pathinfo' => ['path'], 'sscanf' => ['string'], 'fwrite' => ['data'], 'fputs' => ['data'], 'output_add_rewrite_var' => ['name', 'value'], 'parse_url' => ['url'], 'parse_str' => ['string'], 'mb_parse_str' => ['string'], 'parse_ini_string' => ['ini_string'], 'locale_accept_from_http' => ['header'], 'msgfmt_parse' => ['string'], 'msgfmt_parse_message' => ['locale', 'pattern', 'message'], 'str_getcsv' => ['string'], 'fgetcsv' => ['escape'], 'fputcsv' => ['escape'], 'password_hash' => ['password'], 'password_verify' => ['password', 'hash'], 'bcadd' => ['num1', 'num2'], 'bcsub' => ['num1', 'num2'], 'bcmul' => ['num1', 'num2'], 'bcdiv' => ['num1', 'num2'], 'bcmod' => ['num1', 'num2'], 'bcpow' => ['num', 'exponent'], 'bcpowmod' => ['num', 'exponent', 'modulus'], 'bcsqrt' => ['num'], 'bccomp' => ['num1', 'num2'], 'simplexml_load_string' => ['data'], 'xml_parse' => ['data'], 'xml_parse_into_struct' => ['data'], 'xml_parser_create_ns' => ['separator'], 'xmlwriter_set_indent_string' => ['indentation'], 'xmlwriter_write_attribute' => ['name', 'value'], 'xmlwriter_write_attribute_ns' => ['value'], 'xmlwriter_write_pi' => ['target', 'content'], 'xmlwriter_write_cdata' => ['content'], 'xmlwriter_text' => ['content'], 'xmlwriter_write_raw' => ['content'], 'xmlwriter_write_comment' => ['content'], 'xmlwriter_write_dtd' => ['name'], 'xmlwriter_write_dtd_element' => ['name', 'content'], 'xmlwriter_write_dtd_attlist' => ['name', 'content'], 'xmlwriter_write_dtd_entity' => ['name', 'content'], 'sodium_crypto_aead_aes256gcm_encrypt' => ['message', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_aes256gcm_decrypt' => ['ciphertext', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_chacha20poly1305_encrypt' => ['message', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_chacha20poly1305_decrypt' => ['ciphertext', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_chacha20poly1305_ietf_encrypt' => ['message', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_chacha20poly1305_ietf_decrypt' => ['ciphertext', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_xchacha20poly1305_ietf_encrypt' => ['message', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_xchacha20poly1305_ietf_decrypt' => ['ciphertext', 'additional_data', 'nonce', 'key'], 'sodium_crypto_auth' => ['message', 'key'], 'sodium_crypto_auth_verify' => ['mac', 'message', 'key'], 'sodium_crypto_box' => ['message', 'nonce', 'key_pair'], 'sodium_crypto_box_seal' => ['message', 'public_key'], 'sodium_crypto_generichash' => ['message'], 'sodium_crypto_generichash_update' => ['message'], 'sodium_crypto_secretbox' => ['message', 'nonce', 'key'], 'sodium_crypto_secretstream_xchacha20poly1305_push' => ['message'], 'sodium_crypto_secretstream_xchacha20poly1305_pull' => ['ciphertext'], 'sodium_crypto_shorthash' => ['message', 'key'], 'sodium_crypto_sign' => ['message', 'secret_key'], 'sodium_crypto_sign_detached' => ['message'], 'sodium_crypto_sign_open' => ['signed_message', 'public_key'], 'sodium_crypto_sign_verify_detached' => ['signature', 'message', 'public_key'], 'sodium_crypto_stream_xor' => ['message', 'nonce', 'key'], 'sodium_crypto_stream_xchacha20_xor' => ['message', 'nonce', 'key'], 'imagechar' => ['char'], 'imagecharup' => ['char'], 'imageftbbox' => ['string'], 'imagefttext' => ['text'], 'imagestring' => ['string'], 'imagestringup' => ['string'], 'imagettfbbox' => ['string'], 'imagettftext' => ['text'], 'pspell_add_to_personal' => ['word'], 'pspell_add_to_session' => ['word'], 'pspell_check' => ['word'], 'pspell_config_create' => ['language', 'spelling', 'jargon', 'encoding'], 'pspell_new' => ['spelling', 'jargon', 'encoding'], 'pspell_new_personal' => ['spelling', 'jargon', 'encoding'], 'pspell_store_replacement' => ['correct'], 'pspell_suggest' => ['word'], 'stream_get_line' => ['ending'], 'stream_socket_sendto' => ['data'], 'socket_sendto' => ['data'], 'socket_write' => ['data'], 'socket_send' => ['data'], 'mail' => ['to', 'subject', 'message'], 'mb_send_mail' => ['to', 'subject', 'message'], 'ctype_alnum' => ['text'], 'ctype_alpha' => ['text'], 'ctype_cntrl' => ['text'], 'ctype_digit' => ['text'], 'ctype_graph' => ['text'], 'ctype_lower' => ['text'], 'ctype_print' => ['text'], 'ctype_punct' => ['text'], 'ctype_space' => ['text'], 'ctype_upper' => ['text'], 'ctype_xdigit' => ['text'], 'uniqid' => ['prefix']];
/**
* @readonly
* @var \Rector\Core\Reflection\ReflectionResolver
@@ -54,6 +49,10 @@ final class NullToStrictStringFuncCallArgRector extends AbstractScopeAwareRector
* @var \Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer
*/
private $propertyFetchAnalyzer;
+ /**
+ * @var array
+ */
+ private const ARG_POSITION_NAME_NULL_TO_STRICT_STRING = ['preg_split' => ['subject'], 'preg_match' => ['subject'], 'preg_match_all' => ['subject'], 'preg_filter' => ['replacement', 'subject'], 'preg_replace' => ['replacement', 'subject'], 'preg_replace_callback' => ['subject'], 'preg_replace_callback_array' => ['subject'], 'explode' => ['string'], 'strlen' => ['string'], 'str_contains' => ['haystack', 'needle'], 'strtotime' => ['datetime'], 'str_replace' => ['subject'], 'substr_replace' => ['string', 'replace'], 'str_ireplace' => ['search', 'replace', 'subject'], 'substr' => ['string'], 'str_starts_with' => ['haystack', 'needle'], 'strtoupper' => ['string'], 'strtolower' => ['string'], 'strpos' => ['haystack', 'needle'], 'stripos' => ['haystack', 'needle'], 'json_decode' => ['json'], 'urlencode' => ['string'], 'urldecode' => ['string'], 'rawurlencode' => ['string'], 'rawurldecode' => ['string'], 'base64_encode' => ['string'], 'base64_decode' => ['string'], 'utf8_encode' => ['string'], 'utf8_decode' => ['string'], 'bin2hex' => ['string'], 'hex2bin' => ['string'], 'hexdec' => ['hex_string'], 'octdec' => ['octal_string'], 'base_convert' => ['num'], 'htmlspecialchars' => ['string'], 'htmlspecialchars_decode' => ['string'], 'html_entity_decode' => ['string'], 'htmlentities' => ['string'], 'addslashes' => ['string'], 'addcslashes' => ['string', 'characters'], 'stripslashes' => ['string'], 'stripcslashes' => ['string'], 'quotemeta' => ['string'], 'quoted_printable_decode' => ['string'], 'quoted_printable_encode' => ['string'], 'escapeshellarg' => ['arg'], 'curl_escape' => ['string'], 'curl_unescape' => ['string'], 'convert_uuencode' => ['string'], 'setcookie' => ['value', 'path', 'domain'], 'setrawcookie' => ['value', 'path', 'domain'], 'zlib_encode' => ['data'], 'gzdeflate' => ['data'], 'gzencode' => ['data'], 'gzcompress' => ['data'], 'gzwrite' => ['data'], 'gzputs' => ['data'], 'deflate_add' => ['data'], 'inflate_add' => ['data'], 'unpack' => ['format', 'string'], 'iconv_mime_encode' => ['field_name', 'field_value'], 'iconv_mime_decode' => ['string'], 'iconv' => ['from_encoding', 'to_encoding', 'string'], 'sodium_bin2hex' => ['string'], 'sodium_hex2bin' => ['string', 'ignore'], 'sodium_bin2base64' => ['string'], 'sodium_base642bin' => ['string', 'ignore'], 'mb_detect_encoding' => ['string'], 'mb_encode_mimeheader' => ['string'], 'mb_decode_mimeheader' => ['string'], 'mb_encode_numericentity' => ['string'], 'mb_decode_numericentity' => ['string'], 'transliterator_transliterate' => ['string'], 'mysqli_real_escape_string' => ['string'], 'mysqli_escape_string' => ['string'], 'pg_escape_bytea' => ['string'], 'pg_escape_literal' => ['string'], 'pg_escape_string' => ['string'], 'pg_unescape_bytea' => ['string'], 'ucfirst' => ['string'], 'lcfirst' => ['string'], 'ucwords' => ['string'], 'trim' => ['string'], 'ltrim' => ['string'], 'rtrim' => ['string'], 'chop' => ['string'], 'str_rot13' => ['string'], 'str_shuffle' => ['string'], 'substr_count' => ['haystack', 'needle'], 'strcoll' => ['string1', 'string2'], 'str_split' => ['string'], 'chunk_split' => ['string'], 'wordwrap' => ['string'], 'strrev' => ['string'], 'str_repeat' => ['string'], 'str_pad' => ['string'], 'nl2br' => ['string'], 'strip_tags' => ['string'], 'hebrev' => ['string'], 'iconv_substr' => ['string'], 'mb_strtoupper' => ['string'], 'mb_strtolower' => ['string'], 'mb_convert_case' => ['string'], 'mb_convert_kana' => ['string'], 'mb_convert_encoding' => ['string'], 'mb_scrub' => ['string'], 'mb_substr' => ['string'], 'mb_substr_count' => ['haystack', 'needle'], 'mb_str_split' => ['string'], 'mb_split' => ['pattern', 'string'], 'sodium_pad' => ['string'], 'grapheme_substr' => ['string'], 'strrpos' => ['haystack', 'needle'], 'strripos' => ['haystack', 'needle'], 'iconv_strpos' => ['haystack', 'needle'], 'iconv_strrpos' => ['haystack', 'needle'], 'mb_strpos' => ['haystack', 'needle'], 'mb_strrpos' => ['haystack', 'needle'], 'mb_stripos' => ['haystack', 'needle'], 'mb_strripos' => ['haystack', 'needle'], 'grapheme_extract' => ['haystack'], 'grapheme_strpos' => ['haystack', 'needle'], 'grapheme_strrpos' => ['haystack', 'needle'], 'grapheme_stripos' => ['haystack', 'needle'], 'grapheme_strripos' => ['haystack', 'needle'], 'strcmp' => ['string1', 'string2'], 'strncmp' => ['string1', 'string2'], 'strcasecmp' => ['string1', 'string2'], 'strncasecmp' => ['string1', 'string2'], 'strnatcmp' => ['string1', 'string2'], 'strnatcasecmp' => ['string1', 'string2'], 'substr_compare' => ['haystack', 'needle'], 'str_ends_with' => ['haystack', 'needle'], 'collator_compare' => ['string1', 'string2'], 'collator_get_sort_key' => ['string'], 'metaphone' => ['string'], 'soundex' => ['string'], 'levenshtein' => ['string1', 'string2'], 'similar_text' => ['string1', 'string2'], 'sodium_compare' => ['string1', 'string2'], 'sodium_memcmp' => ['string1', 'string2'], 'strstr' => ['haystack', 'needle'], 'strchr' => ['haystack', 'needle'], 'stristr' => ['haystack', 'needle'], 'strrchr' => ['haystack', 'needle'], 'strpbrk' => ['string', 'characters'], 'strspn' => ['string', 'characters'], 'strcspn' => ['string', 'characters'], 'strtr' => ['string'], 'strtok' => ['string'], 'str_word_count' => ['string'], 'count_chars' => ['string'], 'iconv_strlen' => ['string'], 'mb_strlen' => ['string'], 'mb_strstr' => ['haystack', 'needle'], 'mb_strrchr' => ['haystack', 'needle'], 'mb_stristr' => ['haystack', 'needle'], 'mb_strrichr' => ['haystack', 'needle'], 'mb_strcut' => ['string'], 'mb_strwidth' => ['string'], 'mb_strimwidth' => ['string', 'trim_marker'], 'grapheme_strlen' => ['string'], 'grapheme_strstr' => ['haystack', 'needle'], 'grapheme_stristr' => ['haystack', 'needle'], 'preg_quote' => ['str'], 'mb_ereg' => ['pattern', 'string'], 'mb_eregi' => ['pattern', 'string'], 'mb_ereg_replace' => ['pattern', 'replacement', 'string'], 'mb_eregi_replace' => ['pattern', 'replacement', 'string'], 'mb_ereg_replace_callback' => ['pattern', 'string'], 'mb_ereg_match' => ['pattern', 'string'], 'mb_ereg_search_init' => ['string'], 'normalizer_normalize' => ['string'], 'normalizer_is_normalized' => ['string'], 'normalizer_get_raw_decomposition' => ['string'], 'numfmt_parse' => ['string'], 'hash' => ['algo', 'data'], 'hash_hmac' => ['algo', 'data', 'key'], 'hash_update' => ['data'], 'hash_pbkdf2' => ['algo', 'password', 'salt'], 'crc32' => ['string'], 'md5' => ['string'], 'sha1' => ['string'], 'crypt' => ['string', 'salt'], 'basename' => ['path'], 'dirname' => ['path'], 'pathinfo' => ['path'], 'sscanf' => ['string'], 'fwrite' => ['data'], 'fputs' => ['data'], 'output_add_rewrite_var' => ['name', 'value'], 'parse_url' => ['url'], 'parse_str' => ['string'], 'mb_parse_str' => ['string'], 'parse_ini_string' => ['ini_string'], 'locale_accept_from_http' => ['header'], 'msgfmt_parse' => ['string'], 'msgfmt_parse_message' => ['locale', 'pattern', 'message'], 'str_getcsv' => ['string'], 'fgetcsv' => ['escape'], 'fputcsv' => ['escape'], 'password_hash' => ['password'], 'password_verify' => ['password', 'hash'], 'bcadd' => ['num1', 'num2'], 'bcsub' => ['num1', 'num2'], 'bcmul' => ['num1', 'num2'], 'bcdiv' => ['num1', 'num2'], 'bcmod' => ['num1', 'num2'], 'bcpow' => ['num', 'exponent'], 'bcpowmod' => ['num', 'exponent', 'modulus'], 'bcsqrt' => ['num'], 'bccomp' => ['num1', 'num2'], 'simplexml_load_string' => ['data'], 'xml_parse' => ['data'], 'xml_parse_into_struct' => ['data'], 'xml_parser_create_ns' => ['separator'], 'xmlwriter_set_indent_string' => ['indentation'], 'xmlwriter_write_attribute' => ['name', 'value'], 'xmlwriter_write_attribute_ns' => ['value'], 'xmlwriter_write_pi' => ['target', 'content'], 'xmlwriter_write_cdata' => ['content'], 'xmlwriter_text' => ['content'], 'xmlwriter_write_raw' => ['content'], 'xmlwriter_write_comment' => ['content'], 'xmlwriter_write_dtd' => ['name'], 'xmlwriter_write_dtd_element' => ['name', 'content'], 'xmlwriter_write_dtd_attlist' => ['name', 'content'], 'xmlwriter_write_dtd_entity' => ['name', 'content'], 'sodium_crypto_aead_aes256gcm_encrypt' => ['message', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_aes256gcm_decrypt' => ['ciphertext', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_chacha20poly1305_encrypt' => ['message', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_chacha20poly1305_decrypt' => ['ciphertext', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_chacha20poly1305_ietf_encrypt' => ['message', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_chacha20poly1305_ietf_decrypt' => ['ciphertext', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_xchacha20poly1305_ietf_encrypt' => ['message', 'additional_data', 'nonce', 'key'], 'sodium_crypto_aead_xchacha20poly1305_ietf_decrypt' => ['ciphertext', 'additional_data', 'nonce', 'key'], 'sodium_crypto_auth' => ['message', 'key'], 'sodium_crypto_auth_verify' => ['mac', 'message', 'key'], 'sodium_crypto_box' => ['message', 'nonce', 'key_pair'], 'sodium_crypto_box_seal' => ['message', 'public_key'], 'sodium_crypto_generichash' => ['message'], 'sodium_crypto_generichash_update' => ['message'], 'sodium_crypto_secretbox' => ['message', 'nonce', 'key'], 'sodium_crypto_secretstream_xchacha20poly1305_push' => ['message'], 'sodium_crypto_secretstream_xchacha20poly1305_pull' => ['ciphertext'], 'sodium_crypto_shorthash' => ['message', 'key'], 'sodium_crypto_sign' => ['message', 'secret_key'], 'sodium_crypto_sign_detached' => ['message'], 'sodium_crypto_sign_open' => ['signed_message', 'public_key'], 'sodium_crypto_sign_verify_detached' => ['signature', 'message', 'public_key'], 'sodium_crypto_stream_xor' => ['message', 'nonce', 'key'], 'sodium_crypto_stream_xchacha20_xor' => ['message', 'nonce', 'key'], 'imagechar' => ['char'], 'imagecharup' => ['char'], 'imageftbbox' => ['string'], 'imagefttext' => ['text'], 'imagestring' => ['string'], 'imagestringup' => ['string'], 'imagettfbbox' => ['string'], 'imagettftext' => ['text'], 'pspell_add_to_personal' => ['word'], 'pspell_add_to_session' => ['word'], 'pspell_check' => ['word'], 'pspell_config_create' => ['language', 'spelling', 'jargon', 'encoding'], 'pspell_new' => ['spelling', 'jargon', 'encoding'], 'pspell_new_personal' => ['spelling', 'jargon', 'encoding'], 'pspell_store_replacement' => ['correct'], 'pspell_suggest' => ['word'], 'stream_get_line' => ['ending'], 'stream_socket_sendto' => ['data'], 'socket_sendto' => ['data'], 'socket_write' => ['data'], 'socket_send' => ['data'], 'mail' => ['to', 'subject', 'message'], 'mb_send_mail' => ['to', 'subject', 'message'], 'ctype_alnum' => ['text'], 'ctype_alpha' => ['text'], 'ctype_cntrl' => ['text'], 'ctype_digit' => ['text'], 'ctype_graph' => ['text'], 'ctype_lower' => ['text'], 'ctype_print' => ['text'], 'ctype_punct' => ['text'], 'ctype_space' => ['text'], 'ctype_upper' => ['text'], 'ctype_xdigit' => ['text'], 'uniqid' => ['prefix']];
public function __construct(ReflectionResolver $reflectionResolver, ArgsAnalyzer $argsAnalyzer, PropertyFetchAnalyzer $propertyFetchAnalyzer)
{
$this->reflectionResolver = $reflectionResolver;
@@ -172,9 +171,6 @@ private function processNullToStrictStringOnNodePosition(FuncCall $funcCall, arr
if ($this->shouldSkipTrait($argValue, $type, $isTrait)) {
return null;
}
- if ($this->isCastedReassign($argValue)) {
- return null;
- }
$args[$position]->value = new CastString_($argValue);
$funcCall->args = $args;
return $funcCall;
@@ -195,18 +191,6 @@ private function shouldSkipTrait(Expr $expr, Type $type, bool $isTrait) : bool
}
return \true;
}
- private function isCastedReassign(Expr $expr) : bool
- {
- return (bool) $this->betterNodeFinder->findFirstPrevious($expr, function (Node $subNode) use($expr) : bool {
- if (!$subNode instanceof Assign) {
- return \false;
- }
- if (!$this->nodeComparator->areNodesEqual($subNode->var, $expr)) {
- return \false;
- }
- return $subNode->expr instanceof CastString_;
- });
- }
private function isAnErrorTypeFromParentScope(Expr $expr, Scope $scope) : bool
{
$parentScope = $scope->getParentScope();
diff --git a/rules/Php81/Rector/FuncCall/Php81ResourceReturnToObjectRector.php b/rules/Php81/Rector/FuncCall/Php81ResourceReturnToObjectRector.php
index a12fa67420b3..ffe04be60ec3 100644
--- a/rules/Php81/Rector/FuncCall/Php81ResourceReturnToObjectRector.php
+++ b/rules/Php81/Rector/FuncCall/Php81ResourceReturnToObjectRector.php
@@ -19,6 +19,11 @@
*/
final class Php81ResourceReturnToObjectRector extends AbstractRector implements MinPhpVersionInterface
{
+ /**
+ * @readonly
+ * @var \Rector\Php80\NodeManipulator\ResourceReturnToObject
+ */
+ private $resourceReturnToObject;
/**
* @var array
*/
@@ -47,11 +52,6 @@ final class Php81ResourceReturnToObjectRector extends AbstractRector implements
'pg_execute' => 'PgSql\\Result',
'pg_lo_open' => 'PgSql\\Lob',
];
- /**
- * @readonly
- * @var \Rector\Php80\NodeManipulator\ResourceReturnToObject
- */
- private $resourceReturnToObject;
public function __construct(ResourceReturnToObject $resourceReturnToObject)
{
$this->resourceReturnToObject = $resourceReturnToObject;
diff --git a/rules/Php81/Rector/Property/ReadOnlyPropertyRector.php b/rules/Php81/Rector/Property/ReadOnlyPropertyRector.php
index 7e1baadbb4f6..e7aba19205f5 100644
--- a/rules/Php81/Rector/Property/ReadOnlyPropertyRector.php
+++ b/rules/Php81/Rector/Property/ReadOnlyPropertyRector.php
@@ -6,11 +6,11 @@
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
+use PhpParser\Node\Expr\Clone_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use PhpParser\NodeTraverser;
@@ -106,6 +106,13 @@ public function getNodeTypes() : array
public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
$hasChanged = \false;
+ if ($node->isReadonly()) {
+ return null;
+ }
+ // skip "clone $this" cases, as can create unexpected write to local constructor property
+ if ($this->hasCloneThis($node)) {
+ return null;
+ }
foreach ($node->getMethods() as $classMethod) {
foreach ($classMethod->params as $param) {
$justChanged = $this->refactorParam($node, $classMethod, $param, $scope);
@@ -130,17 +137,6 @@ public function provideMinPhpVersion() : int
{
return PhpVersionFeature::READONLY_PROPERTY;
}
- /**
- * @param \PhpParser\Node\Stmt\Property|\PhpParser\Node\Param $node
- */
- private function shouldSkipInReadonlyClass($node) : bool
- {
- $class = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$class instanceof Class_) {
- return \true;
- }
- return $class->isReadonly();
- }
private function refactorProperty(Class_ $class, Property $property, Scope $scope) : ?Property
{
// 1. is property read-only?
@@ -165,9 +161,6 @@ private function refactorProperty(Class_ $class, Property $property, Scope $scop
if ($this->propertyFetchAssignManipulator->isAssignedMultipleTimesInConstructor($class, $property)) {
return null;
}
- if ($this->shouldSkipInReadonlyClass($property)) {
- return null;
- }
$this->visibilityManipulator->makeReadonly($property);
$attributeGroups = $property->attrGroups;
if ($attributeGroups !== []) {
@@ -193,22 +186,15 @@ private function refactorParam(Class_ $class, ClassMethod $classMethod, Param $p
if ($this->paramAnalyzer->isParamReassign($classMethod, $param)) {
return null;
}
- if ($this->isPromotedPropertyAssigned($param)) {
- return null;
- }
- if ($this->shouldSkipInReadonlyClass($param)) {
+ if ($this->isPromotedPropertyAssigned($class, $param)) {
return null;
}
$this->visibilityManipulator->makeReadonly($param);
return $param;
}
- private function isPromotedPropertyAssigned(Param $param) : bool
+ private function isPromotedPropertyAssigned(Class_ $class, Param $param) : bool
{
- $classLike = $this->betterNodeFinder->findParentType($param, ClassLike::class);
- if (!$classLike instanceof Class_) {
- return \false;
- }
- $constructClassMethod = $classLike->getMethod(MethodName::CONSTRUCT);
+ $constructClassMethod = $class->getMethod(MethodName::CONSTRUCT);
if (!$constructClassMethod instanceof ClassMethod) {
return \false;
}
@@ -216,10 +202,12 @@ private function isPromotedPropertyAssigned(Param $param) : bool
return \false;
}
$propertyFetch = new PropertyFetch(new Variable('this'), $this->getName($param));
- $stmts = $classLike->stmts;
$isAssigned = \false;
- $this->traverseNodesWithCallable($stmts, function (Node $node) use($propertyFetch, &$isAssigned) : ?int {
- if ($node instanceof Assign && $this->nodeComparator->areNodesEqual($propertyFetch, $node->var)) {
+ $this->traverseNodesWithCallable($class->stmts, function (Node $node) use($propertyFetch, &$isAssigned) : ?int {
+ if (!$node instanceof Assign) {
+ return null;
+ }
+ if ($this->nodeComparator->areNodesEqual($propertyFetch, $node->var)) {
$isAssigned = \true;
return NodeTraverser::STOP_TRAVERSAL;
}
@@ -227,4 +215,16 @@ private function isPromotedPropertyAssigned(Param $param) : bool
});
return $isAssigned;
}
+ private function hasCloneThis(Class_ $class) : bool
+ {
+ return (bool) $this->betterNodeFinder->findFirst($class, function (Node $node) : bool {
+ if (!$node instanceof Clone_) {
+ return \false;
+ }
+ if (!$node->expr instanceof Variable) {
+ return \false;
+ }
+ return $this->isName($node->expr, 'this');
+ });
+ }
}
diff --git a/rules/Php82/Rector/Class_/ReadOnlyClassRector.php b/rules/Php82/Rector/Class_/ReadOnlyClassRector.php
index 32532969015d..d9c704af3ecf 100644
--- a/rules/Php82/Rector/Class_/ReadOnlyClassRector.php
+++ b/rules/Php82/Rector/Class_/ReadOnlyClassRector.php
@@ -96,8 +96,6 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
return null;
}
$this->visibilityManipulator->makeReadonly($node);
- // invoke reprint with correct readonly newline
- $node->setAttribute(AttributeKey::ORIGINAL_NODE, null);
$constructClassMethod = $node->getMethod(MethodName::CONSTRUCT);
if ($constructClassMethod instanceof ClassMethod) {
foreach ($constructClassMethod->getParams() as $param) {
@@ -107,6 +105,10 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
foreach ($node->getProperties() as $property) {
$this->visibilityManipulator->removeReadonly($property);
}
+ if ($node->attrGroups !== []) {
+ // invoke reprint with correct readonly newline
+ $node->setAttribute(AttributeKey::ORIGINAL_NODE, null);
+ }
return $node;
}
public function provideMinPhpVersion() : int
diff --git a/rules/Php82/Rector/Param/AddSensitiveParameterAttributeRector.php b/rules/Php82/Rector/Param/AddSensitiveParameterAttributeRector.php
new file mode 100644
index 000000000000..249ea66a18d0
--- /dev/null
+++ b/rules/Php82/Rector/Param/AddSensitiveParameterAttributeRector.php
@@ -0,0 +1,87 @@
+phpAttributeAnalyzer = $phpAttributeAnalyzer;
+ }
+ /**
+ * @param mixed[] $configuration
+ */
+ public function configure(array $configuration) : void
+ {
+ Assert::allString($configuration[self::SENSITIVE_PARAMETERS] ?? []);
+ $this->sensitiveParameters = (array) ($configuration[self::SENSITIVE_PARAMETERS] ?? []);
+ }
+ public function getNodeTypes() : array
+ {
+ return [Param::class];
+ }
+ /**
+ * @param Node\Param $node
+ */
+ public function refactor(Node $node) : ?Param
+ {
+ if (!$this->isNames($node, $this->sensitiveParameters)) {
+ return null;
+ }
+ if ($this->phpAttributeAnalyzer->hasPhpAttribute($node, 'SensitiveParameter')) {
+ return null;
+ }
+ $node->attrGroups[] = new AttributeGroup([new Attribute(new FullyQualified('SensitiveParameter'))]);
+ return $node;
+ }
+ public function getRuleDefinition() : RuleDefinition
+ {
+ return new RuleDefinition('Add SensitiveParameter attribute to method and function configured parameters', [new ConfiguredCodeSample(<<<'CODE_SAMPLE'
+class SomeClass
+{
+ public function run(string $password)
+ {
+ }
+}
+CODE_SAMPLE
+, <<<'CODE_SAMPLE'
+class SomeClass
+{
+ public function run(#[\SensitiveParameter] string $password)
+ {
+ }
+}
+CODE_SAMPLE
+, [self::SENSITIVE_PARAMETERS => ['password']])]);
+ }
+ public function provideMinPhpVersion() : int
+ {
+ return PhpVersionFeature::SENSITIVE_PARAMETER_ATTRIBUTE;
+ }
+}
diff --git a/rules/Privatization/Guard/ParentPropertyLookupGuard.php b/rules/Privatization/Guard/ParentPropertyLookupGuard.php
index 618c4573fa74..d6a871f5b941 100644
--- a/rules/Privatization/Guard/ParentPropertyLookupGuard.php
+++ b/rules/Privatization/Guard/ParentPropertyLookupGuard.php
@@ -14,7 +14,7 @@
use Rector\Core\Enum\ObjectReference;
use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
use Rector\Core\NodeManipulator\PropertyManipulator;
-use Rector\Core\PhpParser\AstResolver;
+use Rector\Core\PhpParser\ClassLikeAstResolver;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\Util\Reflection\PrivatesAccessor;
use Rector\NodeNameResolver\NodeNameResolver;
@@ -37,9 +37,9 @@ final class ParentPropertyLookupGuard
private $propertyFetchAnalyzer;
/**
* @readonly
- * @var \Rector\Core\PhpParser\AstResolver
+ * @var \Rector\Core\PhpParser\ClassLikeAstResolver
*/
- private $astResolver;
+ private $classLikeAstResolver;
/**
* @readonly
* @var \Rector\Core\NodeManipulator\PropertyManipulator
@@ -50,12 +50,12 @@ final class ParentPropertyLookupGuard
* @var \Rector\Core\Util\Reflection\PrivatesAccessor
*/
private $privatesAccessor;
- public function __construct(BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver, PropertyFetchAnalyzer $propertyFetchAnalyzer, AstResolver $astResolver, PropertyManipulator $propertyManipulator, PrivatesAccessor $privatesAccessor)
+ public function __construct(BetterNodeFinder $betterNodeFinder, NodeNameResolver $nodeNameResolver, PropertyFetchAnalyzer $propertyFetchAnalyzer, ClassLikeAstResolver $classLikeAstResolver, PropertyManipulator $propertyManipulator, PrivatesAccessor $privatesAccessor)
{
$this->betterNodeFinder = $betterNodeFinder;
$this->nodeNameResolver = $nodeNameResolver;
$this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
- $this->astResolver = $astResolver;
+ $this->classLikeAstResolver = $classLikeAstResolver;
$this->propertyManipulator = $propertyManipulator;
$this->privatesAccessor = $privatesAccessor;
}
@@ -87,7 +87,7 @@ public function isLegal(Property $property, ?ClassReflection $classReflection) :
}
private function isFoundInParentClassMethods(ClassReflection $parentClassReflection, string $propertyName, string $className) : bool
{
- $classLike = $this->astResolver->resolveClassFromName($parentClassReflection->getName());
+ $classLike = $this->classLikeAstResolver->resolveClassFromClassReflection($parentClassReflection);
if (!$classLike instanceof Class_) {
return \false;
}
diff --git a/rules/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php b/rules/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php
index 64d341f4a493..a7043dedc088 100644
--- a/rules/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php
+++ b/rules/Privatization/Rector/ClassMethod/PrivatizeFinalClassMethodRector.php
@@ -8,8 +8,7 @@
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
-use Rector\Core\Rector\AbstractRector;
-use Rector\NodeTypeResolver\Node\AttributeKey;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Privatization\NodeManipulator\VisibilityManipulator;
use Rector\Privatization\VisibilityGuard\ClassMethodVisibilityGuard;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -17,7 +16,7 @@
/**
* @see \Rector\Tests\Privatization\Rector\ClassMethod\PrivatizeFinalClassMethodRector\PrivatizeFinalClassMethodRectorTest
*/
-final class PrivatizeFinalClassMethodRector extends AbstractRector
+final class PrivatizeFinalClassMethodRector extends AbstractScopeAwareRector
{
/**
* @readonly
@@ -64,16 +63,12 @@ public function getNodeTypes() : array
/**
* @param Class_ $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
if (!$node->isFinal()) {
return null;
}
- $classScope = $node->getAttribute(AttributeKey::SCOPE);
- if (!$classScope instanceof Scope) {
- return null;
- }
- $classReflection = $classScope->getClassReflection();
+ $classReflection = $scope->getClassReflection();
if (!$classReflection instanceof ClassReflection) {
return null;
}
diff --git a/rules/Privatization/Rector/Class_/ChangeGlobalVariablesToPropertiesRector.php b/rules/Privatization/Rector/Class_/ChangeGlobalVariablesToPropertiesRector.php
deleted file mode 100644
index ec25368f2ffd..000000000000
--- a/rules/Privatization/Rector/Class_/ChangeGlobalVariablesToPropertiesRector.php
+++ /dev/null
@@ -1,155 +0,0 @@
-variable = 5;
- }
-
- public function run()
- {
- var_dump($this->variable);
- }
-}
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [Class_::class];
- }
- /**
- * @param Class_ $node
- */
- public function refactor(Node $node) : ?Node
- {
- foreach ($node->getMethods() as $classMethod) {
- $this->collectGlobalVariableNamesAndRefactorToPropertyFetch($node, $classMethod);
- }
- if ($this->globalVariableNames === []) {
- return null;
- }
- // @todo find ideal property position
- $globalProperties = [];
- foreach ($this->globalVariableNames as $globalVariableName) {
- $globalProperties[] = new Property(Class_::MODIFIER_PRIVATE, [new PropertyProperty($globalVariableName)]);
- }
- \array_splice($node->stmts, 0, 0, $globalProperties);
- return $node;
- }
- private function collectGlobalVariableNamesAndRefactorToPropertyFetch(Class_ $class, ClassMethod $classMethod) : void
- {
- $this->globalVariableNames = [];
- $this->traverseNodesWithCallable($classMethod, function (Node $node) use($class) {
- if ($node instanceof Global_) {
- $this->refactorGlobal($class, $node);
- return NodeTraverser::DONT_TRAVERSE_CHILDREN;
- }
- if ($node instanceof Variable) {
- return $this->refactorGlobalVariable($node);
- }
- return null;
- });
- }
- private function refactorGlobal(Class_ $class, Global_ $global) : void
- {
- foreach ($global->vars as $var) {
- $varName = $this->getName($var);
- if ($varName === null) {
- return;
- }
- if ($this->isReadOnly($class, $varName)) {
- return;
- }
- $this->globalVariableNames[] = $varName;
- }
- $this->removeNode($global);
- }
- private function refactorGlobalVariable(Variable $variable) : ?PropertyFetch
- {
- if (!$this->isNames($variable, $this->globalVariableNames)) {
- return null;
- }
- // replace with property fetch
- $variableName = $this->getName($variable);
- if ($variableName === null) {
- return null;
- }
- return $this->nodeFactory->createPropertyFetch('this', $variableName);
- }
- private function isReadOnly(Class_ $class, string $globalVariableName) : bool
- {
- /** @var ClassMethod[] $classMethods */
- $classMethods = $this->betterNodeFinder->findInstanceOf($class, ClassMethod::class);
- foreach ($classMethods as $classMethod) {
- $isReAssign = (bool) $this->betterNodeFinder->findFirst((array) $classMethod->stmts, function (Node $node) use($globalVariableName) : bool {
- if (!$node instanceof Assign) {
- return \false;
- }
- if ($node->var instanceof Variable) {
- return $this->nodeNameResolver->isName($node->var, $globalVariableName);
- }
- if ($node->var instanceof PropertyFetch) {
- return $this->nodeNameResolver->isName($node->var, $globalVariableName);
- }
- return \false;
- });
- if ($isReAssign) {
- return \false;
- }
- }
- return \true;
- }
-}
diff --git a/rules/Privatization/Rector/MethodCall/PrivatizeLocalGetterToPropertyRector.php b/rules/Privatization/Rector/MethodCall/PrivatizeLocalGetterToPropertyRector.php
index 8410291ab904..82664a4b75ee 100644
--- a/rules/Privatization/Rector/MethodCall/PrivatizeLocalGetterToPropertyRector.php
+++ b/rules/Privatization/Rector/MethodCall/PrivatizeLocalGetterToPropertyRector.php
@@ -59,32 +59,44 @@ private function getSome()
*/
public function getNodeTypes() : array
{
- return [MethodCall::class];
+ return [Class_::class];
}
/**
- * @param MethodCall $node
+ * @param Class_ $node
*/
public function refactor(Node $node) : ?Node
{
- if (!$node->var instanceof Variable) {
- return null;
- }
- if (!$this->nodeNameResolver->isName($node->var, 'this')) {
- return null;
- }
- $classLike = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$classLike instanceof Class_) {
- return null;
- }
- $methodName = $this->getName($node->name);
- if ($methodName === null) {
- return null;
- }
- $classMethod = $classLike->getMethod($methodName);
- if (!$classMethod instanceof ClassMethod) {
- return null;
+ $class = $node;
+ $hasChanged = \false;
+ $this->traverseNodesWithCallable($node, function (Node $node) use($class, &$hasChanged) : ?PropertyFetch {
+ if (!$node instanceof MethodCall) {
+ return null;
+ }
+ if (!$node->var instanceof Variable) {
+ return null;
+ }
+ if (!$this->nodeNameResolver->isName($node->var, 'this')) {
+ return null;
+ }
+ $methodName = $this->getName($node->name);
+ if ($methodName === null) {
+ return null;
+ }
+ $classMethod = $class->getMethod($methodName);
+ if (!$classMethod instanceof ClassMethod) {
+ return null;
+ }
+ $propertyFetch = $this->matchLocalPropertyFetchInGetterMethod($classMethod);
+ if (!$propertyFetch instanceof PropertyFetch) {
+ return null;
+ }
+ $hasChanged = \true;
+ return $propertyFetch;
+ });
+ if ($hasChanged) {
+ return $node;
}
- return $this->matchLocalPropertyFetchInGetterMethod($classMethod);
+ return null;
}
private function matchLocalPropertyFetchInGetterMethod(ClassMethod $classMethod) : ?PropertyFetch
{
diff --git a/rules/Privatization/TypeManipulator/TypeNormalizer.php b/rules/Privatization/TypeManipulator/TypeNormalizer.php
index 43bf2bfc9507..629e27152210 100644
--- a/rules/Privatization/TypeManipulator/TypeNormalizer.php
+++ b/rules/Privatization/TypeManipulator/TypeNormalizer.php
@@ -5,6 +5,12 @@
use PHPStan\Type\BooleanType;
use PHPStan\Type\Constant\ConstantBooleanType;
+use PHPStan\Type\Constant\ConstantFloatType;
+use PHPStan\Type\Constant\ConstantIntegerType;
+use PHPStan\Type\Constant\ConstantStringType;
+use PHPStan\Type\FloatType;
+use PHPStan\Type\IntegerType;
+use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeTraverser;
final class TypeNormalizer
@@ -19,6 +25,15 @@ public function generalizeConstantBoolTypes(Type $type) : Type
if ($type instanceof ConstantBooleanType) {
return new BooleanType();
}
+ if ($type instanceof ConstantStringType) {
+ return new StringType();
+ }
+ if ($type instanceof ConstantFloatType) {
+ return new FloatType();
+ }
+ if ($type instanceof ConstantIntegerType) {
+ return new IntegerType();
+ }
return $traverseCallback($type, $traverseCallback);
});
}
diff --git a/rules/Removing/NodeManipulator/ComplexNodeRemover.php b/rules/Removing/NodeManipulator/ComplexNodeRemover.php
index f3f08193d0cd..ecee231dbd3d 100644
--- a/rules/Removing/NodeManipulator/ComplexNodeRemover.php
+++ b/rules/Removing/NodeManipulator/ComplexNodeRemover.php
@@ -3,127 +3,9 @@
declare (strict_types=1);
namespace Rector\Removing\NodeManipulator;
-use PhpParser\Node;
-use PhpParser\Node\Expr;
-use PhpParser\Node\Expr\ArrayDimFetch;
-use PhpParser\Node\Expr\Assign;
-use PhpParser\Node\Expr\PropertyFetch;
-use PhpParser\Node\Expr\StaticPropertyFetch;
-use PhpParser\Node\Expr\Variable;
-use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\Expression;
-use PhpParser\Node\Stmt\Property;
-use PHPStan\Analyser\Scope;
-use Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer;
-use Rector\Core\PhpParser\Comparing\NodeComparator;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
-use Rector\Core\ValueObject\MethodName;
-use Rector\DeadCode\SideEffect\SideEffectNodeDetector;
-use Rector\NodeNameResolver\NodeNameResolver;
-use Rector\NodeRemoval\NodeRemover;
-use Rector\NodeTypeResolver\Node\AttributeKey;
-use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser;
final class ComplexNodeRemover
{
- /**
- * @readonly
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- /**
- * @readonly
- * @var \Rector\NodeRemoval\NodeRemover
- */
- private $nodeRemover;
- /**
- * @readonly
- * @var \Rector\DeadCode\SideEffect\SideEffectNodeDetector
- */
- private $sideEffectNodeDetector;
- /**
- * @readonly
- * @var \Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser
- */
- private $simpleCallableNodeTraverser;
- /**
- * @readonly
- * @var \Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer
- */
- private $propertyFetchAnalyzer;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Comparing\NodeComparator
- */
- private $nodeComparator;
- public function __construct(NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder, NodeRemover $nodeRemover, SideEffectNodeDetector $sideEffectNodeDetector, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, PropertyFetchAnalyzer $propertyFetchAnalyzer, NodeComparator $nodeComparator)
- {
- $this->nodeNameResolver = $nodeNameResolver;
- $this->betterNodeFinder = $betterNodeFinder;
- $this->nodeRemover = $nodeRemover;
- $this->sideEffectNodeDetector = $sideEffectNodeDetector;
- $this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
- $this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
- $this->nodeComparator = $nodeComparator;
- }
- public function removePropertyAndUsages(Class_ $class, Property $property, bool $removeAssignSideEffect, Scope $scope, int $propertyStmtKey) : bool
- {
- $propertyName = $this->nodeNameResolver->getName($property);
- $totalPropertyFetch = $this->propertyFetchAnalyzer->countLocalPropertyFetchName($class, $propertyName);
- $expressions = [];
- $this->simpleCallableNodeTraverser->traverseNodesWithCallable($class->stmts, function (Node $node) use($removeAssignSideEffect, $propertyName, &$totalPropertyFetch, &$expressions, $scope) : ?Node {
- // here should be checked all expr like stmts that can hold assign, e.f. if, foreach etc. etc.
- if (!$node instanceof Expression) {
- return null;
- }
- $nodeExpr = $node->expr;
- // remove direct assigns
- if (!$nodeExpr instanceof Assign) {
- return null;
- }
- $assign = $nodeExpr;
- // skip double assigns
- if ($assign->expr instanceof Assign) {
- return null;
- }
- $originalNode = $assign->getAttribute(AttributeKey::ORIGINAL_NODE);
- if (!$this->nodeComparator->areNodesEqual($originalNode, $assign)) {
- return null;
- }
- $propertyFetches = $this->resolvePropertyFetchFromDimFetch($assign->var);
- if ($propertyFetches === []) {
- return null;
- }
- $currentTotalPropertyFetch = $totalPropertyFetch;
- foreach ($propertyFetches as $propertyFetch) {
- if ($this->nodeNameResolver->isName($propertyFetch->name, $propertyName)) {
- if (!$removeAssignSideEffect && $this->sideEffectNodeDetector->detect($assign->expr, $scope)) {
- return null;
- }
- --$totalPropertyFetch;
- }
- }
- if ($totalPropertyFetch < $currentTotalPropertyFetch) {
- $expressions[] = $node;
- }
- return null;
- });
- // not all property fetch with name removed
- if ($totalPropertyFetch > 0) {
- return \false;
- }
- $this->removeConstructorDependency($class, $propertyName);
- foreach ($expressions as $expression) {
- $this->nodeRemover->removeNode($expression);
- }
- unset($class->stmts[$propertyStmtKey]);
- return \true;
- }
/**
* @param int[] $paramKeysToBeRemoved
* @return int[]
@@ -150,93 +32,4 @@ public function processRemoveParamWithKeys(ClassMethod $classMethod, array $para
}
return $removedParamKeys;
}
- private function removeConstructorDependency(Class_ $class, string $propertyName) : void
- {
- $classMethod = $class->getMethod(MethodName::CONSTRUCT);
- if (!$classMethod instanceof ClassMethod) {
- return;
- }
- $stmts = (array) $classMethod->stmts;
- $paramKeysToBeRemoved = [];
- foreach ($stmts as $key => $stmt) {
- if (!$stmt instanceof Expression) {
- continue;
- }
- $stmtExpr = $stmt->expr;
- if (!$stmtExpr instanceof Assign) {
- continue;
- }
- if (!$this->propertyFetchAnalyzer->isLocalPropertyFetch($stmtExpr->var)) {
- continue;
- }
- /** @var StaticPropertyFetch|PropertyFetch $propertyFetch */
- $propertyFetch = $stmtExpr->var;
- if (!$this->nodeNameResolver->isName($propertyFetch, $propertyName)) {
- continue;
- }
- unset($classMethod->stmts[$key]);
- if (!$stmtExpr->expr instanceof Variable) {
- continue;
- }
- $key = $this->resolveToBeClearedParamFromConstructor($classMethod, $stmtExpr->expr);
- if (\is_int($key)) {
- $paramKeysToBeRemoved[] = $key;
- }
- }
- if ($paramKeysToBeRemoved === []) {
- return;
- }
- $this->processRemoveParamWithKeys($classMethod, $paramKeysToBeRemoved);
- }
- /**
- * @return StaticPropertyFetch[]|PropertyFetch[]
- */
- private function resolvePropertyFetchFromDimFetch(Expr $expr) : array
- {
- // unwrap array dim fetch, till we get to parent too caller node
- /** @var PropertyFetch[]|StaticPropertyFetch[] $propertyFetches */
- $propertyFetches = [];
- while ($expr instanceof ArrayDimFetch) {
- $propertyFetches = $this->collectPropertyFetches($expr->dim, $propertyFetches);
- $expr = $expr->var;
- }
- return $this->collectPropertyFetches($expr, $propertyFetches);
- }
- /**
- * @param StaticPropertyFetch[]|PropertyFetch[] $propertyFetches
- * @return PropertyFetch[]|StaticPropertyFetch[]
- */
- private function collectPropertyFetches(?Expr $expr, array $propertyFetches) : array
- {
- if (!$expr instanceof Expr) {
- return $propertyFetches;
- }
- if ($this->propertyFetchAnalyzer->isLocalPropertyFetch($expr)) {
- /** @var StaticPropertyFetch|PropertyFetch $expr */
- return \array_merge($propertyFetches, [$expr]);
- }
- return $propertyFetches;
- }
- private function resolveToBeClearedParamFromConstructor(ClassMethod $classMethod, Variable $assignedVariable) : ?int
- {
- // is variable used somewhere else? skip it
- $variables = $this->betterNodeFinder->findInstanceOf($classMethod, Variable::class);
- $paramNamedVariables = \array_filter($variables, function (Variable $variable) use($assignedVariable) : bool {
- return $this->nodeNameResolver->areNamesEqual($variable, $assignedVariable);
- });
- // there is more than 1 use, keep it in the constructor
- if (\count($paramNamedVariables) > 1) {
- return null;
- }
- $paramName = $this->nodeNameResolver->getName($assignedVariable);
- if (!\is_string($paramName)) {
- return null;
- }
- foreach ($classMethod->params as $paramKey => $param) {
- if ($this->nodeNameResolver->isName($param->var, $paramName)) {
- return $paramKey;
- }
- }
- return null;
- }
}
diff --git a/rules/Removing/Rector/Class_/RemoveParentRector.php b/rules/Removing/Rector/Class_/RemoveParentRector.php
index 797436ee0af6..f86e2d91fb9b 100644
--- a/rules/Removing/Rector/Class_/RemoveParentRector.php
+++ b/rules/Removing/Rector/Class_/RemoveParentRector.php
@@ -18,15 +18,15 @@
*/
final class RemoveParentRector extends AbstractScopeAwareRector implements ConfigurableRectorInterface
{
- /**
- * @var string[]
- */
- private $parentClassesToRemove = [];
/**
* @readonly
* @var \Rector\NodeCollector\ScopeResolver\ParentClassScopeResolver
*/
private $parentClassScopeResolver;
+ /**
+ * @var string[]
+ */
+ private $parentClassesToRemove = [];
public function __construct(ParentClassScopeResolver $parentClassScopeResolver)
{
$this->parentClassScopeResolver = $parentClassScopeResolver;
diff --git a/rules/Removing/Rector/Class_/RemoveTraitUseRector.php b/rules/Removing/Rector/Class_/RemoveTraitUseRector.php
index 6286e944604a..1f1e437ad2fd 100644
--- a/rules/Removing/Rector/Class_/RemoveTraitUseRector.php
+++ b/rules/Removing/Rector/Class_/RemoveTraitUseRector.php
@@ -6,6 +6,7 @@
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Trait_;
+use PhpParser\Node\Stmt\TraitUse;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
@@ -47,17 +48,24 @@ public function getNodeTypes() : array
*/
public function refactor(Node $node) : ?Node
{
- $classHasChanged = \false;
- foreach ($node->getTraitUses() as $traitUse) {
- foreach ($traitUse->traits as $trait) {
+ $hasChanged = \false;
+ foreach ($node->stmts as $key => $stmt) {
+ if (!$stmt instanceof TraitUse) {
+ continue;
+ }
+ foreach ($stmt->traits as $traitKey => $trait) {
if (!$this->isNames($trait, $this->traitsToRemove)) {
continue;
}
- $this->removeNode($traitUse);
- $classHasChanged = \true;
+ unset($stmt->traits[$traitKey]);
+ $hasChanged = \true;
+ }
+ // remove empty trait uses
+ if ($stmt->traits === []) {
+ unset($node->stmts[$key]);
}
}
- if ($classHasChanged) {
+ if ($hasChanged) {
return $node;
}
return null;
diff --git a/rules/Removing/Rector/FuncCall/RemoveFuncCallRector.php b/rules/Removing/Rector/FuncCall/RemoveFuncCallRector.php
index c97fe68e9f91..b30c24c5d15c 100644
--- a/rules/Removing/Rector/FuncCall/RemoveFuncCallRector.php
+++ b/rules/Removing/Rector/FuncCall/RemoveFuncCallRector.php
@@ -6,6 +6,7 @@
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Stmt\Expression;
+use PhpParser\NodeTraverser;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
@@ -41,13 +42,18 @@ public function getNodeTypes() : array
/**
* @param Expression $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactor(Node $node) : ?int
{
$expr = $node->expr;
if (!$expr instanceof FuncCall) {
return null;
}
- $this->removeNodeIfNeeded($node, $expr);
+ foreach ($this->removedFunctions as $removedFunction) {
+ if (!$this->isName($expr->name, $removedFunction)) {
+ continue;
+ }
+ return NodeTraverser::REMOVE_NODE;
+ }
return null;
}
/**
@@ -58,14 +64,4 @@ public function configure(array $configuration) : void
Assert::allString($configuration);
$this->removedFunctions = $configuration;
}
- private function removeNodeIfNeeded(Expression $expression, FuncCall $funcCall) : void
- {
- foreach ($this->removedFunctions as $removedFunction) {
- if (!$this->isName($funcCall->name, $removedFunction)) {
- continue;
- }
- $this->removeNode($expression);
- break;
- }
- }
}
diff --git a/rules/Renaming/Helper/RenameClassCallbackHandler.php b/rules/Renaming/Helper/RenameClassCallbackHandler.php
index 628c38b3799f..f00ba45a5f1c 100644
--- a/rules/Renaming/Helper/RenameClassCallbackHandler.php
+++ b/rules/Renaming/Helper/RenameClassCallbackHandler.php
@@ -12,10 +12,6 @@
use Rector\NodeNameResolver\NodeNameResolver;
final class RenameClassCallbackHandler extends NodeVisitorAbstract
{
- /**
- * @var array
- */
- private $oldToNewClassCallbacks = [];
/**
* @readonly
* @var \Rector\Core\Configuration\RenamedClassesDataCollector
@@ -31,6 +27,10 @@ final class RenameClassCallbackHandler extends NodeVisitorAbstract
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @var array
+ */
+ private $oldToNewClassCallbacks = [];
public function __construct(RenamedClassesDataCollector $renamedClassesDataCollector, NodeNameResolver $nodeNameResolver, ReflectionProvider $reflectionProvider)
{
$this->renamedClassesDataCollector = $renamedClassesDataCollector;
@@ -46,8 +46,7 @@ public function hasOldToNewClassCallbacks() : bool
*/
public function addOldToNewClassCallbacks(array $oldToNewClassCallbacks) : void
{
- $item0Unpacked = $this->oldToNewClassCallbacks;
- $this->oldToNewClassCallbacks = \array_merge($item0Unpacked, $oldToNewClassCallbacks);
+ $this->oldToNewClassCallbacks = \array_merge($this->oldToNewClassCallbacks, $oldToNewClassCallbacks);
}
/**
* @return array
diff --git a/rules/Renaming/NodeManipulator/ClassRenamer.php b/rules/Renaming/NodeManipulator/ClassRenamer.php
index f21bb3f09b5d..93f95241bb79 100644
--- a/rules/Renaming/NodeManipulator/ClassRenamer.php
+++ b/rules/Renaming/NodeManipulator/ClassRenamer.php
@@ -3,18 +3,14 @@
declare (strict_types=1);
namespace Rector\Renaming\NodeManipulator;
-use RectorPrefix202306\Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\AttributeGroup;
-use PhpParser\Node\Expr\New_;
-use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Namespace_;
-use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\Stmt\UseUse;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
@@ -24,13 +20,10 @@
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocClassRenamer;
use Rector\BetterPhpDocParser\ValueObject\NodeTypes;
use Rector\CodingStyle\Naming\ClassNaming;
-use Rector\Core\Configuration\Option;
-use Rector\Core\Configuration\Parameter\ParameterProvider;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\Util\FileHasher;
use Rector\Naming\Naming\UseImportsResolver;
use Rector\NodeNameResolver\NodeNameResolver;
-use Rector\NodeRemoval\NodeRemover;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockClassRenamer;
use Rector\NodeTypeResolver\ValueObject\OldToNewType;
@@ -39,14 +32,6 @@
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
final class ClassRenamer
{
- /**
- * @var string[]
- */
- private $alreadyProcessedClasses = [];
- /**
- * @var array
- */
- private $oldToNewTypesByCacheKey = [];
/**
* @readonly
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
@@ -87,16 +72,6 @@ final class ClassRenamer
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
- /**
- * @readonly
- * @var \Rector\NodeRemoval\NodeRemover
- */
- private $nodeRemover;
- /**
- * @readonly
- * @var \Rector\Core\Configuration\Parameter\ParameterProvider
- */
- private $parameterProvider;
/**
* @readonly
* @var \Rector\Naming\Naming\UseImportsResolver
@@ -112,7 +87,15 @@ final class ClassRenamer
* @var \Rector\Core\Util\FileHasher
*/
private $fileHasher;
- public function __construct(BetterNodeFinder $betterNodeFinder, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, ClassNaming $classNaming, NodeNameResolver $nodeNameResolver, PhpDocClassRenamer $phpDocClassRenamer, PhpDocInfoFactory $phpDocInfoFactory, DocBlockClassRenamer $docBlockClassRenamer, ReflectionProvider $reflectionProvider, NodeRemover $nodeRemover, ParameterProvider $parameterProvider, UseImportsResolver $useImportsResolver, RenameClassCallbackHandler $renameClassCallbackHandler, FileHasher $fileHasher)
+ /**
+ * @var string[]
+ */
+ private $alreadyProcessedClasses = [];
+ /**
+ * @var array
+ */
+ private $oldToNewTypesByCacheKey = [];
+ public function __construct(BetterNodeFinder $betterNodeFinder, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, ClassNaming $classNaming, NodeNameResolver $nodeNameResolver, PhpDocClassRenamer $phpDocClassRenamer, PhpDocInfoFactory $phpDocInfoFactory, DocBlockClassRenamer $docBlockClassRenamer, ReflectionProvider $reflectionProvider, UseImportsResolver $useImportsResolver, RenameClassCallbackHandler $renameClassCallbackHandler, FileHasher $fileHasher)
{
$this->betterNodeFinder = $betterNodeFinder;
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
@@ -122,8 +105,6 @@ public function __construct(BetterNodeFinder $betterNodeFinder, SimpleCallableNo
$this->phpDocInfoFactory = $phpDocInfoFactory;
$this->docBlockClassRenamer = $docBlockClassRenamer;
$this->reflectionProvider = $reflectionProvider;
- $this->nodeRemover = $nodeRemover;
- $this->parameterProvider = $parameterProvider;
$this->useImportsResolver = $useImportsResolver;
$this->renameClassCallbackHandler = $renameClassCallbackHandler;
$this->fileHasher = $fileHasher;
@@ -166,36 +147,20 @@ private function refactorPhpDoc(Node $node, array $oldToNewTypes, array $oldToNe
$this->docBlockClassRenamer->renamePhpDocType($phpDocInfo, $oldToNewTypes);
$this->phpDocClassRenamer->changeTypeInAnnotationTypes($node, $phpDocInfo, $oldToNewClasses);
}
- private function shouldSkip(string $newName, Name $name, ?Node $parentNode = null) : bool
+ private function shouldSkip(string $newName, Name $name) : bool
{
- if ($parentNode instanceof StaticCall && $parentNode->class === $name && $this->reflectionProvider->hasClass($newName)) {
+ if ($name->getAttribute(AttributeKey::IS_STATICCALL_CLASS_NAME) === \true && $this->reflectionProvider->hasClass($newName)) {
$classReflection = $this->reflectionProvider->getClass($newName);
return $classReflection->isInterface();
}
- // parent is not a Node, possibly removed by other rule
- // skip change it
- if (!$parentNode instanceof Node) {
- return \true;
- }
- if (!$parentNode instanceof Namespace_) {
- return \false;
- }
- if ($parentNode->name !== $name) {
- return \false;
- }
- $namespaceNewName = Strings::before($newName, '\\', -1);
- if ($namespaceNewName === null) {
- return \false;
- }
- return $this->nodeNameResolver->isName($parentNode, $namespaceNewName);
+ return \false;
}
/**
* @param array $oldToNewClasses
*/
private function refactorName(Name $name, array $oldToNewClasses) : ?Name
{
- $parentNode = $name->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentNode instanceof Namespace_ && $parentNode->name === $name) {
+ if ($name->getAttribute(AttributeKey::IS_NAMESPACE_NAME) === \true) {
return null;
}
$stringName = $this->nodeNameResolver->getName($name);
@@ -206,43 +171,17 @@ private function refactorName(Name $name, array $oldToNewClasses) : ?Name
if (!$this->isClassToInterfaceValidChange($name, $newName)) {
return null;
}
- if ($this->shouldSkip($newName, $name, $parentNode)) {
- return null;
- }
// no need to preslash "use \SomeNamespace" of imported namespace
- if ($parentNode instanceof UseUse && ($parentNode->type === Use_::TYPE_NORMAL || $parentNode->type === Use_::TYPE_UNKNOWN)) {
+ if ($name->getAttribute(AttributeKey::IS_USEUSE_NAME) === \true) {
// no need to rename imports, they will be handled by autoimport and coding standard
// also they might cause some rename
return null;
}
- $last = $name->getLast();
- $newFullyQualified = new FullyQualified($newName);
- $newNameLastName = $newFullyQualified->getLast();
- $importNames = $this->parameterProvider->provideBoolParameter(Option::AUTO_IMPORT_NAMES);
- if ($this->shouldRemoveUseName($last, $newNameLastName, $importNames)) {
- $this->removeUseName($name);
+ if ($this->shouldSkip($newName, $name)) {
+ return null;
}
return new FullyQualified($newName);
}
- private function removeUseName(Name $oldName) : void
- {
- $uses = $this->betterNodeFinder->findFirstPrevious($oldName, function (Node $node) use($oldName) : bool {
- return $node instanceof UseUse && $this->nodeNameResolver->areNamesEqual($node, $oldName);
- });
- if (!$uses instanceof UseUse) {
- return;
- }
- if ($uses->alias instanceof Identifier) {
- return;
- }
- // ios the only one? Remove whole use instead to avoid "use ;" constructions
- $parentUse = $uses->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentUse instanceof Use_ && \count($parentUse->uses) === 1) {
- $this->nodeRemover->removeNode($parentUse);
- } else {
- $this->nodeRemover->removeNode($uses);
- }
- }
/**
* @param array $oldToNewClasses
*/
@@ -322,10 +261,10 @@ private function isClassToInterfaceValidChange(Name $name, string $newClassName)
}
$classReflection = $this->reflectionProvider->getClass($newClassName);
// ensure new is not with interface
- $parentNode = $name->getAttribute(AttributeKey::PARENT_NODE);
- if ($parentNode instanceof New_ && $classReflection->isInterface()) {
+ if ($name->getAttribute(AttributeKey::IS_NEW_INSTANCE_NAME) === \true && $classReflection->isInterface()) {
return \false;
}
+ $parentNode = $name->getAttribute(AttributeKey::PARENT_NODE);
if ($parentNode instanceof Class_) {
return $this->isValidClassNameChange($name, $parentNode, $classReflection);
}
@@ -402,7 +341,7 @@ private function isValidClassNameChange(Name $name, Class_ $class, ClassReflecti
}
private function isValidUseImportChange(string $newName, UseUse $useUse) : bool
{
- $uses = $this->useImportsResolver->resolveForNode($useUse);
+ $uses = $this->useImportsResolver->resolve();
if ($uses === []) {
return \true;
}
@@ -417,10 +356,6 @@ private function isValidUseImportChange(string $newName, UseUse $useUse) : bool
}
return \true;
}
- private function shouldRemoveUseName(string $last, string $newNameLastName, bool $importNames) : bool
- {
- return $last === $newNameLastName && $importNames;
- }
/**
* @param array $oldToNewClasses
* @return OldToNewType[]
@@ -448,7 +383,6 @@ private function createOldToNewTypes(Node $node, array $oldToNewClasses) : array
*/
private function resolveOldToNewClassCallbacks(Node $node, array $oldToNewClasses) : array
{
- $item1Unpacked = $this->renameClassCallbackHandler->getOldToNewClassesFromNode($node);
- return \array_merge($oldToNewClasses, $item1Unpacked);
+ return \array_merge($oldToNewClasses, $this->renameClassCallbackHandler->getOldToNewClassesFromNode($node));
}
}
diff --git a/rules/Renaming/Rector/ClassMethod/RenameAnnotationRector.php b/rules/Renaming/Rector/ClassMethod/RenameAnnotationRector.php
index 936650da84a4..66c748b934c9 100644
--- a/rules/Renaming/Rector/ClassMethod/RenameAnnotationRector.php
+++ b/rules/Renaming/Rector/ClassMethod/RenameAnnotationRector.php
@@ -21,15 +21,15 @@
*/
final class RenameAnnotationRector extends AbstractRector implements ConfigurableRectorInterface
{
- /**
- * @var RenameAnnotationInterface[]
- */
- private $renameAnnotations = [];
/**
* @readonly
* @var \Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockTagReplacer
*/
private $docBlockTagReplacer;
+ /**
+ * @var RenameAnnotationInterface[]
+ */
+ private $renameAnnotations = [];
public function __construct(DocBlockTagReplacer $docBlockTagReplacer)
{
$this->docBlockTagReplacer = $docBlockTagReplacer;
@@ -69,26 +69,40 @@ public function someMethod()
*/
public function getNodeTypes() : array
{
- return [ClassMethod::class, Property::class, Expression::class];
+ return [Class_::class, Expression::class];
}
/**
- * @param ClassMethod|Property $node
+ * @param Class_|Expression $node
*/
public function refactor(Node $node) : ?Node
{
- $classLike = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$classLike instanceof Class_) {
+ $hasChanged = \false;
+ if ($node instanceof Expression) {
+ $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
+ foreach ($this->renameAnnotations as $renameAnnotation) {
+ $hasDocBlockChanged = $this->docBlockTagReplacer->replaceTagByAnother($phpDocInfo, $renameAnnotation->getOldAnnotation(), $renameAnnotation->getNewAnnotation());
+ if ($hasDocBlockChanged) {
+ $hasChanged = \true;
+ }
+ }
+ if ($hasChanged) {
+ return $node;
+ }
return null;
}
- $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
- $hasChanged = \false;
- foreach ($this->renameAnnotations as $renameAnnotation) {
- if ($renameAnnotation instanceof RenameAnnotationByType && !$this->isObjectType($classLike, $renameAnnotation->getObjectType())) {
+ foreach ($node->stmts as $stmt) {
+ if (!$stmt instanceof ClassMethod && !$stmt instanceof Property) {
continue;
}
- $hasDocBlockChanged = $this->docBlockTagReplacer->replaceTagByAnother($phpDocInfo, $renameAnnotation->getOldAnnotation(), $renameAnnotation->getNewAnnotation());
- if ($hasDocBlockChanged) {
- $hasChanged = \true;
+ $phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($stmt);
+ foreach ($this->renameAnnotations as $renameAnnotation) {
+ if ($renameAnnotation instanceof RenameAnnotationByType && !$this->isObjectType($node, $renameAnnotation->getObjectType())) {
+ continue;
+ }
+ $hasDocBlockChanged = $this->docBlockTagReplacer->replaceTagByAnother($phpDocInfo, $renameAnnotation->getOldAnnotation(), $renameAnnotation->getNewAnnotation());
+ if ($hasDocBlockChanged) {
+ $hasChanged = \true;
+ }
}
}
if (!$hasChanged) {
diff --git a/rules/Renaming/Rector/FileWithoutNamespace/PseudoNamespaceToNamespaceRector.php b/rules/Renaming/Rector/FileWithoutNamespace/PseudoNamespaceToNamespaceRector.php
index c260904f5a4f..d860f4c29a0c 100644
--- a/rules/Renaming/Rector/FileWithoutNamespace/PseudoNamespaceToNamespaceRector.php
+++ b/rules/Renaming/Rector/FileWithoutNamespace/PseudoNamespaceToNamespaceRector.php
@@ -8,6 +8,7 @@
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
+use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Property;
@@ -25,6 +26,11 @@
*/
final class PseudoNamespaceToNamespaceRector extends AbstractRector implements ConfigurableRectorInterface
{
+ /**
+ * @readonly
+ * @var \Rector\NodeTypeResolver\PhpDoc\PhpDocTypeRenamer
+ */
+ private $phpDocTypeRenamer;
/**
* @see https://regex101.com/r/chvLgs/1/
* @var string
@@ -38,11 +44,6 @@ final class PseudoNamespaceToNamespaceRector extends AbstractRector implements C
* @var string|null
*/
private $newNamespace;
- /**
- * @readonly
- * @var \Rector\NodeTypeResolver\PhpDoc\PhpDocTypeRenamer
- */
- private $phpDocTypeRenamer;
public function __construct(PhpDocTypeRenamer $phpDocTypeRenamer)
{
$this->phpDocTypeRenamer = $phpDocTypeRenamer;
@@ -145,8 +146,7 @@ private function processNameOrIdentifier($node) : ?Node
private function processName(Name $name) : Name
{
$nodeName = $this->getName($name);
- $name->parts = \explode('_', $nodeName);
- return $name;
+ return $name instanceof FullyQualified ? new FullyQualified(\explode('_', $nodeName), $name->getAttributes()) : new Name(\explode('_', $nodeName), $name->getAttributes());
}
private function processIdentifier(Identifier $identifier) : ?Identifier
{
diff --git a/rules/Renaming/Rector/MethodCall/RenameMethodRector.php b/rules/Renaming/Rector/MethodCall/RenameMethodRector.php
index a091455199b2..1b1c961ab164 100644
--- a/rules/Renaming/Rector/MethodCall/RenameMethodRector.php
+++ b/rules/Renaming/Rector/MethodCall/RenameMethodRector.php
@@ -9,8 +9,8 @@
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
-use PhpParser\Node\Stmt\ClassLike;
-use PhpParser\Node\Stmt\ClassMethod;
+use PhpParser\Node\Stmt\Class_;
+use PhpParser\Node\Stmt\Interface_;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
@@ -29,10 +29,6 @@
*/
final class RenameMethodRector extends AbstractScopeAwareRector implements ConfigurableRectorInterface
{
- /**
- * @var MethodCallRenameInterface[]
- */
- private $methodCallRenames = [];
/**
* @readonly
* @var \Rector\Core\NodeManipulator\ClassManipulator
@@ -48,6 +44,10 @@ final class RenameMethodRector extends AbstractScopeAwareRector implements Confi
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @var MethodCallRenameInterface[]
+ */
+ private $methodCallRenames = [];
public function __construct(ClassManipulator $classManipulator, ReflectionResolver $reflectionResolver, ReflectionProvider $reflectionProvider)
{
$this->classManipulator = $classManipulator;
@@ -71,34 +71,17 @@ public function getRuleDefinition() : RuleDefinition
*/
public function getNodeTypes() : array
{
- return [MethodCall::class, StaticCall::class, ClassMethod::class];
+ return [MethodCall::class, StaticCall::class, Class_::class, Interface_::class];
}
/**
- * @param MethodCall|StaticCall|ClassMethod $node
+ * @param MethodCall|StaticCall|Class_|Interface_ $node
*/
public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
- $classReflection = $scope->getClassReflection();
- foreach ($this->methodCallRenames as $methodCallRename) {
- if (!$this->isName($node->name, $methodCallRename->getOldMethod())) {
- continue;
- }
- if ($this->shouldKeepForParentInterface($methodCallRename, $node, $classReflection)) {
- continue;
- }
- if (!$this->nodeTypeResolver->isMethodStaticCallOrClassMethodObjectType($node, $methodCallRename->getObjectType())) {
- continue;
- }
- if ($this->shouldSkipClassMethod($node, $methodCallRename)) {
- continue;
- }
- $node->name = new Identifier($methodCallRename->getNewMethod());
- if ($methodCallRename instanceof MethodCallRenameWithArrayKey && !$node instanceof ClassMethod) {
- return new ArrayDimFetch($node, BuilderHelpers::normalizeValue($methodCallRename->getArrayKey()));
- }
- return $node;
+ if ($node instanceof Class_ || $node instanceof Interface_) {
+ return $this->refactorClass($node, $scope);
}
- return null;
+ return $this->refactorMethodCallAndStaticCall($node);
}
/**
* @param mixed[] $configuration
@@ -109,47 +92,37 @@ public function configure(array $configuration) : void
$this->methodCallRenames = $configuration;
}
/**
- * @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall|\PhpParser\Node\Stmt\ClassMethod $node
+ * @param \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall $call
*/
- private function shouldSkipClassMethod($node, MethodCallRenameInterface $methodCallRename) : bool
+ private function shouldSkipClassMethod($call, MethodCallRenameInterface $methodCallRename) : bool
{
- if (!$node instanceof ClassMethod) {
- $classReflection = $this->reflectionResolver->resolveClassReflectionSourceObject($node);
- if (!$classReflection instanceof ClassReflection) {
- return \false;
- }
- $targetClass = $methodCallRename->getClass();
- if (!$this->reflectionProvider->hasClass($targetClass)) {
- return \false;
- }
- $targetClassReflection = $this->reflectionProvider->getClass($targetClass);
- if ($classReflection->getName() === $targetClassReflection->getName()) {
- return \false;
- }
- // different with configured ClassLike source? it is a child, which may has old and new exists
- if (!$classReflection->hasMethod($methodCallRename->getOldMethod())) {
- return \false;
- }
- return $classReflection->hasMethod($methodCallRename->getNewMethod());
+ $classReflection = $this->reflectionResolver->resolveClassReflectionSourceObject($call);
+ if (!$classReflection instanceof ClassReflection) {
+ return \false;
}
- return $this->shouldSkipForAlreadyExistingClassMethod($node, $methodCallRename);
- }
- private function shouldSkipForAlreadyExistingClassMethod(ClassMethod $classMethod, MethodCallRenameInterface $methodCallRename) : bool
- {
- $classLike = $this->betterNodeFinder->findParentType($classMethod, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
+ $targetClass = $methodCallRename->getClass();
+ if (!$this->reflectionProvider->hasClass($targetClass)) {
+ return \false;
+ }
+ $targetClassReflection = $this->reflectionProvider->getClass($targetClass);
+ if ($classReflection->getName() === $targetClassReflection->getName()) {
return \false;
}
- return (bool) $classLike->getMethod($methodCallRename->getNewMethod());
+ // different with configured ClassLike source? it is a child, which may has old and new exists
+ if (!$classReflection->hasMethod($methodCallRename->getOldMethod())) {
+ return \false;
+ }
+ return $classReflection->hasMethod($methodCallRename->getNewMethod());
}
/**
- * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\StaticCall|\PhpParser\Node\Expr\MethodCall $node
+ * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_ $classOrInternace
*/
- private function shouldKeepForParentInterface(MethodCallRenameInterface $methodCallRename, $node, ?ClassReflection $classReflection) : bool
+ private function hasClassNewClassMethod($classOrInternace, MethodCallRenameInterface $methodCallRename) : bool
+ {
+ return (bool) $classOrInternace->getMethod($methodCallRename->getNewMethod());
+ }
+ private function shouldKeepForParentInterface(MethodCallRenameInterface $methodCallRename, ?ClassReflection $classReflection) : bool
{
- if (!$node instanceof ClassMethod) {
- return \false;
- }
if (!$classReflection instanceof ClassReflection) {
return \false;
}
@@ -159,4 +132,62 @@ private function shouldKeepForParentInterface(MethodCallRenameInterface $methodC
}
return $this->classManipulator->hasParentMethodOrInterface($methodCallRename->getObjectType(), $methodCallRename->getOldMethod(), $methodCallRename->getNewMethod());
}
+ /**
+ * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_ $classOrInterface
+ * @return \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_|null
+ */
+ private function refactorClass($classOrInterface, Scope $scope)
+ {
+ if (!$scope->isInClass()) {
+ return null;
+ }
+ $classReflection = $scope->getClassReflection();
+ $hasChanged = \false;
+ foreach ($classOrInterface->getMethods() as $classMethod) {
+ foreach ($this->methodCallRenames as $methodCallRename) {
+ if (!$this->isName($classMethod->name, $methodCallRename->getOldMethod())) {
+ continue;
+ }
+ if (!$this->nodeTypeResolver->isMethodStaticCallOrClassMethodObjectType($classMethod, $methodCallRename->getObjectType())) {
+ continue;
+ }
+ if ($this->shouldKeepForParentInterface($methodCallRename, $classReflection)) {
+ continue;
+ }
+ if ($this->hasClassNewClassMethod($classOrInterface, $methodCallRename)) {
+ continue;
+ }
+ $classMethod->name = new Identifier($methodCallRename->getNewMethod());
+ $hasChanged = \true;
+ }
+ }
+ if ($hasChanged) {
+ return $classOrInterface;
+ }
+ return null;
+ }
+ /**
+ * @param \PhpParser\Node\Expr\StaticCall|\PhpParser\Node\Expr\MethodCall $call
+ * @return \PhpParser\Node\Expr\ArrayDimFetch|null|\PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\StaticCall
+ */
+ private function refactorMethodCallAndStaticCall($call)
+ {
+ foreach ($this->methodCallRenames as $methodCallRename) {
+ if (!$this->isName($call->name, $methodCallRename->getOldMethod())) {
+ continue;
+ }
+ if (!$this->nodeTypeResolver->isMethodStaticCallOrClassMethodObjectType($call, $methodCallRename->getObjectType())) {
+ continue;
+ }
+ if ($this->shouldSkipClassMethod($call, $methodCallRename)) {
+ continue;
+ }
+ $call->name = new Identifier($methodCallRename->getNewMethod());
+ if ($methodCallRename instanceof MethodCallRenameWithArrayKey) {
+ return new ArrayDimFetch($call, BuilderHelpers::normalizeValue($methodCallRename->getArrayKey()));
+ }
+ return $call;
+ }
+ return null;
+ }
}
diff --git a/rules/Renaming/Rector/Name/RenameClassRector.php b/rules/Renaming/Rector/Name/RenameClassRector.php
index 879b3044ce2a..10c4b3a1f642 100644
--- a/rules/Renaming/Rector/Name/RenameClassRector.php
+++ b/rules/Renaming/Rector/Name/RenameClassRector.php
@@ -25,10 +25,6 @@
*/
final class RenameClassRector extends AbstractScopeAwareRector implements ConfigurableRectorInterface
{
- /**
- * @var string
- */
- public const CALLBACKS = '#callbacks#';
/**
* @readonly
* @var \Rector\Core\Configuration\RenamedClassesDataCollector
@@ -44,6 +40,10 @@ final class RenameClassRector extends AbstractScopeAwareRector implements Config
* @var \Rector\Renaming\Helper\RenameClassCallbackHandler
*/
private $renameClassCallbackHandler;
+ /**
+ * @var string
+ */
+ public const CALLBACKS = '#callbacks#';
public function __construct(RenamedClassesDataCollector $renamedClassesDataCollector, ClassRenamer $classRenamer, RenameClassCallbackHandler $renameClassCallbackHandler)
{
$this->renamedClassesDataCollector = $renamedClassesDataCollector;
diff --git a/rules/Renaming/Rector/PropertyFetch/RenamePropertyRector.php b/rules/Renaming/Rector/PropertyFetch/RenamePropertyRector.php
index 4235879c8038..ae91d72f9a28 100644
--- a/rules/Renaming/Rector/PropertyFetch/RenamePropertyRector.php
+++ b/rules/Renaming/Rector/PropertyFetch/RenamePropertyRector.php
@@ -6,13 +6,10 @@
use PhpParser\Node;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Identifier;
-use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\VarLikeIdentifier;
use PHPStan\Type\ObjectType;
-use PHPStan\Type\ThisType;
-use PHPStan\Type\Type;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
use Rector\Renaming\ValueObject\RenameProperty;
@@ -57,7 +54,7 @@ public function refactor(Node $node) : ?Node
}
return null;
}
- return $this->processFromPropertyFetch($node);
+ return $this->refactorPropertyFetch($node);
}
/**
* @param mixed[] $configuration
@@ -90,10 +87,8 @@ private function renameProperty(ClassLike $classLike, RenameProperty $renameProp
$this->hasChanged = \true;
$property->props[0]->name = new VarLikeIdentifier($newProperty);
}
- private function processFromPropertyFetch(PropertyFetch $propertyFetch) : ?PropertyFetch
+ private function refactorPropertyFetch(PropertyFetch $propertyFetch) : ?PropertyFetch
{
- $class = $this->betterNodeFinder->findParentType($propertyFetch, Class_::class);
- $nodeVarType = null;
foreach ($this->renamedProperties as $renamedProperty) {
$oldProperty = $renamedProperty->getOldProperty();
if (!$this->isName($propertyFetch, $oldProperty)) {
@@ -102,14 +97,6 @@ private function processFromPropertyFetch(PropertyFetch $propertyFetch) : ?Prope
if (!$this->isObjectType($propertyFetch->var, $renamedProperty->getObjectType())) {
continue;
}
- if ($class instanceof ClassLike) {
- if (!$nodeVarType instanceof Type) {
- $nodeVarType = $this->nodeTypeResolver->getType($propertyFetch->var);
- }
- if ($nodeVarType instanceof ThisType) {
- $this->renameProperty($class, $renamedProperty);
- }
- }
$propertyFetch->name = new Identifier($renamedProperty->getNewProperty());
return $propertyFetch;
}
diff --git a/rules/Strict/Rector/BooleanNot/BooleanInBooleanNotRuleFixerRector.php b/rules/Strict/Rector/BooleanNot/BooleanInBooleanNotRuleFixerRector.php
index b274254df81b..321055a63159 100644
--- a/rules/Strict/Rector/BooleanNot/BooleanInBooleanNotRuleFixerRector.php
+++ b/rules/Strict/Rector/BooleanNot/BooleanInBooleanNotRuleFixerRector.php
@@ -72,6 +72,9 @@ public function getNodeTypes() : array
public function refactorWithScope(Node $node, Scope $scope) : ?Expr
{
$exprType = $scope->getType($node->expr);
+ if ($exprType->isBoolean()->yes()) {
+ return null;
+ }
return $this->exactCompareFactory->createIdenticalFalsyCompare($exprType, $node->expr, $this->treatAsNonEmpty);
}
}
diff --git a/rules/Strict/Rector/ClassMethod/AddConstructorParentCallRector.php b/rules/Strict/Rector/ClassMethod/AddConstructorParentCallRector.php
deleted file mode 100644
index bc2b2bfbaa46..000000000000
--- a/rules/Strict/Rector/ClassMethod/AddConstructorParentCallRector.php
+++ /dev/null
@@ -1,100 +0,0 @@
-dependencyClassMethodDecorator = $dependencyClassMethodDecorator;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- $errorMessage = \sprintf('Fixer for PHPStan reports by strict type rule - "%s"', 'PHPStan\\Rules\\Classes\\RequireParentConstructCallRule');
- return new RuleDefinition($errorMessage, [new CodeSample(<<<'CODE_SAMPLE'
-class SunshineCommand extends ParentClassWithConstructor
-{
- public function __construct()
- {
- $value = 5;
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-class SunshineCommand extends ParentClassWithConstructor
-{
- public function __construct(ParentDependency $parentDependency)
- {
- $value = 5;
-
- parent::__construct($parentDependency);
- }
-}
-CODE_SAMPLE
-)]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [ClassMethod::class];
- }
- /**
- * @param ClassMethod $node
- */
- public function refactorWithScope(Node $node, Scope $scope) : ?Node
- {
- if (!$this->isName($node, MethodName::CONSTRUCT)) {
- return null;
- }
- $classLike = $this->betterNodeFinder->findParentType($node, ClassLike::class);
- if (!$classLike instanceof Class_) {
- return null;
- }
- if ($this->hasParentCallOfMethod($node)) {
- return null;
- }
- $this->dependencyClassMethodDecorator->decorateConstructorWithParentDependencies($classLike, $node, $scope);
- return $node;
- }
- /**
- * Looks for "parent::__construct"
- */
- private function hasParentCallOfMethod(ClassMethod $classMethod) : bool
- {
- return (bool) $this->betterNodeFinder->findFirst((array) $classMethod->stmts, function (Node $node) : bool {
- if (!$node instanceof StaticCall) {
- return \false;
- }
- if (!$this->isName($node->class, ObjectReference::PARENT)) {
- return \false;
- }
- return $this->isName($node->name, MethodName::CONSTRUCT);
- });
- }
-}
diff --git a/rules/Transform/NodeAnalyzer/FuncCallStaticCallToMethodCallAnalyzer.php b/rules/Transform/NodeAnalyzer/FuncCallStaticCallToMethodCallAnalyzer.php
index cbc6b81d0df5..96dc70d7438c 100644
--- a/rules/Transform/NodeAnalyzer/FuncCallStaticCallToMethodCallAnalyzer.php
+++ b/rules/Transform/NodeAnalyzer/FuncCallStaticCallToMethodCallAnalyzer.php
@@ -10,12 +10,11 @@
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
-use PHPStan\Analyser\Scope;
use PHPStan\Type\ObjectType;
+use Rector\Core\NodeManipulator\ClassDependencyManipulator;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Naming\Naming\PropertyNaming;
use Rector\NodeNameResolver\NodeNameResolver;
-use Rector\PostRector\Collector\PropertyToAddCollector;
use Rector\PostRector\ValueObject\PropertyMetadata;
use Rector\Transform\NodeFactory\PropertyFetchFactory;
use Rector\Transform\NodeTypeAnalyzer\TypeProvidingExprFromClassResolver;
@@ -48,24 +47,24 @@ final class FuncCallStaticCallToMethodCallAnalyzer
private $propertyFetchFactory;
/**
* @readonly
- * @var \Rector\PostRector\Collector\PropertyToAddCollector
+ * @var \Rector\Core\NodeManipulator\ClassDependencyManipulator
*/
- private $propertyToAddCollector;
- public function __construct(TypeProvidingExprFromClassResolver $typeProvidingExprFromClassResolver, PropertyNaming $propertyNaming, NodeNameResolver $nodeNameResolver, NodeFactory $nodeFactory, PropertyFetchFactory $propertyFetchFactory, PropertyToAddCollector $propertyToAddCollector)
+ private $classDependencyManipulator;
+ public function __construct(TypeProvidingExprFromClassResolver $typeProvidingExprFromClassResolver, PropertyNaming $propertyNaming, NodeNameResolver $nodeNameResolver, NodeFactory $nodeFactory, PropertyFetchFactory $propertyFetchFactory, ClassDependencyManipulator $classDependencyManipulator)
{
$this->typeProvidingExprFromClassResolver = $typeProvidingExprFromClassResolver;
$this->propertyNaming = $propertyNaming;
$this->nodeNameResolver = $nodeNameResolver;
$this->nodeFactory = $nodeFactory;
$this->propertyFetchFactory = $propertyFetchFactory;
- $this->propertyToAddCollector = $propertyToAddCollector;
+ $this->classDependencyManipulator = $classDependencyManipulator;
}
/**
* @return \PhpParser\Node\Expr\MethodCall|\PhpParser\Node\Expr\PropertyFetch|\PhpParser\Node\Expr\Variable
*/
- public function matchTypeProvidingExpr(Class_ $class, ClassMethod $classMethod, ObjectType $objectType, Scope $scope)
+ public function matchTypeProvidingExpr(Class_ $class, ClassMethod $classMethod, ObjectType $objectType)
{
- $expr = $this->typeProvidingExprFromClassResolver->resolveTypeProvidingExprFromClass($class, $classMethod, $objectType, $scope);
+ $expr = $this->typeProvidingExprFromClassResolver->resolveTypeProvidingExprFromClass($class, $classMethod, $objectType);
if ($expr instanceof Expr) {
if ($expr instanceof Variable) {
$this->addClassMethodParamForVariable($expr, $objectType, $classMethod);
@@ -73,8 +72,7 @@ public function matchTypeProvidingExpr(Class_ $class, ClassMethod $classMethod,
return $expr;
}
$propertyName = $this->propertyNaming->fqnToVariableName($objectType);
- $propertyMetadata = new PropertyMetadata($propertyName, $objectType, Class_::MODIFIER_PRIVATE);
- $this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
+ $this->classDependencyManipulator->addConstructorDependency($class, new PropertyMetadata($propertyName, $objectType));
return $this->propertyFetchFactory->createFromType($objectType);
}
/**
diff --git a/rules/Transform/NodeTypeAnalyzer/TypeProvidingExprFromClassResolver.php b/rules/Transform/NodeTypeAnalyzer/TypeProvidingExprFromClassResolver.php
index 224d0f03f614..85c0e0d137f3 100644
--- a/rules/Transform/NodeTypeAnalyzer/TypeProvidingExprFromClassResolver.php
+++ b/rules/Transform/NodeTypeAnalyzer/TypeProvidingExprFromClassResolver.php
@@ -9,7 +9,6 @@
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
-use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParametersAcceptorSelector;
@@ -49,7 +48,7 @@ public function __construct(ReflectionProvider $reflectionProvider, NodeNameReso
/**
* @return MethodCall|PropertyFetch|Variable|null
*/
- public function resolveTypeProvidingExprFromClass(Class_ $class, ClassMethod $classMethod, ObjectType $objectType, Scope $scope) : ?Expr
+ public function resolveTypeProvidingExprFromClass(Class_ $class, ClassMethod $classMethod, ObjectType $objectType) : ?Expr
{
$className = (string) $this->nodeNameResolver->getName($class);
// A. match a method
@@ -59,7 +58,7 @@ public function resolveTypeProvidingExprFromClass(Class_ $class, ClassMethod $cl
return $methodCallProvidingType;
}
// B. match existing property
- $propertyFetch = $this->resolvePropertyFetchProvidingType($classReflection, $scope, $objectType);
+ $propertyFetch = $this->resolvePropertyFetchProvidingType($classReflection, $objectType);
if ($propertyFetch instanceof PropertyFetch) {
return $propertyFetch;
}
@@ -80,12 +79,12 @@ private function resolveMethodCallProvidingType(ClassReflection $classReflection
}
return null;
}
- private function resolvePropertyFetchProvidingType(ClassReflection $classReflection, Scope $scope, ObjectType $objectType) : ?PropertyFetch
+ private function resolvePropertyFetchProvidingType(ClassReflection $classReflection, ObjectType $objectType) : ?PropertyFetch
{
$nativeReflectionClass = $classReflection->getNativeReflection();
foreach ($nativeReflectionClass->getProperties() as $reflectionProperty) {
/** @var PhpPropertyReflection $phpPropertyReflection */
- $phpPropertyReflection = $classReflection->getProperty($reflectionProperty->getName(), $scope);
+ $phpPropertyReflection = $classReflection->getNativeProperty($reflectionProperty->getName());
$readableType = $phpPropertyReflection->getReadableType();
if (!$this->isMatchingType($readableType, $objectType)) {
continue;
diff --git a/rules/Transform/Rector/Attribute/AttributeKeyToClassConstFetchRector.php b/rules/Transform/Rector/Attribute/AttributeKeyToClassConstFetchRector.php
index 67604e895404..99ae647be1bd 100644
--- a/rules/Transform/Rector/Attribute/AttributeKeyToClassConstFetchRector.php
+++ b/rules/Transform/Rector/Attribute/AttributeKeyToClassConstFetchRector.php
@@ -15,6 +15,7 @@
/**
* @changelog https://github.com/doctrine/dbal/blob/3.1.x/src/Types/Types.php
*
+ * @api used in rector-doctrine
* @see \Rector\Tests\Transform\Rector\Attribute\AttributeKeyToClassConstFetchRector\AttributeKeyToClassConstFetchRectorTest
*/
final class AttributeKeyToClassConstFetchRector extends AbstractRector implements ConfigurableRectorInterface
diff --git a/rules/Transform/Rector/ClassMethod/ReturnTypeWillChangeRector.php b/rules/Transform/Rector/ClassMethod/ReturnTypeWillChangeRector.php
index 4b5c5f55173f..1abaf6ce8939 100644
--- a/rules/Transform/Rector/ClassMethod/ReturnTypeWillChangeRector.php
+++ b/rules/Transform/Rector/ClassMethod/ReturnTypeWillChangeRector.php
@@ -5,8 +5,6 @@
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassLike;
-use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Interface_;
use Rector\Core\Contract\Rector\AllowEmptyConfigurableRectorInterface;
use Rector\Core\Rector\AbstractRector;
@@ -25,10 +23,6 @@
*/
final class ReturnTypeWillChangeRector extends AbstractRector implements AllowEmptyConfigurableRectorInterface, MinPhpVersionInterface
{
- /**
- * @var ClassMethodReference[]
- */
- private $returnTypeChangedClassMethodReferences = [];
/**
* @readonly
* @var \Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer
@@ -44,13 +38,16 @@ final class ReturnTypeWillChangeRector extends AbstractRector implements AllowEm
* @var \Rector\Core\Reflection\ReflectionResolver
*/
private $reflectionResolver;
+ /**
+ * @var ClassMethodReference[]
+ */
+ private $returnTypeChangedClassMethodReferences = [];
public function __construct(PhpAttributeAnalyzer $phpAttributeAnalyzer, PhpAttributeGroupFactory $phpAttributeGroupFactory, ReflectionResolver $reflectionResolver)
{
$this->phpAttributeAnalyzer = $phpAttributeAnalyzer;
$this->phpAttributeGroupFactory = $phpAttributeGroupFactory;
$this->reflectionResolver = $reflectionResolver;
- $this->returnTypeChangedClassMethodReferences[] = new ClassMethodReference('ArrayAccess', 'getIterator');
- $this->returnTypeChangedClassMethodReferences[] = new ClassMethodReference('ArrayAccess', 'offsetGet');
+ $this->returnTypeChangedClassMethodReferences = [new ClassMethodReference('ArrayAccess', 'getIterator'), new ClassMethodReference('ArrayAccess', 'offsetGet')];
}
public function getRuleDefinition() : RuleDefinition
{
@@ -78,42 +75,39 @@ public function offsetGet($offset)
*/
public function getNodeTypes() : array
{
- return [ClassMethod::class];
+ return [Class_::class, Interface_::class];
}
/**
- * @param ClassMethod $node
+ * @param Class_|Interface_ $node
*/
public function refactor(Node $node) : ?Node
{
- if ($this->phpAttributeAnalyzer->hasPhpAttribute($node, AttributeName::RETURN_TYPE_WILL_CHANGE)) {
- return null;
- }
- // the return type is known, no need to add attribute
- if ($node->returnType !== null) {
- return null;
- }
- $classLike = $this->betterNodeFinder->findParentByTypes($node, [Class_::class, Interface_::class]);
- if (!$classLike instanceof ClassLike) {
- return null;
- }
- $classReflection = $this->reflectionResolver->resolveClassAndAnonymousClass($classLike);
- $methodName = $node->name->toString();
$hasChanged = \false;
- foreach ($this->returnTypeChangedClassMethodReferences as $returnTypeChangedClassMethodReference) {
- if (!$classReflection->isSubclassOf($returnTypeChangedClassMethodReference->getClass())) {
+ $classReflection = $this->reflectionResolver->resolveClassAndAnonymousClass($node);
+ foreach ($node->getMethods() as $classMethod) {
+ if ($this->phpAttributeAnalyzer->hasPhpAttribute($classMethod, AttributeName::RETURN_TYPE_WILL_CHANGE)) {
continue;
}
- if ($returnTypeChangedClassMethodReference->getMethod() !== $methodName) {
+ // the return type is known, no need to add attribute
+ if ($classMethod->returnType !== null) {
continue;
}
- $node->attrGroups[] = $this->phpAttributeGroupFactory->createFromClass(AttributeName::RETURN_TYPE_WILL_CHANGE);
- $hasChanged = \true;
- break;
+ foreach ($this->returnTypeChangedClassMethodReferences as $returnTypeChangedClassMethodReference) {
+ if (!$classReflection->isSubclassOf($returnTypeChangedClassMethodReference->getClass())) {
+ continue;
+ }
+ if (!$this->isName($classMethod, $returnTypeChangedClassMethodReference->getMethod())) {
+ continue;
+ }
+ $classMethod->attrGroups[] = $this->phpAttributeGroupFactory->createFromClass(AttributeName::RETURN_TYPE_WILL_CHANGE);
+ $hasChanged = \true;
+ break;
+ }
}
- if (!$hasChanged) {
- return null;
+ if ($hasChanged) {
+ return $node;
}
- return $node;
+ return null;
}
/**
* @param mixed[] $configuration
diff --git a/rules/Transform/Rector/Class_/AddAllowDynamicPropertiesAttributeRector.php b/rules/Transform/Rector/Class_/AddAllowDynamicPropertiesAttributeRector.php
index 2674df3ee227..86254307f878 100644
--- a/rules/Transform/Rector/Class_/AddAllowDynamicPropertiesAttributeRector.php
+++ b/rules/Transform/Rector/Class_/AddAllowDynamicPropertiesAttributeRector.php
@@ -26,10 +26,6 @@
*/
final class AddAllowDynamicPropertiesAttributeRector extends AbstractRector implements AllowEmptyConfigurableRectorInterface, MinPhpVersionInterface
{
- /**
- * @var array
- */
- private $transformOnNamespaces = [];
/**
* @readonly
* @var \Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer
@@ -50,6 +46,10 @@ final class AddAllowDynamicPropertiesAttributeRector extends AbstractRector impl
* @var \PHPStan\Reflection\ReflectionProvider
*/
private $reflectionProvider;
+ /**
+ * @var array
+ */
+ private $transformOnNamespaces = [];
public function __construct(FamilyRelationsAnalyzer $familyRelationsAnalyzer, PhpAttributeAnalyzer $phpAttributeAnalyzer, PhpAttributeGroupFactory $phpAttributeGroupFactory, ReflectionProvider $reflectionProvider)
{
$this->familyRelationsAnalyzer = $familyRelationsAnalyzer;
diff --git a/rules/Transform/Rector/Class_/AddInterfaceByTraitRector.php b/rules/Transform/Rector/Class_/AddInterfaceByTraitRector.php
index 131f7674e19b..0ccb4d8925f2 100644
--- a/rules/Transform/Rector/Class_/AddInterfaceByTraitRector.php
+++ b/rules/Transform/Rector/Class_/AddInterfaceByTraitRector.php
@@ -14,6 +14,7 @@
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
use RectorPrefix202306\Webmozart\Assert\Assert;
/**
+ * @api used in rector-doctrine
* @see \Rector\Tests\Transform\Rector\Class_\AddInterfaceByTraitRector\AddInterfaceByTraitRectorTest
*/
final class AddInterfaceByTraitRector extends AbstractScopeAwareRector implements ConfigurableRectorInterface
diff --git a/rules/Transform/Rector/Class_/ParentClassToTraitsRector.php b/rules/Transform/Rector/Class_/ParentClassToTraitsRector.php
index 5b97fe1b1735..c4dca442b071 100644
--- a/rules/Transform/Rector/Class_/ParentClassToTraitsRector.php
+++ b/rules/Transform/Rector/Class_/ParentClassToTraitsRector.php
@@ -5,10 +5,11 @@
use PhpParser\Node;
use PhpParser\Node\Name;
+use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
+use PhpParser\Node\Stmt\TraitUse;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\NodeAnalyzer\ClassAnalyzer;
-use Rector\Core\NodeManipulator\ClassInsertManipulator;
use Rector\Core\Rector\AbstractRector;
use Rector\Transform\ValueObject\ParentClassToTraits;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
@@ -23,23 +24,17 @@
*/
final class ParentClassToTraitsRector extends AbstractRector implements ConfigurableRectorInterface
{
- /**
- * @var ParentClassToTraits[]
- */
- private $parentClassToTraits = [];
- /**
- * @readonly
- * @var \Rector\Core\NodeManipulator\ClassInsertManipulator
- */
- private $classInsertManipulator;
/**
* @readonly
* @var \Rector\Core\NodeAnalyzer\ClassAnalyzer
*/
private $classAnalyzer;
- public function __construct(ClassInsertManipulator $classInsertManipulator, ClassAnalyzer $classAnalyzer)
+ /**
+ * @var ParentClassToTraits[]
+ */
+ private $parentClassToTraits = [];
+ public function __construct(ClassAnalyzer $classAnalyzer)
{
- $this->classInsertManipulator = $classInsertManipulator;
$this->classAnalyzer = $classAnalyzer;
}
public function getRuleDefinition() : RuleDefinition
@@ -76,17 +71,21 @@ public function refactor(Node $node) : ?Node
if ($this->classAnalyzer->isAnonymousClass($node)) {
return null;
}
+ $traitUses = [];
foreach ($this->parentClassToTraits as $parentClassToTrait) {
if (!$this->isName($parentExtends, $parentClassToTrait->getParentType())) {
continue;
}
foreach ($parentClassToTrait->getTraitNames() as $traitName) {
- $this->classInsertManipulator->addAsFirstTrait($node, $traitName);
+ $traitUses[] = new TraitUse([new FullyQualified($traitName)]);
}
$this->removeParentClass($node);
- return $node;
}
- return null;
+ if ($traitUses === []) {
+ return null;
+ }
+ $node->stmts = \array_merge($traitUses, $node->stmts);
+ return $node;
}
/**
* @param mixed[] $configuration
diff --git a/rules/Transform/Rector/Class_/RemoveAllowDynamicPropertiesAttributeRector.php b/rules/Transform/Rector/Class_/RemoveAllowDynamicPropertiesAttributeRector.php
deleted file mode 100644
index a3b2081ec38e..000000000000
--- a/rules/Transform/Rector/Class_/RemoveAllowDynamicPropertiesAttributeRector.php
+++ /dev/null
@@ -1,107 +0,0 @@
-
- */
- private $transformOnNamespaces = [];
- /**
- * @readonly
- * @var \Rector\Php80\NodeAnalyzer\PhpAttributeAnalyzer
- */
- private $phpAttributeAnalyzer;
- public function __construct(PhpAttributeAnalyzer $phpAttributeAnalyzer)
- {
- $this->phpAttributeAnalyzer = $phpAttributeAnalyzer;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Remove the `AllowDynamicProperties` attribute from all classes', [new ConfiguredCodeSample(<<<'CODE_SAMPLE'
-namespace Example\Domain;
-
-#[AllowDynamicProperties]
-class SomeObject {
- public string $someProperty = 'hello world';
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-namespace Example\Domain;
-
-class SomeObject {
- public string $someProperty = 'hello world';
-}
-CODE_SAMPLE
-, ['Example\\*'])]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [Class_::class];
- }
- public function configure(array $configuration) : void
- {
- $transformOnNamespaces = $configuration;
- Assert::allString($transformOnNamespaces);
- $this->transformOnNamespaces = $transformOnNamespaces;
- }
- /**
- * @param Class_ $node
- */
- public function refactor(Node $node) : ?Node
- {
- if ($this->shouldRemove($node)) {
- return $this->removeAllowDynamicPropertiesAttribute($node);
- }
- return null;
- }
- private function removeAllowDynamicPropertiesAttribute(Class_ $class) : Class_
- {
- $newAttrGroups = [];
- foreach ($class->attrGroups as $attrGroup) {
- $newAttrs = [];
- foreach ($attrGroup->attrs as $attribute) {
- if (!$this->nodeNameResolver->isName($attribute, AttributeName::ALLOW_DYNAMIC_PROPERTIES)) {
- $newAttrs[] = $attribute;
- }
- }
- $attrGroup->attrs = $newAttrs;
- if ($attrGroup->attrs !== []) {
- $newAttrGroups[] = $attrGroup;
- }
- }
- $class->attrGroups = $newAttrGroups;
- return $class;
- }
- private function shouldRemove(Class_ $class) : bool
- {
- if ($this->transformOnNamespaces !== []) {
- $className = (string) $this->nodeNameResolver->getName($class);
- foreach ($this->transformOnNamespaces as $transformOnNamespace) {
- if (!$this->nodeNameResolver->isStringName($className, $transformOnNamespace)) {
- return \false;
- }
- }
- }
- return $this->phpAttributeAnalyzer->hasPhpAttribute($class, AttributeName::ALLOW_DYNAMIC_PROPERTIES);
- }
-}
diff --git a/rules/Transform/Rector/FuncCall/FuncCallToMethodCallRector.php b/rules/Transform/Rector/FuncCall/FuncCallToMethodCallRector.php
index c5eae2778092..71c2d8273caa 100644
--- a/rules/Transform/Rector/FuncCall/FuncCallToMethodCallRector.php
+++ b/rules/Transform/Rector/FuncCall/FuncCallToMethodCallRector.php
@@ -6,10 +6,8 @@
use PhpParser\Node;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassMethod;
-use PHPStan\Analyser\Scope;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
-use Rector\Core\Rector\AbstractScopeAwareRector;
+use Rector\Core\Rector\AbstractRector;
use Rector\Transform\NodeAnalyzer\FuncCallStaticCallToMethodCallAnalyzer;
use Rector\Transform\ValueObject\FuncCallToMethodCall;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
@@ -18,17 +16,17 @@
/**
* @see \Rector\Tests\Transform\Rector\FuncCall\FuncCallToMethodCallRector\FuncCallToMethodCallRectorTest
*/
-final class FuncCallToMethodCallRector extends AbstractScopeAwareRector implements ConfigurableRectorInterface
+final class FuncCallToMethodCallRector extends AbstractRector implements ConfigurableRectorInterface
{
- /**
- * @var FuncCallToMethodCall[]
- */
- private $funcNameToMethodCallNames = [];
/**
* @readonly
* @var \Rector\Transform\NodeAnalyzer\FuncCallStaticCallToMethodCallAnalyzer
*/
private $funcCallStaticCallToMethodCallAnalyzer;
+ /**
+ * @var FuncCallToMethodCall[]
+ */
+ private $funcNameToMethodCallNames = [];
public function __construct(FuncCallStaticCallToMethodCallAnalyzer $funcCallStaticCallToMethodCallAnalyzer)
{
$this->funcCallStaticCallToMethodCallAnalyzer = $funcCallStaticCallToMethodCallAnalyzer;
@@ -70,30 +68,39 @@ public function run()
*/
public function getNodeTypes() : array
{
- return [FuncCall::class];
+ return [Class_::class];
}
/**
- * @param FuncCall $node
+ * @param Class_ $node
*/
- public function refactorWithScope(Node $node, Scope $scope) : ?Node
+ public function refactor(Node $node) : ?Node
{
- $classLike = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$classLike instanceof Class_) {
- return null;
- }
- $classMethod = $this->betterNodeFinder->findParentType($node, ClassMethod::class);
- if (!$classMethod instanceof ClassMethod) {
- return null;
- }
- if ($classMethod->isStatic()) {
- return null;
- }
- foreach ($this->funcNameToMethodCallNames as $funcNameToMethodCallName) {
- if (!$this->isName($node->name, $funcNameToMethodCallName->getOldFuncName())) {
+ $hasChanged = \false;
+ $class = $node;
+ foreach ($node->getMethods() as $classMethod) {
+ if ($classMethod->isStatic()) {
continue;
}
- $expr = $this->funcCallStaticCallToMethodCallAnalyzer->matchTypeProvidingExpr($classLike, $classMethod, $funcNameToMethodCallName->getNewObjectType(), $scope);
- return $this->nodeFactory->createMethodCall($expr, $funcNameToMethodCallName->getNewMethodName(), $node->args);
+ if ($classMethod->isAbstract()) {
+ continue;
+ }
+ $this->traverseNodesWithCallable($classMethod, function (Node $node) use($class, $classMethod, &$hasChanged) : ?Node {
+ if (!$node instanceof FuncCall) {
+ return null;
+ }
+ foreach ($this->funcNameToMethodCallNames as $funcNameToMethodCallName) {
+ if (!$this->isName($node->name, $funcNameToMethodCallName->getOldFuncName())) {
+ continue;
+ }
+ $expr = $this->funcCallStaticCallToMethodCallAnalyzer->matchTypeProvidingExpr($class, $classMethod, $funcNameToMethodCallName->getNewObjectType());
+ $hasChanged = \true;
+ return $this->nodeFactory->createMethodCall($expr, $funcNameToMethodCallName->getNewMethodName(), $node->args);
+ }
+ return null;
+ });
+ }
+ if ($hasChanged) {
+ return $node;
}
return null;
}
diff --git a/rules/Transform/Rector/Isset_/UnsetAndIssetToMethodCallRector.php b/rules/Transform/Rector/Isset_/UnsetAndIssetToMethodCallRector.php
deleted file mode 100644
index 9956a2ef475e..000000000000
--- a/rules/Transform/Rector/Isset_/UnsetAndIssetToMethodCallRector.php
+++ /dev/null
@@ -1,91 +0,0 @@
-hasService("someKey");
-$container->removeService("someKey");
-CODE_SAMPLE
-, [new UnsetAndIssetToMethodCall('SomeContainer', 'hasService', 'removeService')])]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [Isset_::class, Unset_::class];
- }
- /**
- * @param Isset_|Unset_ $node
- */
- public function refactor(Node $node) : ?Node
- {
- foreach ($node->vars as $arrayDimFetch) {
- if (!$arrayDimFetch instanceof ArrayDimFetch) {
- continue;
- }
- foreach ($this->issetUnsetToMethodCalls as $issetUnsetToMethodCall) {
- if (!$this->isObjectType($arrayDimFetch->var, $issetUnsetToMethodCall->getObjectType())) {
- continue;
- }
- $newNode = $this->processArrayDimFetchNode($node, $arrayDimFetch, $issetUnsetToMethodCall);
- if ($newNode instanceof Node) {
- return $newNode;
- }
- }
- }
- return null;
- }
- /**
- * @param mixed[] $configuration
- */
- public function configure(array $configuration) : void
- {
- Assert::allIsAOf($configuration, UnsetAndIssetToMethodCall::class);
- $this->issetUnsetToMethodCalls = $configuration;
- }
- private function processArrayDimFetchNode(Node $node, ArrayDimFetch $arrayDimFetch, UnsetAndIssetToMethodCall $unsetAndIssetToMethodCall) : ?Node
- {
- if ($node instanceof Isset_) {
- if ($unsetAndIssetToMethodCall->getIssetMethodCall() === '') {
- return null;
- }
- return $this->nodeFactory->createMethodCall($arrayDimFetch->var, $unsetAndIssetToMethodCall->getIssetMethodCall(), [$arrayDimFetch->dim]);
- }
- if ($node instanceof Unset_) {
- if ($unsetAndIssetToMethodCall->getUnsedMethodCall() === '') {
- return null;
- }
- return $this->nodeFactory->createMethodCall($arrayDimFetch->var, $unsetAndIssetToMethodCall->getUnsedMethodCall(), [$arrayDimFetch->dim]);
- }
- return null;
- }
-}
diff --git a/rules/Transform/Rector/MethodCall/MethodCallToFuncCallRector.php b/rules/Transform/Rector/MethodCall/MethodCallToFuncCallRector.php
index b448ae895e27..60848b734799 100644
--- a/rules/Transform/Rector/MethodCall/MethodCallToFuncCallRector.php
+++ b/rules/Transform/Rector/MethodCall/MethodCallToFuncCallRector.php
@@ -57,6 +57,9 @@ public function getNodeTypes() : array
*/
public function refactor(Node $node) : ?Node
{
+ if ($node->isFirstClassCallable()) {
+ return null;
+ }
foreach ($this->methodCallsToFuncCalls as $methodCallToFuncCall) {
if (!$this->isName($node->name, $methodCallToFuncCall->getMethodName())) {
continue;
diff --git a/rules/Transform/Rector/MethodCall/MethodCallToMethodCallRector.php b/rules/Transform/Rector/MethodCall/MethodCallToMethodCallRector.php
deleted file mode 100644
index b04ab14dee28..000000000000
--- a/rules/Transform/Rector/MethodCall/MethodCallToMethodCallRector.php
+++ /dev/null
@@ -1,165 +0,0 @@
-propertyNaming = $propertyNaming;
- $this->propertyPresenceChecker = $propertyPresenceChecker;
- $this->propertyToAddCollector = $propertyToAddCollector;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Change method one method from one service to a method call to in another service', [new ConfiguredCodeSample(<<<'CODE_SAMPLE'
-class SomeClass
-{
- public function __construct(
- private FirstDependency $firstDependency
- ) {
- }
-
- public function run()
- {
- $this->firstDependency->go();
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-class SomeClass
-{
- public function __construct(
- private SecondDependency $secondDependency
- ) {
- }
-
- public function run()
- {
- $this->secondDependency->away();
- }
-}
-CODE_SAMPLE
-, [new MethodCallToMethodCall('FirstDependency', 'go', 'SecondDependency', 'away')])]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [MethodCall::class];
- }
- /**
- * @param MethodCall $node
- */
- public function refactor(Node $node) : ?Node
- {
- $class = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$class instanceof Class_) {
- return null;
- }
- $isMethodCallCurrentClass = $this->isMethodCallCurrentClass($node);
- if (!$node->var instanceof PropertyFetch && !$isMethodCallCurrentClass) {
- return null;
- }
- foreach ($this->methodCallsToMethodsCalls as $methodCallToMethodCall) {
- if (!$this->isMatch($node, $methodCallToMethodCall, $isMethodCallCurrentClass, $class)) {
- continue;
- }
- $newPropertyName = $this->matchNewPropertyName($methodCallToMethodCall, $class);
- if ($newPropertyName === null) {
- continue;
- }
- /** @var PropertyFetch $propertyFetch */
- $propertyFetch = $isMethodCallCurrentClass ? $node : $node->var;
- $newObjectType = new ObjectType($methodCallToMethodCall->getNewType());
- $propertyMetadata = new PropertyMetadata($newPropertyName, $newObjectType, Class_::MODIFIER_PRIVATE);
- $this->propertyToAddCollector->addPropertyToClass($class, $propertyMetadata);
- // rename property
- $node->var = new PropertyFetch($propertyFetch->var, $newPropertyName);
- // rename method
- $node->name = new Identifier($methodCallToMethodCall->getNewMethod());
- return $node;
- }
- return null;
- }
- /**
- * @param mixed[] $configuration
- */
- public function configure(array $configuration) : void
- {
- Assert::allIsAOf($configuration, MethodCallToMethodCall::class);
- $this->methodCallsToMethodsCalls = $configuration;
- }
- private function isMethodCallCurrentClass(MethodCall $methodCall) : bool
- {
- return $methodCall->var instanceof Variable && $methodCall->var->name === 'this';
- }
- private function isMatch(MethodCall $methodCall, MethodCallToMethodCall $methodCallToMethodCall, bool $isMethodCallCurrentClass, Class_ $class) : bool
- {
- $oldTypeObject = new ObjectType($methodCallToMethodCall->getOldType());
- if ($isMethodCallCurrentClass) {
- $className = (string) $this->nodeNameResolver->getName($class);
- $objectType = new ObjectType($className);
- if (!$objectType->equals($oldTypeObject)) {
- return \false;
- }
- return $this->isName($methodCall->name, $methodCallToMethodCall->getOldMethod());
- }
- if (!$this->isName($methodCall->name, $methodCallToMethodCall->getOldMethod())) {
- return \false;
- }
- return $this->isObjectType($methodCall->var, $oldTypeObject);
- }
- private function matchNewPropertyName(MethodCallToMethodCall $methodCallToMethodCall, Class_ $class) : ?string
- {
- $newPropertyName = $this->propertyNaming->fqnToVariableName($methodCallToMethodCall->getNewType());
- $propertyMetadata = new PropertyMetadata($newPropertyName, new ObjectType($methodCallToMethodCall->getNewType()), Class_::MODIFIER_PRIVATE);
- $classContextProperty = $this->propertyPresenceChecker->getClassContextProperty($class, $propertyMetadata);
- if ($classContextProperty === null) {
- return $newPropertyName;
- }
- // re-use existing property name
- return $this->getName($classContextProperty);
- }
-}
diff --git a/rules/Transform/Rector/New_/NewArgToMethodCallRector.php b/rules/Transform/Rector/New_/NewArgToMethodCallRector.php
deleted file mode 100644
index e29572defc34..000000000000
--- a/rules/Transform/Rector/New_/NewArgToMethodCallRector.php
+++ /dev/null
@@ -1,89 +0,0 @@
-usePutenv();
- }
-}
-CODE_SAMPLE
-, [new NewArgToMethodCall('Dotenv', \true, 'usePutenv')])]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [New_::class];
- }
- /**
- * @param New_ $node
- */
- public function refactor(Node $node) : ?Node
- {
- foreach ($this->newArgsToMethodCalls as $newArgToMethodCall) {
- if (!$this->isObjectType($node->class, $newArgToMethodCall->getObjectType())) {
- continue;
- }
- if (!isset($node->getArgs()[0])) {
- return null;
- }
- if (!$node->args[0] instanceof Arg) {
- return null;
- }
- $firstArgValue = $node->args[0]->value;
- if (!$this->valueResolver->isValue($firstArgValue, $newArgToMethodCall->getValue())) {
- continue;
- }
- unset($node->args[0]);
- return new MethodCall($node, $newArgToMethodCall->getMethodCall());
- }
- return null;
- }
- /**
- * @param mixed[] $configuration
- */
- public function configure(array $configuration) : void
- {
- Assert::allIsAOf($configuration, NewArgToMethodCall::class);
- $this->newArgsToMethodCalls = $configuration;
- }
-}
diff --git a/rules/Transform/Rector/New_/NewToConstructorInjectionRector.php b/rules/Transform/Rector/New_/NewToConstructorInjectionRector.php
deleted file mode 100644
index 0ca0a9de9cbb..000000000000
--- a/rules/Transform/Rector/New_/NewToConstructorInjectionRector.php
+++ /dev/null
@@ -1,172 +0,0 @@
-propertyFetchFactory = $propertyFetchFactory;
- $this->propertyNaming = $propertyNaming;
- $this->propertyToAddCollector = $propertyToAddCollector;
- }
- public function getRuleDefinition() : RuleDefinition
- {
- return new RuleDefinition('Change defined new type to constructor injection', [new ConfiguredCodeSample(<<<'CODE_SAMPLE'
-class SomeClass
-{
- public function run()
- {
- $validator = new Validator();
- $validator->validate(1000);
- }
-}
-CODE_SAMPLE
-, <<<'CODE_SAMPLE'
-class SomeClass
-{
- /**
- * @var Validator
- */
- private $validator;
-
- public function __construct(Validator $validator)
- {
- $this->validator = $validator;
- }
-
- public function run()
- {
- $this->validator->validate(1000);
- }
-}
-CODE_SAMPLE
-, ['Validator'])]);
- }
- /**
- * @return array>
- */
- public function getNodeTypes() : array
- {
- return [New_::class, Assign::class, MethodCall::class, Expression::class];
- }
- /**
- * @param New_|Assign|MethodCall|Expression $node
- */
- public function refactor(Node $node) : ?Node
- {
- if ($node instanceof MethodCall) {
- return $this->refactorMethodCall($node);
- }
- if ($node instanceof Expression) {
- $nodeExpr = $node->expr;
- if ($nodeExpr instanceof Assign) {
- $this->refactorAssignExpression($node, $nodeExpr);
- }
- }
- if ($node instanceof New_) {
- $this->refactorNew($node);
- }
- return null;
- }
- /**
- * @param mixed[] $configuration
- */
- public function configure(array $configuration) : void
- {
- $typesToConstructorInjections = $configuration;
- Assert::allString($typesToConstructorInjections);
- foreach ($typesToConstructorInjections as $typeToConstructorInjection) {
- $this->constructorInjectionObjectTypes[] = new ObjectType($typeToConstructorInjection);
- }
- }
- private function refactorMethodCall(MethodCall $methodCall) : ?MethodCall
- {
- foreach ($this->constructorInjectionObjectTypes as $constructorInjectionObjectType) {
- if (!$methodCall->var instanceof Variable) {
- continue;
- }
- if (!$this->isObjectType($methodCall->var, $constructorInjectionObjectType)) {
- continue;
- }
- if (!$this->nodeTypeResolver->isObjectType($methodCall->var, $constructorInjectionObjectType)) {
- continue;
- }
- $methodCall->var = $this->propertyFetchFactory->createFromType($constructorInjectionObjectType);
- return $methodCall;
- }
- return null;
- }
- private function refactorAssignExpression(Expression $expression, Assign $assign) : void
- {
- $currentAssign = $assign->expr instanceof Assign ? $assign->expr : $assign;
- if (!$currentAssign->expr instanceof New_) {
- return;
- }
- foreach ($this->constructorInjectionObjectTypes as $constructorInjectionObjectType) {
- if (!$this->isObjectType($currentAssign->expr, $constructorInjectionObjectType)) {
- continue;
- }
- $this->removeNode($expression);
- }
- }
- private function refactorNew(New_ $new) : void
- {
- foreach ($this->constructorInjectionObjectTypes as $constructorInjectionObjectType) {
- if (!$this->isObjectType($new->class, $constructorInjectionObjectType)) {
- continue;
- }
- $classLike = $this->betterNodeFinder->findParentType($new, Class_::class);
- if (!$classLike instanceof Class_) {
- continue;
- }
- $expectedPropertyName = $this->propertyNaming->getExpectedNameFromType($constructorInjectionObjectType);
- if (!$expectedPropertyName instanceof ExpectedName) {
- continue;
- }
- $propertyMetadata = new PropertyMetadata($expectedPropertyName->getName(), $constructorInjectionObjectType, Class_::MODIFIER_PRIVATE);
- $this->propertyToAddCollector->addPropertyToClass($classLike, $propertyMetadata);
- }
- }
-}
diff --git a/rules/Transform/Rector/StaticCall/StaticCallToFuncCallRector.php b/rules/Transform/Rector/StaticCall/StaticCallToFuncCallRector.php
index 75c166dd3655..57d989720e01 100644
--- a/rules/Transform/Rector/StaticCall/StaticCallToFuncCallRector.php
+++ b/rules/Transform/Rector/StaticCall/StaticCallToFuncCallRector.php
@@ -22,13 +22,6 @@ final class StaticCallToFuncCallRector extends AbstractRector implements Configu
* @var StaticCallToFuncCall[]
*/
private $staticCallsToFunctions = [];
- /**
- * @param StaticCallToFuncCall[] $staticCallsToFunctions
- */
- public function __construct(array $staticCallsToFunctions = [])
- {
- $this->staticCallsToFunctions = $staticCallsToFunctions;
- }
public function getRuleDefinition() : RuleDefinition
{
return new RuleDefinition('Turns static call to function call.', [new ConfiguredCodeSample('OldClass::oldMethod("args");', 'new_function("args");', [new StaticCallToFuncCall('OldClass', 'oldMethod', 'new_function')])]);
diff --git a/rules/Transform/Rector/StaticCall/StaticCallToMethodCallRector.php b/rules/Transform/Rector/StaticCall/StaticCallToMethodCallRector.php
index ef7de0893a75..5be2c1672d06 100644
--- a/rules/Transform/Rector/StaticCall/StaticCallToMethodCallRector.php
+++ b/rules/Transform/Rector/StaticCall/StaticCallToMethodCallRector.php
@@ -9,7 +9,6 @@
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use Rector\Core\Contract\Rector\ConfigurableRectorInterface;
use Rector\Core\Exception\ShouldNotHappenException;
@@ -24,15 +23,15 @@
*/
final class StaticCallToMethodCallRector extends AbstractScopeAwareRector implements ConfigurableRectorInterface
{
- /**
- * @var StaticCallToMethodCall[]
- */
- private $staticCallsToMethodCalls = [];
/**
* @readonly
* @var \Rector\Transform\NodeAnalyzer\FuncCallStaticCallToMethodCallAnalyzer
*/
private $funcCallStaticCallToMethodCallAnalyzer;
+ /**
+ * @var StaticCallToMethodCall[]
+ */
+ private $staticCallsToMethodCalls = [];
public function __construct(FuncCallStaticCallToMethodCallAnalyzer $funcCallStaticCallToMethodCallAnalyzer)
{
$this->funcCallStaticCallToMethodCallAnalyzer = $funcCallStaticCallToMethodCallAnalyzer;
@@ -78,40 +77,46 @@ public function run()
*/
public function getNodeTypes() : array
{
- return [StaticCall::class];
+ return [Class_::class];
}
/**
- * @param StaticCall $node
+ * @param Class_ $node
*/
public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
- $classLike = $this->betterNodeFinder->findParentType($node, Class_::class);
- if (!$classLike instanceof Class_) {
- return null;
- }
- $classMethod = $this->betterNodeFinder->findParentType($node, ClassMethod::class);
- if (!$classMethod instanceof ClassMethod) {
- return null;
+ $class = $node;
+ $hasChanged = \false;
+ foreach ($node->getMethods() as $classMethod) {
+ $this->traverseNodesWithCallable($classMethod, function (Node $node) use($class, $classMethod, &$hasChanged) {
+ if (!$node instanceof StaticCall) {
+ return null;
+ }
+ foreach ($this->staticCallsToMethodCalls as $staticCallToMethodCall) {
+ if (!$staticCallToMethodCall->isStaticCallMatch($node)) {
+ continue;
+ }
+ if ($classMethod->isStatic()) {
+ return $this->refactorToInstanceCall($node, $staticCallToMethodCall);
+ }
+ $expr = $this->funcCallStaticCallToMethodCallAnalyzer->matchTypeProvidingExpr($class, $classMethod, $staticCallToMethodCall->getClassObjectType());
+ if ($staticCallToMethodCall->getMethodName() === '*') {
+ $methodName = $this->getName($node->name);
+ } else {
+ $methodName = $staticCallToMethodCall->getMethodName();
+ }
+ if (!\is_string($methodName)) {
+ throw new ShouldNotHappenException();
+ }
+ $hasChanged = \true;
+ return new MethodCall($expr, $methodName, $node->args);
+ }
+ return $node;
+ });
}
- foreach ($this->staticCallsToMethodCalls as $staticCallToMethodCall) {
- if (!$staticCallToMethodCall->isStaticCallMatch($node)) {
- continue;
- }
- if ($classMethod->isStatic()) {
- return $this->refactorToInstanceCall($node, $staticCallToMethodCall);
- }
- $expr = $this->funcCallStaticCallToMethodCallAnalyzer->matchTypeProvidingExpr($classLike, $classMethod, $staticCallToMethodCall->getClassObjectType(), $scope);
- if ($staticCallToMethodCall->getMethodName() === '*') {
- $methodName = $this->getName($node->name);
- } else {
- $methodName = $staticCallToMethodCall->getMethodName();
- }
- if (!\is_string($methodName)) {
- throw new ShouldNotHappenException();
- }
- return new MethodCall($expr, $methodName, $node->args);
+ if ($hasChanged) {
+ return $node;
}
- return $node;
+ return null;
}
/**
* @param mixed[] $configuration
diff --git a/rules/Transform/ValueObject/MethodCallToMethodCall.php b/rules/Transform/ValueObject/MethodCallToMethodCall.php
deleted file mode 100644
index 68256e1db1ae..000000000000
--- a/rules/Transform/ValueObject/MethodCallToMethodCall.php
+++ /dev/null
@@ -1,56 +0,0 @@
-oldType = $oldType;
- $this->oldMethod = $oldMethod;
- $this->newType = $newType;
- $this->newMethod = $newMethod;
- RectorAssert::className($oldType);
- RectorAssert::methodName($oldMethod);
- RectorAssert::className($newType);
- RectorAssert::methodName($newMethod);
- }
- public function getOldType() : string
- {
- return $this->oldType;
- }
- public function getOldMethod() : string
- {
- return $this->oldMethod;
- }
- public function getNewType() : string
- {
- return $this->newType;
- }
- public function getNewMethod() : string
- {
- return $this->newMethod;
- }
-}
diff --git a/rules/Transform/ValueObject/NewArgToMethodCall.php b/rules/Transform/ValueObject/NewArgToMethodCall.php
deleted file mode 100644
index 251ea115aac7..000000000000
--- a/rules/Transform/ValueObject/NewArgToMethodCall.php
+++ /dev/null
@@ -1,51 +0,0 @@
-type = $type;
- $this->value = $value;
- $this->methodCall = $methodCall;
- RectorAssert::className($type);
- RectorAssert::className($methodCall);
- }
- public function getObjectType() : ObjectType
- {
- return new ObjectType($this->type);
- }
- /**
- * @return mixed
- */
- public function getValue()
- {
- return $this->value;
- }
- public function getMethodCall() : string
- {
- return $this->methodCall;
- }
-}
diff --git a/rules/Transform/ValueObject/UnsetAndIssetToMethodCall.php b/rules/Transform/ValueObject/UnsetAndIssetToMethodCall.php
deleted file mode 100644
index 6262b28bec75..000000000000
--- a/rules/Transform/ValueObject/UnsetAndIssetToMethodCall.php
+++ /dev/null
@@ -1,46 +0,0 @@
-type = $type;
- $this->issetMethodCall = $issetMethodCall;
- $this->unsedMethodCall = $unsedMethodCall;
- RectorAssert::className($type);
- RectorAssert::methodName($issetMethodCall);
- RectorAssert::methodName($unsedMethodCall);
- }
- public function getObjectType() : ObjectType
- {
- return new ObjectType($this->type);
- }
- public function getIssetMethodCall() : string
- {
- return $this->issetMethodCall;
- }
- public function getUnsedMethodCall() : string
- {
- return $this->unsedMethodCall;
- }
-}
diff --git a/rules/TypeDeclaration/AlreadyAssignDetector/ConstructorAssignDetector.php b/rules/TypeDeclaration/AlreadyAssignDetector/ConstructorAssignDetector.php
index fb27961d9849..2f85d3312dc6 100644
--- a/rules/TypeDeclaration/AlreadyAssignDetector/ConstructorAssignDetector.php
+++ b/rules/TypeDeclaration/AlreadyAssignDetector/ConstructorAssignDetector.php
@@ -15,15 +15,10 @@
use Rector\Core\ValueObject\MethodName;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser;
-use Rector\PostRector\Collector\NodesToRemoveCollector;
use Rector\TypeDeclaration\Matcher\PropertyAssignMatcher;
use Rector\TypeDeclaration\NodeAnalyzer\AutowiredClassMethodOrPropertyAnalyzer;
final class ConstructorAssignDetector
{
- /**
- * @var string
- */
- private const IS_FIRST_LEVEL_STATEMENT = 'first_level_stmt';
/**
* @readonly
* @var \Rector\NodeTypeResolver\NodeTypeResolver
@@ -50,18 +45,16 @@ final class ConstructorAssignDetector
*/
private $propertyFetchAnalyzer;
/**
- * @readonly
- * @var \Rector\PostRector\Collector\NodesToRemoveCollector
+ * @var string
*/
- private $nodesToRemoveCollector;
- public function __construct(NodeTypeResolver $nodeTypeResolver, PropertyAssignMatcher $propertyAssignMatcher, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, AutowiredClassMethodOrPropertyAnalyzer $autowiredClassMethodOrPropertyAnalyzer, PropertyFetchAnalyzer $propertyFetchAnalyzer, NodesToRemoveCollector $nodesToRemoveCollector)
+ private const IS_FIRST_LEVEL_STATEMENT = 'first_level_stmt';
+ public function __construct(NodeTypeResolver $nodeTypeResolver, PropertyAssignMatcher $propertyAssignMatcher, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, AutowiredClassMethodOrPropertyAnalyzer $autowiredClassMethodOrPropertyAnalyzer, PropertyFetchAnalyzer $propertyFetchAnalyzer)
{
$this->nodeTypeResolver = $nodeTypeResolver;
$this->propertyAssignMatcher = $propertyAssignMatcher;
$this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
$this->autowiredClassMethodOrPropertyAnalyzer = $autowiredClassMethodOrPropertyAnalyzer;
$this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
- $this->nodesToRemoveCollector = $nodesToRemoveCollector;
}
public function isPropertyAssigned(ClassLike $classLike, string $propertyName) : bool
{
@@ -73,9 +66,6 @@ public function isPropertyAssigned(ClassLike $classLike, string $propertyName) :
$this->decorateFirstLevelStatementAttribute($initializeClassMethods);
foreach ($initializeClassMethods as $initializeClassMethod) {
$this->simpleCallableNodeTraverser->traverseNodesWithCallable((array) $initializeClassMethod->stmts, function (Node $node) use($propertyName, &$isAssignedInConstructor) : ?int {
- if ($node instanceof Expression && $this->nodesToRemoveCollector->isNodeRemoved($node)) {
- return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
- }
$expr = $this->matchAssignExprToPropertyName($node, $propertyName);
if (!$expr instanceof Expr) {
return null;
@@ -88,7 +78,7 @@ public function isPropertyAssigned(ClassLike $classLike, string $propertyName) :
return null;
}
$isAssignedInConstructor = \true;
- return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
+ return NodeTraverser::STOP_TRAVERSAL;
});
}
if (!$isAssignedInConstructor) {
diff --git a/rules/TypeDeclaration/AlreadyAssignDetector/NullTypeAssignDetector.php b/rules/TypeDeclaration/AlreadyAssignDetector/NullTypeAssignDetector.php
index 4f8f418b1741..8727467f094e 100644
--- a/rules/TypeDeclaration/AlreadyAssignDetector/NullTypeAssignDetector.php
+++ b/rules/TypeDeclaration/AlreadyAssignDetector/NullTypeAssignDetector.php
@@ -8,7 +8,6 @@
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\NodeTraverser;
-use Rector\NodeNestingScope\ScopeNestingComparator;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser;
use Rector\PHPStanStaticTypeMapper\DoctrineTypeAnalyzer;
@@ -18,11 +17,6 @@
*/
final class NullTypeAssignDetector
{
- /**
- * @readonly
- * @var \Rector\NodeNestingScope\ScopeNestingComparator
- */
- private $scopeNestingComparator;
/**
* @readonly
* @var \Rector\PHPStanStaticTypeMapper\DoctrineTypeAnalyzer
@@ -43,9 +37,8 @@ final class NullTypeAssignDetector
* @var \Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser
*/
private $simpleCallableNodeTraverser;
- public function __construct(ScopeNestingComparator $scopeNestingComparator, DoctrineTypeAnalyzer $doctrineTypeAnalyzer, NodeTypeResolver $nodeTypeResolver, PropertyAssignMatcher $propertyAssignMatcher, SimpleCallableNodeTraverser $simpleCallableNodeTraverser)
+ public function __construct(DoctrineTypeAnalyzer $doctrineTypeAnalyzer, NodeTypeResolver $nodeTypeResolver, PropertyAssignMatcher $propertyAssignMatcher, SimpleCallableNodeTraverser $simpleCallableNodeTraverser)
{
- $this->scopeNestingComparator = $scopeNestingComparator;
$this->doctrineTypeAnalyzer = $doctrineTypeAnalyzer;
$this->nodeTypeResolver = $nodeTypeResolver;
$this->propertyAssignMatcher = $propertyAssignMatcher;
@@ -59,10 +52,6 @@ public function detect(ClassLike $classLike, string $propertyName) : bool
if (!$expr instanceof Expr) {
return null;
}
- if ($this->scopeNestingComparator->isNodeConditionallyScoped($expr)) {
- $needsNullType = \true;
- return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
- }
// not in doctrine property
$staticType = $this->nodeTypeResolver->getType($expr);
if ($this->doctrineTypeAnalyzer->isDoctrineCollectionWithIterableUnionType($staticType)) {
diff --git a/rules/TypeDeclaration/Guard/PhpDocNestedAnnotationGuard.php b/rules/TypeDeclaration/Guard/PhpDocNestedAnnotationGuard.php
index ce110c8ab74e..c0e5e5e11d25 100644
--- a/rules/TypeDeclaration/Guard/PhpDocNestedAnnotationGuard.php
+++ b/rules/TypeDeclaration/Guard/PhpDocNestedAnnotationGuard.php
@@ -10,6 +10,11 @@
use Rector\NodeTypeResolver\Node\AttributeKey;
final class PhpDocNestedAnnotationGuard
{
+ /**
+ * @readonly
+ * @var \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory
+ */
+ private $phpDocInfoFactory;
/**
* Regex is used to count annotations including nested annotations
*
@@ -17,11 +22,6 @@ final class PhpDocNestedAnnotationGuard
* @var string
*/
private const SIMPLE_ANNOTATION_REGEX = '/@[A-z]+\\(?/i';
- /**
- * @readonly
- * @var \Rector\BetterPhpDocParser\PhpDocInfo\PhpDocInfoFactory
- */
- private $phpDocInfoFactory;
public function __construct(PhpDocInfoFactory $phpDocInfoFactory)
{
$this->phpDocInfoFactory = $phpDocInfoFactory;
diff --git a/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictScalarReturnTypeAnalyzer.php b/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictScalarReturnTypeAnalyzer.php
index 046aea5f12c6..c0ef2adbb82c 100644
--- a/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictScalarReturnTypeAnalyzer.php
+++ b/rules/TypeDeclaration/NodeAnalyzer/ReturnTypeAnalyzer/StrictScalarReturnTypeAnalyzer.php
@@ -7,6 +7,7 @@
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
+use PHPStan\Analyser\Scope;
use PHPStan\Type\Type;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\TypeDeclaration\TypeAnalyzer\AlwaysStrictScalarExprAnalyzer;
@@ -36,7 +37,7 @@ public function __construct(\Rector\TypeDeclaration\NodeAnalyzer\ReturnTypeAnaly
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Stmt\Function_ $functionLike
*/
- public function matchAlwaysScalarReturnType($functionLike) : ?Type
+ public function matchAlwaysScalarReturnType($functionLike, Scope $scope) : ?Type
{
$returns = $this->alwaysStrictReturnAnalyzer->matchAlwaysStrictReturns($functionLike);
if ($returns === null) {
@@ -48,7 +49,7 @@ public function matchAlwaysScalarReturnType($functionLike) : ?Type
if (!$return->expr instanceof Expr) {
return null;
}
- $scalarType = $this->alwaysStrictScalarExprAnalyzer->matchStrictScalarExpr($return->expr);
+ $scalarType = $this->alwaysStrictScalarExprAnalyzer->matchStrictScalarExpr($return->expr, $scope);
if (!$scalarType instanceof Type) {
return null;
}
diff --git a/rules/TypeDeclaration/NodeTypeAnalyzer/PropertyTypeDecorator.php b/rules/TypeDeclaration/NodeTypeAnalyzer/PropertyTypeDecorator.php
index d0af8fa0e197..b7b79310c4ee 100644
--- a/rules/TypeDeclaration/NodeTypeAnalyzer/PropertyTypeDecorator.php
+++ b/rules/TypeDeclaration/NodeTypeAnalyzer/PropertyTypeDecorator.php
@@ -56,7 +56,7 @@ public function decoratePropertyUnionType(UnionType $unionType, $typeNode, Prope
return;
}
if ($changeVarTypeFallback) {
- $this->phpDocTypeChanger->changeVarType($phpDocInfo, $unionType);
+ $this->phpDocTypeChanger->changeVarType($property, $phpDocInfo, $unionType);
}
return;
}
@@ -73,7 +73,7 @@ public function decoratePropertyUnionType(UnionType $unionType, $typeNode, Prope
if (!$changeVarTypeFallback) {
return;
}
- $this->phpDocTypeChanger->changeVarType($phpDocInfo, $unionType);
+ $this->phpDocTypeChanger->changeVarType($property, $phpDocInfo, $unionType);
}
private function isDocBlockRequired(UnionType $unionType) : bool
{
diff --git a/rules/TypeDeclaration/PHPStan/ObjectTypeSpecifier.php b/rules/TypeDeclaration/PHPStan/ObjectTypeSpecifier.php
index b808ba4233c4..fcd7ef0d7a12 100644
--- a/rules/TypeDeclaration/PHPStan/ObjectTypeSpecifier.php
+++ b/rules/TypeDeclaration/PHPStan/ObjectTypeSpecifier.php
@@ -5,8 +5,6 @@
use RectorPrefix202306\Nette\Utils\Strings;
use PhpParser\Node;
-use PhpParser\Node\Expr\MethodCall;
-use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Use_;
@@ -26,6 +24,8 @@
use Rector\StaticTypeMapper\ValueObject\Type\ShortenedGenericObjectType;
use Rector\StaticTypeMapper\ValueObject\Type\ShortenedObjectType;
use Rector\TypeDeclaration\Contract\PHPStan\TypeWithClassTypeSpecifierInterface;
+use Rector\TypeDeclaration\PHPStan\TypeSpecifier\SameNamespacedTypeSpecifier;
+use Rector\TypeDeclaration\PHPStan\TypeSpecifier\SelfStaticParentTypeSpecifier;
final class ObjectTypeSpecifier
{
/**
@@ -40,25 +40,19 @@ final class ObjectTypeSpecifier
private $useImportsResolver;
/**
* @var TypeWithClassTypeSpecifierInterface[]
- * @readonly
- */
- private $typeWithClassTypeSpecifiers;
- /**
- * @param TypeWithClassTypeSpecifierInterface[] $typeWithClassTypeSpecifiers
*/
- public function __construct(ReflectionProvider $reflectionProvider, UseImportsResolver $useImportsResolver, array $typeWithClassTypeSpecifiers)
+ private $typeWithClassTypeSpecifiers = [];
+ public function __construct(ReflectionProvider $reflectionProvider, UseImportsResolver $useImportsResolver, SelfStaticParentTypeSpecifier $selfStaticParentTypeSpecifier, SameNamespacedTypeSpecifier $sameNamespacedTypeSpecifier)
{
$this->reflectionProvider = $reflectionProvider;
$this->useImportsResolver = $useImportsResolver;
- $this->typeWithClassTypeSpecifiers = $typeWithClassTypeSpecifiers;
+ $this->typeWithClassTypeSpecifiers = [$selfStaticParentTypeSpecifier, $sameNamespacedTypeSpecifier];
}
/**
* @return \PHPStan\Type\TypeWithClassName|\Rector\StaticTypeMapper\ValueObject\Type\NonExistingObjectType|\PHPStan\Type\UnionType|\PHPStan\Type\MixedType
*/
public function narrowToFullyQualifiedOrAliasedObjectType(Node $node, ObjectType $objectType, ?\PHPStan\Analyser\Scope $scope)
{
- // $nameScope = $this->nameScopeFactory->createNameScopeFromNodeWithoutTemplateTypes($node);
- // @todo reuse name scope
if ($scope instanceof Scope) {
foreach ($this->typeWithClassTypeSpecifiers as $typeWithClassTypeSpecifier) {
if ($typeWithClassTypeSpecifier->match($objectType, $scope)) {
@@ -66,7 +60,7 @@ public function narrowToFullyQualifiedOrAliasedObjectType(Node $node, ObjectType
}
}
}
- $uses = $this->useImportsResolver->resolveForNode($node);
+ $uses = $this->useImportsResolver->resolve();
if ($uses === []) {
if (!$this->reflectionProvider->hasClass($objectType->getClassName())) {
return new NonExistingObjectType($objectType->getClassName());
@@ -97,7 +91,7 @@ private function matchAliasedObjectType(Node $node, ObjectType $objectType, arra
return null;
}
$className = $objectType->getClassName();
- $parentNode = $node->getAttribute(AttributeKey::PARENT_NODE);
+ $isObjectCaller = $node->getAttribute(AttributeKey::IS_OBJECT_CALLER) === \true;
foreach ($uses as $use) {
$prefix = $this->useImportsResolver->resolvePrefix($use);
foreach ($use->uses as $useUse) {
@@ -107,7 +101,7 @@ private function matchAliasedObjectType(Node $node, ObjectType $objectType, arra
$useName = $prefix . $useUse->name->toString();
$alias = $useUse->alias->toString();
$fullyQualifiedName = $prefix . $useUse->name->toString();
- $processAliasedObject = $this->processAliasedObject($alias, $className, $useName, $parentNode, $fullyQualifiedName);
+ $processAliasedObject = $this->processAliasedObject($alias, $className, $useName, $fullyQualifiedName, $isObjectCaller);
if ($processAliasedObject instanceof AliasedObjectType) {
return $processAliasedObject;
}
@@ -115,14 +109,14 @@ private function matchAliasedObjectType(Node $node, ObjectType $objectType, arra
}
return null;
}
- private function processAliasedObject(string $alias, string $className, string $useName, ?Node $parentNode, string $fullyQualifiedName) : ?AliasedObjectType
+ private function processAliasedObject(string $alias, string $className, string $useName, string $fullyQualifiedName, bool $isObjectCaller) : ?AliasedObjectType
{
// A. is alias in use statement matching this class alias
if ($alias === $className) {
return new AliasedObjectType($alias, $fullyQualifiedName);
}
// B. is aliased classes matching the class name and parent node is MethodCall/StaticCall
- if ($useName === $className && ($parentNode instanceof MethodCall || $parentNode instanceof StaticCall)) {
+ if ($useName === $className && $isObjectCaller) {
return new AliasedObjectType($useName, $fullyQualifiedName);
}
// C. is aliased classes matching the class name
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector.php b/rules/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector.php
index 5851669edbef..4639c8a82473 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/AddMethodCallBasedStrictParamTypeRector.php
@@ -4,6 +4,7 @@
namespace Rector\TypeDeclaration\Rector\ClassMethod;
use PhpParser\Node;
+use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\PhpParser\NodeFinder\LocalMethodCallFinder;
use Rector\Core\Rector\AbstractRector;
@@ -18,10 +19,6 @@
*/
final class AddMethodCallBasedStrictParamTypeRector extends AbstractRector
{
- /**
- * @var int
- */
- private const MAX_UNION_TYPES = 3;
/**
* @readonly
* @var \Rector\TypeDeclaration\NodeAnalyzer\CallTypesResolver
@@ -37,6 +34,10 @@ final class AddMethodCallBasedStrictParamTypeRector extends AbstractRector
* @var \Rector\Core\PhpParser\NodeFinder\LocalMethodCallFinder
*/
private $localMethodCallFinder;
+ /**
+ * @var int
+ */
+ private const MAX_UNION_TYPES = 3;
public function __construct(CallTypesResolver $callTypesResolver, ClassMethodParamTypeCompleter $classMethodParamTypeCompleter, LocalMethodCallFinder $localMethodCallFinder)
{
$this->callTypesResolver = $callTypesResolver;
@@ -78,21 +79,31 @@ private function resolve(int $value)
*/
public function getNodeTypes() : array
{
- return [ClassMethod::class];
+ return [Class_::class];
}
/**
- * @param ClassMethod $node
+ * @param Class_ $node
*/
public function refactor(Node $node) : ?Node
{
- if ($node->params === []) {
- return null;
+ $hasChanged = \false;
+ foreach ($node->getMethods() as $method) {
+ if ($method->params === []) {
+ continue;
+ }
+ if (!$method->isPrivate()) {
+ continue;
+ }
+ $methodCalls = $this->localMethodCallFinder->match($node, $method);
+ $classMethodParameterTypes = $this->callTypesResolver->resolveStrictTypesFromCalls($methodCalls);
+ $classMethod = $this->classMethodParamTypeCompleter->complete($method, $classMethodParameterTypes, self::MAX_UNION_TYPES);
+ if ($classMethod instanceof ClassMethod) {
+ $hasChanged = \true;
+ }
}
- if (!$node->isPrivate()) {
- return null;
+ if ($hasChanged) {
+ return $node;
}
- $methodCalls = $this->localMethodCallFinder->match($node);
- $classMethodParameterTypes = $this->callTypesResolver->resolveStrictTypesFromCalls($methodCalls);
- return $this->classMethodParamTypeCompleter->complete($node, $classMethodParameterTypes, self::MAX_UNION_TYPES);
+ return null;
}
}
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeBasedOnPHPUnitDataProviderRector.php b/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeBasedOnPHPUnitDataProviderRector.php
index dd0a3d6111c4..27d862b32b18 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeBasedOnPHPUnitDataProviderRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeBasedOnPHPUnitDataProviderRector.php
@@ -31,15 +31,6 @@
*/
final class AddParamTypeBasedOnPHPUnitDataProviderRector extends AbstractRector
{
- /**
- * @var string
- */
- private const ERROR_MESSAGE = 'Adds param type declaration based on PHPUnit provider return type declaration';
- /**
- * @see https://regex101.com/r/hW09Vt/1
- * @var string
- */
- private const METHOD_NAME_REGEX = '#^(?\\w+)(\\(\\))?#';
/**
* @readonly
* @var \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory
@@ -50,6 +41,15 @@ final class AddParamTypeBasedOnPHPUnitDataProviderRector extends AbstractRector
* @var \Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer
*/
private $testsNodeAnalyzer;
+ /**
+ * @var string
+ */
+ private const ERROR_MESSAGE = 'Adds param type declaration based on PHPUnit provider return type declaration';
+ /**
+ * @see https://regex101.com/r/hW09Vt/1
+ * @var string
+ */
+ private const METHOD_NAME_REGEX = '#^(?\\w+)(\\(\\))?#';
public function __construct(TypeFactory $typeFactory, TestsNodeAnalyzer $testsNodeAnalyzer)
{
$this->typeFactory = $typeFactory;
@@ -100,46 +100,49 @@ public static function provideData()
*/
public function getNodeTypes() : array
{
- return [ClassMethod::class];
+ return [Class_::class];
}
/**
- * @param ClassMethod $node
+ * @param Class_ $node
*/
- public function refactor(Node $node) : ?ClassMethod
+ public function refactor(Node $node)
{
- if (!$node->isPublic()) {
- return null;
- }
- if ($node->getParams() === []) {
- return null;
- }
if (!$this->testsNodeAnalyzer->isInTestClass($node)) {
return null;
}
- $dataProviderPhpDocTagNode = $this->resolveDataProviderPhpDocTagNode($node);
- if (!$dataProviderPhpDocTagNode instanceof PhpDocTagNode) {
- return null;
- }
$hasChanged = \false;
- foreach ($node->getParams() as $param) {
- if ($param->type instanceof Node) {
+ foreach ($node->getMethods() as $classMethod) {
+ if (!$classMethod->isPublic()) {
continue;
}
- $paramTypeDeclaration = $this->inferParam($param, $dataProviderPhpDocTagNode);
- if ($paramTypeDeclaration instanceof MixedType) {
+ if ($classMethod->getParams() === []) {
continue;
}
- $param->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($paramTypeDeclaration, TypeKind::PARAM);
- $hasChanged = \true;
+ $dataProviderPhpDocTagNode = $this->resolveDataProviderPhpDocTagNode($classMethod);
+ if (!$dataProviderPhpDocTagNode instanceof PhpDocTagNode) {
+ return null;
+ }
+ $hasChanged = \false;
+ foreach ($classMethod->getParams() as $param) {
+ if ($param->type instanceof Node) {
+ continue;
+ }
+ $paramTypeDeclaration = $this->inferParam($node, $param, $dataProviderPhpDocTagNode);
+ if ($paramTypeDeclaration instanceof MixedType) {
+ continue;
+ }
+ $param->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($paramTypeDeclaration, TypeKind::PARAM);
+ $hasChanged = \true;
+ }
}
if ($hasChanged) {
return $node;
}
return null;
}
- private function inferParam(Param $param, PhpDocTagNode $dataProviderPhpDocTagNode) : Type
+ private function inferParam(Class_ $class, Param $param, PhpDocTagNode $dataProviderPhpDocTagNode) : Type
{
- $dataProviderClassMethod = $this->resolveDataProviderClassMethod($param, $dataProviderPhpDocTagNode);
+ $dataProviderClassMethod = $this->resolveDataProviderClassMethod($class, $dataProviderPhpDocTagNode);
if (!$dataProviderClassMethod instanceof ClassMethod) {
return new MixedType();
}
@@ -156,12 +159,8 @@ private function inferParam(Param $param, PhpDocTagNode $dataProviderPhpDocTagNo
$yields = $this->betterNodeFinder->findInstanceOf((array) $dataProviderClassMethod->stmts, Yield_::class);
return $this->resolveYieldStaticArrayTypeByParameterPosition($yields, $parameterPosition);
}
- private function resolveDataProviderClassMethod(Param $param, PhpDocTagNode $dataProviderPhpDocTagNode) : ?ClassMethod
+ private function resolveDataProviderClassMethod(Class_ $class, PhpDocTagNode $dataProviderPhpDocTagNode) : ?ClassMethod
{
- $class = $this->betterNodeFinder->findParentType($param, Class_::class);
- if (!$class instanceof Class_) {
- return null;
- }
if (!$dataProviderPhpDocTagNode->value instanceof GenericTagValueNode) {
return null;
}
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeDeclarationRector.php b/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeDeclarationRector.php
index 54f57511aee3..03efa9df1eba 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeDeclarationRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeDeclarationRector.php
@@ -7,7 +7,6 @@
use PhpParser\Node\Name;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Interface_;
use PHPStan\Type\MixedType;
@@ -27,14 +26,6 @@
*/
final class AddParamTypeDeclarationRector extends AbstractRector implements ConfigurableRectorInterface
{
- /**
- * @var AddParamTypeDeclaration[]
- */
- private $addParamTypeDeclarations = [];
- /**
- * @var bool
- */
- private $hasChanged = \false;
/**
* @readonly
* @var \Rector\NodeTypeResolver\TypeComparator\TypeComparator
@@ -45,6 +36,14 @@ final class AddParamTypeDeclarationRector extends AbstractRector implements Conf
* @var \Rector\Core\Php\PhpVersionProvider
*/
private $phpVersionProvider;
+ /**
+ * @var AddParamTypeDeclaration[]
+ */
+ private $addParamTypeDeclarations = [];
+ /**
+ * @var bool
+ */
+ private $hasChanged = \false;
public function __construct(TypeComparator $typeComparator, PhpVersionProvider $phpVersionProvider)
{
$this->typeComparator = $typeComparator;
@@ -75,29 +74,29 @@ public function process(string $name)
*/
public function getNodeTypes() : array
{
- return [ClassMethod::class];
+ return [Class_::class, Interface_::class];
}
/**
- * @param ClassMethod $node
+ * @param Class_|Interface_ $node
*/
public function refactor(Node $node) : ?Node
{
- if ($this->shouldSkip($node)) {
- return null;
- }
- /** @var ClassLike $classLike */
- $classLike = $this->betterNodeFinder->findParentType($node, ClassLike::class);
- foreach ($this->addParamTypeDeclarations as $addParamTypeDeclaration) {
- if (!$this->isName($node, $addParamTypeDeclaration->getMethodName())) {
+ foreach ($node->getMethods() as $classMethod) {
+ if ($this->shouldSkip($node, $classMethod)) {
continue;
}
- if (!$this->isObjectType($classLike, $addParamTypeDeclaration->getObjectType())) {
- continue;
+ foreach ($this->addParamTypeDeclarations as $addParamTypeDeclaration) {
+ if (!$this->isName($classMethod, $addParamTypeDeclaration->getMethodName())) {
+ continue;
+ }
+ if (!$this->isObjectType($node, $addParamTypeDeclaration->getObjectType())) {
+ continue;
+ }
+ $this->refactorClassMethodWithTypehintByParameterPosition($classMethod, $addParamTypeDeclaration);
+ }
+ if (!$this->hasChanged) {
+ return null;
}
- $this->refactorClassMethodWithTypehintByParameterPosition($node, $addParamTypeDeclaration);
- }
- if (!$this->hasChanged) {
- return null;
}
return $node;
}
@@ -109,26 +108,20 @@ public function configure(array $configuration) : void
Assert::allIsAOf($configuration, AddParamTypeDeclaration::class);
$this->addParamTypeDeclarations = $configuration;
}
- private function shouldSkip(ClassMethod $classMethod) : bool
+ /**
+ * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_ $classLike
+ */
+ private function shouldSkip($classLike, ClassMethod $classMethod) : bool
{
// skip class methods without args
if ($classMethod->params === []) {
return \true;
}
- $classLike = $this->betterNodeFinder->findParentByTypes($classMethod, [Class_::class, Interface_::class]);
- if (!$classLike instanceof ClassLike) {
- return \true;
- }
// skip class without parents/interfaces
- if ($classLike instanceof Class_) {
- if ($classLike->implements !== []) {
- return \false;
- }
- return !$classLike->extends instanceof Name;
+ if ($classLike instanceof Class_ && $classLike->implements !== []) {
+ return \false;
}
- // skip interface without parents
- /** @var Interface_ $classLike */
- return !(bool) $classLike->extends;
+ return !$classLike->extends instanceof Name;
}
private function refactorClassMethodWithTypehintByParameterPosition(ClassMethod $classMethod, AddParamTypeDeclaration $addParamTypeDeclaration) : void
{
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeFromPropertyTypeRector.php b/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeFromPropertyTypeRector.php
index 50675586c331..5ab51e9b7b95 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeFromPropertyTypeRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/AddParamTypeFromPropertyTypeRector.php
@@ -25,10 +25,6 @@
*/
final class AddParamTypeFromPropertyTypeRector extends AbstractRector implements MinPhpVersionInterface
{
- /**
- * @var string
- */
- private const ERROR_MESSAGE = 'Adds param type declaration based on property type the value is assigned to PHPUnit provider return type declaration';
/**
* @readonly
* @var \Rector\Core\NodeAnalyzer\PropertyFetchAnalyzer
@@ -44,6 +40,10 @@ final class AddParamTypeFromPropertyTypeRector extends AbstractRector implements
* @var \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory
*/
private $typeFactory;
+ /**
+ * @var string
+ */
+ private const ERROR_MESSAGE = 'Adds param type declaration based on property type the value is assigned to PHPUnit provider return type declaration';
public function __construct(PropertyFetchAnalyzer $propertyFetchAnalyzer, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, TypeFactory $typeFactory)
{
$this->propertyFetchAnalyzer = $propertyFetchAnalyzer;
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/AddReturnTypeDeclarationRector.php b/rules/TypeDeclaration/Rector/ClassMethod/AddReturnTypeDeclarationRector.php
index c39abeed0b00..87f9c3ccc520 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/AddReturnTypeDeclarationRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/AddReturnTypeDeclarationRector.php
@@ -25,14 +25,6 @@
*/
final class AddReturnTypeDeclarationRector extends AbstractRector implements ConfigurableRectorInterface
{
- /**
- * @var AddReturnTypeDeclaration[]
- */
- private $methodReturnTypes = [];
- /**
- * @var bool
- */
- private $hasChanged = \false;
/**
* @readonly
* @var \Rector\Core\Php\PhpVersionProvider
@@ -43,6 +35,14 @@ final class AddReturnTypeDeclarationRector extends AbstractRector implements Con
* @var \Rector\VendorLocker\ParentClassMethodTypeOverrideGuard
*/
private $parentClassMethodTypeOverrideGuard;
+ /**
+ * @var AddReturnTypeDeclaration[]
+ */
+ private $methodReturnTypes = [];
+ /**
+ * @var bool
+ */
+ private $hasChanged = \false;
public function __construct(PhpVersionProvider $phpVersionProvider, ParentClassMethodTypeOverrideGuard $parentClassMethodTypeOverrideGuard)
{
$this->phpVersionProvider = $phpVersionProvider;
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/AddVoidReturnTypeWhereNoReturnRector.php b/rules/TypeDeclaration/Rector/ClassMethod/AddVoidReturnTypeWhereNoReturnRector.php
index 30d9e44edcce..a67e875946b8 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/AddVoidReturnTypeWhereNoReturnRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/AddVoidReturnTypeWhereNoReturnRector.php
@@ -27,15 +27,6 @@
*/
final class AddVoidReturnTypeWhereNoReturnRector extends AbstractRector implements MinPhpVersionInterface, AllowEmptyConfigurableRectorInterface
{
- /**
- * @api
- * @var string using phpdoc instead of a native void type can ease the migration path for consumers of code being processed.
- */
- public const USE_PHPDOC = 'use_phpdoc';
- /**
- * @var bool
- */
- private $usePhpdoc = \false;
/**
* @readonly
* @var \Rector\TypeDeclaration\TypeInferer\SilentVoidResolver
@@ -56,6 +47,15 @@ final class AddVoidReturnTypeWhereNoReturnRector extends AbstractRector implemen
* @var \Rector\Core\Reflection\ReflectionResolver
*/
private $reflectionResolver;
+ /**
+ * @api
+ * @var string using phpdoc instead of a native void type can ease the migration path for consumers of code being processed.
+ */
+ public const USE_PHPDOC = 'use_phpdoc';
+ /**
+ * @var bool
+ */
+ private $usePhpdoc = \false;
public function __construct(SilentVoidResolver $silentVoidResolver, ClassMethodReturnVendorLockResolver $classMethodReturnVendorLockResolver, PhpDocTypeChanger $phpDocTypeChanger, ReflectionResolver $reflectionResolver)
{
$this->silentVoidResolver = $silentVoidResolver;
@@ -135,7 +135,7 @@ public function configure(array $configuration) : void
$this->usePhpdoc = $usePhpdoc;
}
/**
- * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure|\PhpParser\Node $node
+ * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node
*/
private function changePhpDocToVoidIfNotNever($node) : bool
{
@@ -143,7 +143,7 @@ private function changePhpDocToVoidIfNotNever($node) : bool
if ($phpDocInfo->getReturnType() instanceof NeverType) {
return \false;
}
- return $this->phpDocTypeChanger->changeReturnType($phpDocInfo, new VoidType());
+ return $this->phpDocTypeChanger->changeReturnType($node, $phpDocInfo, new VoidType());
}
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $functionLike
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ArrayShapeFromConstantArrayReturnRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ArrayShapeFromConstantArrayReturnRector.php
index ff587242b69a..4bb63cc96d34 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ArrayShapeFromConstantArrayReturnRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ArrayShapeFromConstantArrayReturnRector.php
@@ -19,7 +19,6 @@
use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\Util\StringUtils;
use Rector\PhpDocParser\TypeAnalyzer\ClassMethodReturnTypeResolver;
-use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
@@ -27,11 +26,6 @@
*/
final class ArrayShapeFromConstantArrayReturnRector extends AbstractScopeAwareRector
{
- /**
- * @see https://regex101.com/r/WvUD0m/2
- * @var string
- */
- private const SKIPPED_CHAR_REGEX = '#\\W#u';
/**
* @readonly
* @var \Rector\PhpDocParser\TypeAnalyzer\ClassMethodReturnTypeResolver
@@ -42,6 +36,11 @@ final class ArrayShapeFromConstantArrayReturnRector extends AbstractScopeAwareRe
* @var \Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger
*/
private $phpDocTypeChanger;
+ /**
+ * @see https://regex101.com/r/WvUD0m/2
+ * @var string
+ */
+ private const SKIPPED_CHAR_REGEX = '#\\W#u';
public function __construct(ClassMethodReturnTypeResolver $classMethodReturnTypeResolver, PhpDocTypeChanger $phpDocTypeChanger)
{
$this->classMethodReturnTypeResolver = $classMethodReturnTypeResolver;
@@ -109,14 +108,14 @@ public function refactorWithScope(Node $node, Scope $scope) : ?Node
return null;
}
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
- $returnExprTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($returnExprType, TypeKind::RETURN);
+ $returnExprTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($returnExprType);
if ($returnExprTypeNode instanceof GenericTypeNode) {
return null;
}
if ($returnExprTypeNode instanceof SpacingAwareArrayTypeNode) {
return null;
}
- $hasChanged = $this->phpDocTypeChanger->changeReturnType($phpDocInfo, $returnExprType);
+ $hasChanged = $this->phpDocTypeChanger->changeReturnType($node, $phpDocInfo, $returnExprType);
if (!$hasChanged) {
return null;
}
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/NumericReturnTypeFromStrictScalarReturnsRector.php b/rules/TypeDeclaration/Rector/ClassMethod/NumericReturnTypeFromStrictScalarReturnsRector.php
new file mode 100644
index 000000000000..b3f97f4079ea
--- /dev/null
+++ b/rules/TypeDeclaration/Rector/ClassMethod/NumericReturnTypeFromStrictScalarReturnsRector.php
@@ -0,0 +1,136 @@
+>
+ */
+ public function getNodeTypes() : array
+ {
+ return [ClassMethod::class, Function_::class];
+ }
+ /**
+ * @param ClassMethod|Function_ $node
+ */
+ public function refactor(Node $node) : ?Node
+ {
+ if ($node->returnType instanceof Node) {
+ return null;
+ }
+ if ($node->stmts === null) {
+ return null;
+ }
+ $return = $this->matchRootReturnWithExpr($node);
+ if (!$return instanceof Return_) {
+ return null;
+ }
+ if ($return->expr instanceof PreInc || $return->expr instanceof PostInc || $return->expr instanceof PostDec || $return->expr instanceof PreDec) {
+ $exprType = $this->getType($return->expr);
+ if ($exprType instanceof IntegerType) {
+ $node->returnType = new Identifier('int');
+ return $node;
+ }
+ return null;
+ }
+ // @see https://chat.openai.com/share/a9e4fb74-5366-4c4c-9998-d6caeb8b5acc
+ if ($return->expr instanceof Minus || $return->expr instanceof Plus || $return->expr instanceof Mul || $return->expr instanceof Mod || $return->expr instanceof BitwiseAnd || $return->expr instanceof ShiftRight || $return->expr instanceof ShiftLeft || $return->expr instanceof BitwiseOr) {
+ return $this->refactorBinaryOp($return->expr, $node);
+ }
+ return null;
+ }
+ public function provideMinPhpVersion() : int
+ {
+ return PhpVersionFeature::SCALAR_TYPES;
+ }
+ /**
+ * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_ $functionLike
+ */
+ private function matchRootReturnWithExpr($functionLike) : ?Return_
+ {
+ if ($functionLike->stmts === null) {
+ return null;
+ }
+ foreach ($functionLike->stmts as $stmt) {
+ if (!$stmt instanceof Return_) {
+ continue;
+ }
+ if (!$stmt->expr instanceof Expr) {
+ return null;
+ }
+ return $stmt;
+ }
+ return null;
+ }
+ /**
+ * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_ $functionLike
+ * @return null|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Stmt\ClassMethod
+ */
+ private function refactorBinaryOp(BinaryOp $binaryOp, $functionLike)
+ {
+ $leftType = $this->getType($binaryOp->left);
+ $rightType = $this->getType($binaryOp->right);
+ if ($leftType instanceof IntegerType && $rightType instanceof IntegerType) {
+ $functionLike->returnType = new Identifier('int');
+ return $functionLike;
+ }
+ if ($leftType instanceof FloatType && $rightType instanceof FloatType) {
+ $functionLike->returnType = new Identifier('float');
+ return $functionLike;
+ }
+ return null;
+ }
+}
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ParamAnnotationIncorrectNullableRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ParamAnnotationIncorrectNullableRector.php
index 30ef9211bed9..04416358610a 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ParamAnnotationIncorrectNullableRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ParamAnnotationIncorrectNullableRector.php
@@ -14,7 +14,6 @@
use Rector\Core\Rector\AbstractRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeTypeResolver\TypeComparator\TypeComparator;
-use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\TypeDeclaration\Guard\PhpDocNestedAnnotationGuard;
use Rector\TypeDeclaration\Helper\PhpDocNullableTypeHelper;
use Rector\TypeDeclaration\NodeAnalyzer\ParamAnalyzer;
@@ -124,7 +123,7 @@ private function wasUpdateOfParamTypeRequired(PhpDocInfo $phpDocInfo, Type $newT
if ($phpDocInfo->hasInvalidTag('@param')) {
return \false;
}
- $typeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType, TypeKind::PARAM);
+ $typeNode = $this->staticTypeMapper->mapPHPStanTypeToPHPStanPhpDocTypeNode($newType);
$paramTagValueNode = $phpDocInfo->getParamTagValueByName($paramName);
// override existing type
if ($paramTagValueNode instanceof ParamTagValueNode) {
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ParamTypeByMethodCallTypeRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ParamTypeByMethodCallTypeRector.php
index 210dddffcaea..bfee0a143487 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ParamTypeByMethodCallTypeRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ParamTypeByMethodCallTypeRector.php
@@ -14,14 +14,14 @@
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\Param;
+use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\If_;
use PhpParser\Node\UnionType;
+use PhpParser\NodeTraverser;
use PHPStan\Analyser\Scope;
-use PHPStan\Reflection\ClassReflection;
use Rector\Core\Rector\AbstractScopeAwareRector;
-use Rector\Core\Reflection\ReflectionResolver;
-use Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser;
+use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\TypeDeclaration\NodeAnalyzer\CallerParamMatcher;
use Rector\VendorLocker\ParentClassMethodTypeOverrideGuard;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
@@ -36,27 +36,15 @@ final class ParamTypeByMethodCallTypeRector extends AbstractScopeAwareRector
* @var \Rector\TypeDeclaration\NodeAnalyzer\CallerParamMatcher
*/
private $callerParamMatcher;
- /**
- * @readonly
- * @var \Rector\PhpDocParser\NodeTraverser\SimpleCallableNodeTraverser
- */
- private $simpleCallableNodeTraverser;
/**
* @readonly
* @var \Rector\VendorLocker\ParentClassMethodTypeOverrideGuard
*/
private $parentClassMethodTypeOverrideGuard;
- /**
- * @readonly
- * @var \Rector\Core\Reflection\ReflectionResolver
- */
- private $reflectionResolver;
- public function __construct(CallerParamMatcher $callerParamMatcher, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, ParentClassMethodTypeOverrideGuard $parentClassMethodTypeOverrideGuard, ReflectionResolver $reflectionResolver)
+ public function __construct(CallerParamMatcher $callerParamMatcher, ParentClassMethodTypeOverrideGuard $parentClassMethodTypeOverrideGuard)
{
$this->callerParamMatcher = $callerParamMatcher;
- $this->simpleCallableNodeTraverser = $simpleCallableNodeTraverser;
$this->parentClassMethodTypeOverrideGuard = $parentClassMethodTypeOverrideGuard;
- $this->reflectionResolver = $reflectionResolver;
}
public function getRuleDefinition() : RuleDefinition
{
@@ -109,30 +97,32 @@ public function go(string $value)
*/
public function getNodeTypes() : array
{
- return [ClassMethod::class];
+ return [Class_::class];
}
/**
- * @param ClassMethod $node
+ * @param Class_ $node
*/
public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
- if ($this->shouldSkipClassMethod($node)) {
- return null;
- }
- /** @var array $callers */
- $callers = $this->betterNodeFinder->findInstancesOf((array) $node->stmts, [StaticCall::class, MethodCall::class, FuncCall::class]);
$hasChanged = \false;
- foreach ($node->params as $param) {
- if ($this->shouldSkipParam($param, $node)) {
+ foreach ($node->getMethods() as $classMethod) {
+ if ($this->shouldSkipClassMethod($classMethod)) {
continue;
}
- foreach ($callers as $caller) {
- $paramType = $this->callerParamMatcher->matchCallParamType($caller, $param, $scope);
- if ($paramType === null) {
+ /** @var array $callers */
+ $callers = $this->betterNodeFinder->findInstancesOf($classMethod, [StaticCall::class, MethodCall::class, FuncCall::class]);
+ foreach ($classMethod->params as $param) {
+ if ($this->shouldSkipParam($param, $classMethod)) {
continue;
}
- $this->mirrorParamType($param, $paramType);
- $hasChanged = \true;
+ foreach ($callers as $caller) {
+ $paramType = $this->callerParamMatcher->matchCallParamType($caller, $param, $scope);
+ if ($paramType === null) {
+ continue;
+ }
+ $this->mirrorParamType($param, $paramType);
+ $hasChanged = \true;
+ }
}
}
if ($hasChanged) {
@@ -145,14 +135,7 @@ private function shouldSkipClassMethod(ClassMethod $classMethod) : bool
if ($classMethod->params === []) {
return \true;
}
- if ($this->parentClassMethodTypeOverrideGuard->hasParentClassMethod($classMethod)) {
- return \true;
- }
- $classReflection = $this->reflectionResolver->resolveClassReflection($classMethod);
- if (!$classReflection instanceof ClassReflection) {
- return \true;
- }
- return !$classReflection->isClass();
+ return $this->parentClassMethodTypeOverrideGuard->hasParentClassMethod($classMethod);
}
/**
* @param \PhpParser\Node\Identifier|\PhpParser\Node\Name|\PhpParser\Node\NullableType|\PhpParser\Node\UnionType|\PhpParser\Node\ComplexType $paramType
@@ -161,9 +144,9 @@ private function mirrorParamType(Param $decoratedParam, $paramType) : void
{
// mimic type
$newParamType = $paramType;
- $this->simpleCallableNodeTraverser->traverseNodesWithCallable($newParamType, static function (Node $node) {
- // original attributes have to removed to avoid tokens crashing from origin positions
- $node->setAttributes([]);
+ $this->traverseNodesWithCallable($newParamType, static function (Node $node) {
+ // original node has to removed to avoid tokens crashing from origin positions
+ $node->setAttribute(AttributeKey::ORIGINAL_NODE, null);
return null;
});
$decoratedParam->type = $newParamType;
@@ -177,22 +160,23 @@ private function isParamConditioned(Param $param, ClassMethod $classMethod) : bo
if ($paramName === null) {
return \false;
}
- /** @var Variable[] $variables */
- $variables = $this->betterNodeFinder->findInstanceOf((array) $classMethod->stmts, Variable::class);
- foreach ($variables as $variable) {
- if (!$this->isName($variable, $paramName)) {
- continue;
+ $isParamConditioned = \false;
+ $this->traverseNodesWithCallable((array) $classMethod->stmts, function (Node $subNode) use(&$isParamConditioned, $paramName) : ?int {
+ if ($subNode instanceof If_ && (bool) $this->betterNodeFinder->findFirst($subNode->cond, function (Node $node) use($paramName) : bool {
+ return $node instanceof Variable && $this->isName($node, $paramName);
+ })) {
+ $isParamConditioned = \true;
+ return NodeTraverser::STOP_TRAVERSAL;
}
- $conditional = $this->betterNodeFinder->findParentType($variable, If_::class);
- if ($conditional instanceof If_) {
- return \true;
+ if ($subNode instanceof Ternary && (bool) $this->betterNodeFinder->findFirst($subNode, function (Node $node) use($paramName) : bool {
+ return $node instanceof Variable && $this->isName($node, $paramName);
+ })) {
+ $isParamConditioned = \true;
+ return NodeTraverser::STOP_TRAVERSAL;
}
- $conditional = $this->betterNodeFinder->findParentType($variable, Ternary::class);
- if ($conditional instanceof Ternary) {
- return \true;
- }
- }
- return \false;
+ return null;
+ });
+ return $isParamConditioned;
}
private function shouldSkipParam(Param $param, ClassMethod $classMethod) : bool
{
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnAnnotationIncorrectNullableRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnAnnotationIncorrectNullableRector.php
index 19e45f2b0af1..c5be498cc504 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnAnnotationIncorrectNullableRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnAnnotationIncorrectNullableRector.php
@@ -6,10 +6,11 @@
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
+use PHPStan\Analyser\Scope;
use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
use PHPStan\Type\Type;
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\TypeDeclaration\Guard\PhpDocNestedAnnotationGuard;
use Rector\TypeDeclaration\Helper\PhpDocNullableTypeHelper;
use Rector\VendorLocker\NodeVendorLocker\ClassMethodReturnTypeOverrideGuard;
@@ -18,7 +19,7 @@
/**
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnAnnotationIncorrectNullableRector\ReturnAnnotationIncorrectNullableRectorTest
*/
-final class ReturnAnnotationIncorrectNullableRector extends AbstractRector
+final class ReturnAnnotationIncorrectNullableRector extends AbstractScopeAwareRector
{
/**
* @readonly
@@ -85,10 +86,10 @@ public function getNodeTypes() : array
/**
* @param ClassMethod|Function_ $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
$returnType = $node->getReturnType();
- if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node)) {
+ if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
return null;
}
if ($returnType === null) {
@@ -109,7 +110,7 @@ public function refactor(Node $node) : ?Node
if (!$updatedPhpDocType instanceof Type) {
return null;
}
- $hasReturnTypeChanged = $this->phpDocTypeChanger->changeReturnType($phpDocInfo, $updatedPhpDocType);
+ $hasReturnTypeChanged = $this->phpDocTypeChanger->changeReturnType($node, $phpDocInfo, $updatedPhpDocType);
if ($hasReturnTypeChanged) {
return $node;
}
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnNeverTypeRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnNeverTypeRector.php
index e1cb594545b1..6dbfef76f95c 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnNeverTypeRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnNeverTypeRector.php
@@ -13,8 +13,9 @@
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\Stmt\Throw_;
+use PHPStan\Analyser\Scope;
use PHPStan\Type\NeverType;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeNestingScope\ValueObject\ControlStructure;
use Rector\VendorLocker\NodeVendorLocker\ClassMethodReturnTypeOverrideGuard;
@@ -26,7 +27,7 @@
*
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnNeverTypeRector\ReturnNeverTypeRectorTest
*/
-final class ReturnNeverTypeRector extends AbstractRector implements MinPhpVersionInterface
+final class ReturnNeverTypeRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -69,9 +70,9 @@ public function getNodeTypes() : array
/**
* @param ClassMethod|Function_|Closure $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
- if ($this->shouldSkip($node)) {
+ if ($this->shouldSkip($node, $scope)) {
return null;
}
$node->returnType = new Identifier('never');
@@ -84,7 +85,7 @@ public function provideMinPhpVersion() : int
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node
*/
- private function shouldSkip($node) : bool
+ private function shouldSkip($node, Scope $scope) : bool
{
$hasReturn = $this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($node, Return_::class);
if ($node instanceof ClassMethod && $node->isMagic()) {
@@ -93,8 +94,7 @@ private function shouldSkip($node) : bool
if ($hasReturn) {
return \true;
}
- $item1Unpacked = ControlStructure::CONDITIONAL_NODE_SCOPE_TYPES;
- $hasNotNeverNodes = $this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($node, \array_merge([Yield_::class], $item1Unpacked));
+ $hasNotNeverNodes = $this->betterNodeFinder->hasInstancesOfInFunctionLikeScoped($node, \array_merge([Yield_::class], ControlStructure::CONDITIONAL_NODE_SCOPE_TYPES));
if ($hasNotNeverNodes) {
return \true;
}
@@ -103,7 +103,7 @@ private function shouldSkip($node) : bool
if (!$hasNeverNodes && !$hasNeverFuncCall) {
return \true;
}
- if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node)) {
+ if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
return \true;
}
if (!$node->returnType instanceof Node) {
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnDirectArrayRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnDirectArrayRector.php
index f3149ab5d3bf..3176580dddc2 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnDirectArrayRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnDirectArrayRector.php
@@ -11,7 +11,8 @@
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Return_;
-use Rector\Core\Rector\AbstractRector;
+use PHPStan\Analyser\Scope;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
use Rector\VendorLocker\NodeVendorLocker\ClassMethodReturnTypeOverrideGuard;
@@ -21,7 +22,7 @@
/**
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnDirectArrayRector\ReturnTypeFromReturnDirectArrayRectorTest
*/
-final class ReturnTypeFromReturnDirectArrayRector extends AbstractRector implements MinPhpVersionInterface
+final class ReturnTypeFromReturnDirectArrayRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -70,12 +71,12 @@ public function getNodeTypes() : array
/**
* @param ClassMethod|Function_|ArrowFunction $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
if ($node->returnType !== null) {
return null;
}
- if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node)) {
+ if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
return null;
}
if (!$this->hasReturnArray($node)) {
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnNewRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnNewRector.php
index 3106251b68b5..87b813d0c927 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnNewRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromReturnNewRector.php
@@ -12,6 +12,7 @@
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Return_;
+use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Type\ObjectType;
@@ -20,7 +21,7 @@
use PHPStan\Type\UnionType;
use Rector\Core\Enum\ObjectReference;
use Rector\Core\Exception\ShouldNotHappenException;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
@@ -35,7 +36,7 @@
/**
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromReturnNewRector\ReturnTypeFromReturnNewRectorTest
*/
-final class ReturnTypeFromReturnNewRector extends AbstractRector implements MinPhpVersionInterface
+final class ReturnTypeFromReturnNewRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -108,12 +109,12 @@ public function getNodeTypes() : array
/**
* @param ClassMethod|Function_|ArrowFunction $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
if ($node->returnType !== null) {
return null;
}
- if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node)) {
+ if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
return null;
}
if (!$node instanceof ArrowFunction) {
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictBoolReturnExprRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictBoolReturnExprRector.php
index 014715201913..ebe718a108c1 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictBoolReturnExprRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictBoolReturnExprRector.php
@@ -8,7 +8,8 @@
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
-use Rector\Core\Rector\AbstractRector;
+use PHPStan\Analyser\Scope;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersion;
use Rector\TypeDeclaration\NodeAnalyzer\ReturnTypeAnalyzer\StrictBoolReturnTypeAnalyzer;
use Rector\VendorLocker\NodeVendorLocker\ClassMethodReturnTypeOverrideGuard;
@@ -18,7 +19,7 @@
/**
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictBoolReturnExprRector\ReturnTypeFromStrictBoolReturnExprRectorTest
*/
-final class ReturnTypeFromStrictBoolReturnExprRector extends AbstractRector implements MinPhpVersionInterface
+final class ReturnTypeFromStrictBoolReturnExprRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -67,12 +68,12 @@ public function getNodeTypes() : array
/**
* @param ClassMethod|Function_|Closure $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
if ($node->returnType !== null) {
return null;
}
- if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node)) {
+ if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
return null;
}
if (!$this->strictBoolReturnTypeAnalyzer->hasAlwaysStrictBoolReturn($node)) {
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictConstantReturnRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictConstantReturnRector.php
index dc018a87de67..06ba89dc7ae9 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictConstantReturnRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictConstantReturnRector.php
@@ -5,8 +5,9 @@
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassMethod;
+use PHPStan\Analyser\Scope;
use PHPStan\Type\Type;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersion;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\TypeDeclaration\TypeAnalyzer\StrictReturnClassConstReturnTypeAnalyzer;
@@ -17,7 +18,7 @@
/**
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictConstantReturnRector\ReturnTypeFromStrictConstantReturnRectorTest
*/
-final class ReturnTypeFromStrictConstantReturnRector extends AbstractRector implements MinPhpVersionInterface
+final class ReturnTypeFromStrictConstantReturnRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -70,12 +71,12 @@ public function getNodeTypes() : array
/**
* @param ClassMethod $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
if ($node->returnType instanceof Node) {
return null;
}
- if ($this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node)) {
+ if ($this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
return null;
}
$matchedType = $this->strictReturnClassConstReturnTypeAnalyzer->matchAlwaysReturnConstFetch($node);
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNativeCallRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNativeCallRector.php
index 51d36099edbb..542761b969b1 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNativeCallRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNativeCallRector.php
@@ -7,8 +7,9 @@
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
+use PHPStan\Analyser\Scope;
use PHPStan\Type\MixedType;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersion;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
@@ -20,7 +21,7 @@
/**
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictNativeCallRector\ReturnTypeFromStrictNativeCallRectorTest
*/
-final class ReturnTypeFromStrictNativeCallRector extends AbstractRector implements MinPhpVersionInterface
+final class ReturnTypeFromStrictNativeCallRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -75,12 +76,12 @@ public function getNodeTypes() : array
/**
* @param ClassMethod|Closure|Function_ $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
if ($node->returnType !== null) {
return null;
}
- if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node)) {
+ if ($node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
return null;
}
$nativeCallLikes = $this->strictNativeFunctionReturnTypeAnalyzer->matchAlwaysReturnNativeCallLikes($node);
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNewArrayRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNewArrayRector.php
index 852a9def0efd..98593b558419 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNewArrayRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictNewArrayRector.php
@@ -15,6 +15,7 @@
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Return_;
+use PHPStan\Analyser\Scope;
use PHPStan\Type\ArrayType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\MixedType;
@@ -23,7 +24,7 @@
use PHPStan\Type\Type;
use PHPStan\Type\VerbosityLevel;
use Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersion;
use Rector\NodeTypeResolver\TypeComparator\TypeComparator;
use Rector\VendorLocker\NodeVendorLocker\ClassMethodReturnTypeOverrideGuard;
@@ -33,7 +34,7 @@
/**
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictNewArrayRector\ReturnTypeFromStrictNewArrayRectorTest
*/
-final class ReturnTypeFromStrictNewArrayRector extends AbstractRector implements MinPhpVersionInterface
+final class ReturnTypeFromStrictNewArrayRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -92,9 +93,9 @@ public function getNodeTypes() : array
/**
* @param ClassMethod|Function_|Closure $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
- if ($this->shouldSkip($node)) {
+ if ($this->shouldSkip($node, $scope)) {
return null;
}
// 1. is variable instantiated with array
@@ -145,19 +146,22 @@ public function provideMinPhpVersion() : int
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node
*/
- private function shouldSkip($node) : bool
+ private function shouldSkip($node, Scope $scope) : bool
{
if ($node->returnType !== null) {
return \true;
}
- return $node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node);
+ return $node instanceof ClassMethod && $this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope);
}
- private function changeReturnType(Node $node, Type $exprType) : void
+ /**
+ * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node
+ */
+ private function changeReturnType($node, Type $exprType) : void
{
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($node);
$exprType = $this->narrowConstantArrayType($exprType);
if (!$this->typeComparator->isSubtype($phpDocInfo->getReturnType(), $exprType)) {
- $this->phpDocTypeChanger->changeReturnType($phpDocInfo, $exprType);
+ $this->phpDocTypeChanger->changeReturnType($node, $phpDocInfo, $exprType);
}
}
/**
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedCallRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedCallRector.php
index 9284ded87e5d..f7133fd9a2d5 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedCallRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedCallRector.php
@@ -5,7 +5,7 @@
use PhpParser\Node;
use PhpParser\Node\ComplexType;
-use PhpParser\Node\Expr\ArrowFunction;
+use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Identifier;
@@ -16,13 +16,14 @@
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Return_;
use PhpParser\Node\UnionType as PhpParserUnionType;
+use PhpParser\NodeTraverser;
+use PHPStan\Analyser\Scope;
use PHPStan\Type\NullType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\UnionType;
use Rector\Core\Php\PhpVersionProvider;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersionFeature;
-use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\TypeDeclaration\NodeAnalyzer\TypeNodeUnwrapper;
use Rector\TypeDeclaration\TypeAnalyzer\ReturnStrictTypeAnalyzer;
use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
@@ -33,7 +34,7 @@
/**
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedCallRector\ReturnTypeFromStrictTypedCallRectorTest
*/
-final class ReturnTypeFromStrictTypedCallRector extends AbstractRector implements MinPhpVersionInterface
+final class ReturnTypeFromStrictTypedCallRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -105,45 +106,30 @@ private function getNumber(): int
*/
public function getNodeTypes() : array
{
- return [ClassMethod::class, Function_::class, Closure::class, ArrowFunction::class];
+ return [ClassMethod::class, Function_::class, Closure::class];
}
public function provideMinPhpVersion() : int
{
return PhpVersionFeature::SCALAR_TYPES;
}
/**
- * @param ClassMethod|Function_|Closure|ArrowFunction $node
+ * @param ClassMethod|Function_|Closure $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
- if ($this->isSkipped($node)) {
+ if ($node->stmts === null) {
return null;
}
- if ($node instanceof ArrowFunction) {
- return $this->processArrowFunction($node);
+ if ($this->shouldSkip($node, $scope)) {
+ return null;
}
- /** @var Return_[] $returns */
- $returns = $this->betterNodeFinder->find((array) $node->stmts, function (Node $subNode) use($node) : bool {
- $currentFunctionLike = $this->betterNodeFinder->findParentType($subNode, FunctionLike::class);
- if ($currentFunctionLike === $node) {
- return $subNode instanceof Return_;
- }
- $currentReturn = $this->betterNodeFinder->findParentType($subNode, Return_::class);
- if (!$currentReturn instanceof Return_) {
- return \false;
- }
- $currentReturnFunctionLike = $this->betterNodeFinder->findParentType($currentReturn, FunctionLike::class);
- if ($currentReturnFunctionLike !== $currentFunctionLike) {
- return \false;
- }
- return $subNode instanceof Return_;
- });
- $returnedStrictTypes = $this->returnStrictTypeAnalyzer->collectStrictReturnTypes($returns);
+ $currentScopeReturns = $this->findCurrentScopeReturns($node);
+ $returnedStrictTypes = $this->returnStrictTypeAnalyzer->collectStrictReturnTypes($currentScopeReturns);
if ($returnedStrictTypes === []) {
return null;
}
if (\count($returnedStrictTypes) === 1) {
- return $this->refactorSingleReturnType($returns[0], $returnedStrictTypes[0], $node);
+ return $this->refactorSingleReturnType($currentScopeReturns[0], $returnedStrictTypes[0], $node);
}
if ($this->phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::UNION_TYPES)) {
/** @var PhpParserUnionType[] $returnedStrictTypes */
@@ -153,20 +139,6 @@ public function refactor(Node $node) : ?Node
}
return null;
}
- private function processArrowFunction(ArrowFunction $arrowFunction) : ?ArrowFunction
- {
- $resolvedType = $this->nodeTypeResolver->getType($arrowFunction->expr);
- // void type is not accepted for arrow functions - https://www.php.net/manual/en/functions.arrow.php#125673
- if ($resolvedType->isVoid()->yes()) {
- return null;
- }
- $returnType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($resolvedType, TypeKind::RETURN);
- if (!$returnType instanceof Node) {
- return null;
- }
- $arrowFunction->returnType = $returnType;
- return $arrowFunction;
- }
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node
*/
@@ -194,26 +166,22 @@ private function processSingleUnionType($node, UnionType $unionType, NullableTyp
return $node;
}
/**
- * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Expr\ArrowFunction $node
+ * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node
*/
- private function isSkipped($node) : bool
+ private function shouldSkip($node, Scope $scope) : bool
{
- if ($node instanceof ArrowFunction) {
- return $node->returnType !== null;
- }
if ($node->returnType !== null) {
return \true;
}
- if (!$node instanceof ClassMethod) {
- return $this->isUnionPossibleReturnsVoid($node);
- }
- if ($this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node)) {
- return \true;
- }
- if (!$node->isMagic()) {
- return $this->isUnionPossibleReturnsVoid($node);
+ if ($node instanceof ClassMethod) {
+ if ($this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
+ return \true;
+ }
+ if ($node->isMagic()) {
+ return \true;
+ }
}
- return \true;
+ return $this->isUnionPossibleReturnsVoid($node);
}
/**
* @param \PhpParser\Node\Identifier|\PhpParser\Node\Name|\PhpParser\Node\NullableType|\PhpParser\Node\ComplexType $returnedStrictTypeNode
@@ -234,4 +202,30 @@ private function refactorSingleReturnType(Return_ $return, $returnedStrictTypeNo
$functionLike->returnType = $returnType;
return $functionLike;
}
+ /**
+ * @return Return_[]
+ * @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure $node
+ */
+ private function findCurrentScopeReturns($node) : array
+ {
+ $currentScopeReturns = [];
+ if ($node->stmts === null) {
+ return [];
+ }
+ $this->traverseNodesWithCallable($node->stmts, static function (Node $node) use(&$currentScopeReturns) : ?int {
+ // skip scope nesting
+ if ($node instanceof FunctionLike) {
+ return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
+ }
+ if (!$node instanceof Return_) {
+ return null;
+ }
+ if (!$node->expr instanceof Expr) {
+ return null;
+ }
+ $currentScopeReturns[] = $node;
+ return null;
+ });
+ return $currentScopeReturns;
+ }
}
diff --git a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedPropertyRector.php b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedPropertyRector.php
index df293c7a3d7e..0939ed1ee413 100644
--- a/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedPropertyRector.php
+++ b/rules/TypeDeclaration/Rector/ClassMethod/ReturnTypeFromStrictTypedPropertyRector.php
@@ -8,10 +8,11 @@
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Return_;
+use PHPStan\Analyser\Scope;
use PHPStan\Reflection\Php\PhpPropertyReflection;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
@@ -23,7 +24,7 @@
/**
* @see \Rector\Tests\TypeDeclaration\Rector\ClassMethod\ReturnTypeFromStrictTypedPropertyRector\ReturnTypeFromStrictTypedPropertyRectorTest
*/
-final class ReturnTypeFromStrictTypedPropertyRector extends AbstractRector implements MinPhpVersionInterface
+final class ReturnTypeFromStrictTypedPropertyRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -82,12 +83,12 @@ public function getNodeTypes() : array
/**
* @param ClassMethod $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
if ($node->returnType !== null) {
return null;
}
- if ($this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node)) {
+ if ($this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($node, $scope)) {
return null;
}
$propertyTypes = $this->resolveReturnPropertyType($node);
diff --git a/rules/TypeDeclaration/Rector/Class_/ReturnTypeFromStrictTernaryRector.php b/rules/TypeDeclaration/Rector/Class_/ReturnTypeFromStrictTernaryRector.php
index 2ed1e916f3d1..934fb1b997b3 100644
--- a/rules/TypeDeclaration/Rector/Class_/ReturnTypeFromStrictTernaryRector.php
+++ b/rules/TypeDeclaration/Rector/Class_/ReturnTypeFromStrictTernaryRector.php
@@ -11,10 +11,11 @@
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Return_;
+use PHPStan\Analyser\Scope;
use PHPStan\Type\ConstantType;
use PHPStan\Type\GeneralizePrecision;
use PHPStan\Type\Type;
-use Rector\Core\Rector\AbstractRector;
+use Rector\Core\Rector\AbstractScopeAwareRector;
use Rector\Core\ValueObject\PhpVersionFeature;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\TypeDeclaration\ValueObject\TernaryIfElseTypes;
@@ -25,7 +26,7 @@
/**
* @see \Rector\Tests\TypeDeclaration\Rector\Class_\ReturnTypeFromStrictTernaryRector\ReturnTypeFromStrictTernaryRectorTest
*/
-final class ReturnTypeFromStrictTernaryRector extends AbstractRector implements MinPhpVersionInterface
+final class ReturnTypeFromStrictTernaryRector extends AbstractScopeAwareRector implements MinPhpVersionInterface
{
/**
* @readonly
@@ -68,7 +69,7 @@ public function getNodeTypes() : array
/**
* @param Class_ $node
*/
- public function refactor(Node $node) : ?Node
+ public function refactorWithScope(Node $node, Scope $scope) : ?Node
{
$hasChanged = \false;
foreach ($node->getMethods() as $classMethod) {
@@ -93,7 +94,7 @@ public function refactor(Node $node) : ?Node
if (!$this->areTypesEqual($ifType, $elseType)) {
continue;
}
- if ($this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($classMethod)) {
+ if ($this->classMethodReturnTypeOverrideGuard->shouldSkipClassMethod($classMethod, $scope)) {
continue;
}
$returnTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($ifType, TypeKind::RETURN);
diff --git a/rules/TypeDeclaration/Rector/FunctionLike/AddParamTypeSplFixedArrayRector.php b/rules/TypeDeclaration/Rector/FunctionLike/AddParamTypeSplFixedArrayRector.php
index 9b77f0ceb45a..8f8c8b84ad17 100644
--- a/rules/TypeDeclaration/Rector/FunctionLike/AddParamTypeSplFixedArrayRector.php
+++ b/rules/TypeDeclaration/Rector/FunctionLike/AddParamTypeSplFixedArrayRector.php
@@ -20,15 +20,15 @@
*/
final class AddParamTypeSplFixedArrayRector extends AbstractRector
{
- /**
- * @var array
- */
- private const SPL_FIXED_ARRAY_TO_SINGLE = ['PhpCsFixer\\Tokenizer\\Tokens' => 'PhpCsFixer\\Tokenizer\\Token', 'PhpCsFixer\\Doctrine\\Annotation\\Tokens' => 'PhpCsFixer\\Doctrine\\Annotation\\Token'];
/**
* @readonly
* @var \Rector\BetterPhpDocParser\PhpDocManipulator\PhpDocTypeChanger
*/
private $phpDocTypeChanger;
+ /**
+ * @var array
+ */
+ private const SPL_FIXED_ARRAY_TO_SINGLE = ['PhpCsFixer\\Tokenizer\\Tokens' => 'PhpCsFixer\\Tokenizer\\Token', 'PhpCsFixer\\Doctrine\\Annotation\\Tokens' => 'PhpCsFixer\\Doctrine\\Annotation\\Token'];
public function __construct(PhpDocTypeChanger $phpDocTypeChanger)
{
$this->phpDocTypeChanger = $phpDocTypeChanger;
@@ -96,7 +96,7 @@ public function refactor(Node $node) : ?Node
continue;
}
$paramName = $this->getName($param);
- $this->phpDocTypeChanger->changeParamType($functionLikePhpDocInfo, $genericParamType, $param, $paramName);
+ $this->phpDocTypeChanger->changeParamType($node, $functionLikePhpDocInfo, $genericParamType, $param, $paramName);
}
if ($functionLikePhpDocInfo->hasChanged()) {
return $node;
diff --git a/rules/TypeDeclaration/Rector/Property/AddPropertyTypeDeclarationRector.php b/rules/TypeDeclaration/Rector/Property/AddPropertyTypeDeclarationRector.php
index b628514ecc5d..c6fff802da4e 100644
--- a/rules/TypeDeclaration/Rector/Property/AddPropertyTypeDeclarationRector.php
+++ b/rules/TypeDeclaration/Rector/Property/AddPropertyTypeDeclarationRector.php
@@ -21,15 +21,15 @@
*/
final class AddPropertyTypeDeclarationRector extends AbstractRector implements ConfigurableRectorInterface
{
- /**
- * @var AddPropertyTypeDeclaration[]
- */
- private $addPropertyTypeDeclarations = [];
/**
* @readonly
* @var \Rector\Core\Reflection\ReflectionResolver
*/
private $reflectionResolver;
+ /**
+ * @var AddPropertyTypeDeclaration[]
+ */
+ private $addPropertyTypeDeclarations = [];
public function __construct(ReflectionResolver $reflectionResolver)
{
$this->reflectionResolver = $reflectionResolver;
diff --git a/rules/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector.php b/rules/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector.php
index 8eb5901389c5..1c2cb1b59f8a 100644
--- a/rules/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector.php
+++ b/rules/TypeDeclaration/Rector/Property/TypedPropertyFromAssignsRector.php
@@ -26,21 +26,6 @@
*/
final class TypedPropertyFromAssignsRector extends AbstractRector implements AllowEmptyConfigurableRectorInterface, MinPhpVersionInterface
{
- /**
- * @api
- * @var string
- */
- public const INLINE_PUBLIC = 'inline_public';
- /**
- * Default to false, which only apply changes:
- *
- * – private modifier property
- * - protected modifier property on final class without extends or has extends but property and/or its usage only in current class
- *
- * Set to true will allow change other modifiers as well as far as not forbidden, eg: callable type, null type, etc.
- * @var bool
- */
- private $inlinePublic = \false;
/**
* @readonly
* @var \Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer\AllAssignNodePropertyTypeInferer
@@ -61,6 +46,21 @@ final class TypedPropertyFromAssignsRector extends AbstractRector implements All
* @var \Rector\Php74\Guard\MakePropertyTypedGuard
*/
private $makePropertyTypedGuard;
+ /**
+ * @api
+ * @var string
+ */
+ public const INLINE_PUBLIC = 'inline_public';
+ /**
+ * Default to false, which only apply changes:
+ *
+ * – private modifier property
+ * - protected modifier property on final class without extends or has extends but property and/or its usage only in current class
+ *
+ * Set to true will allow change other modifiers as well as far as not forbidden, eg: callable type, null type, etc.
+ * @var bool
+ */
+ private $inlinePublic = \false;
public function __construct(AllAssignNodePropertyTypeInferer $allAssignNodePropertyTypeInferer, PropertyTypeDecorator $propertyTypeDecorator, VarTagRemover $varTagRemover, MakePropertyTypedGuard $makePropertyTypedGuard)
{
$this->allAssignNodePropertyTypeInferer = $allAssignNodePropertyTypeInferer;
diff --git a/rules/TypeDeclaration/Rector/Property/TypedPropertyFromStrictConstructorRector.php b/rules/TypeDeclaration/Rector/Property/TypedPropertyFromStrictConstructorRector.php
index 1280cc3d922c..bb13e10b74c9 100644
--- a/rules/TypeDeclaration/Rector/Property/TypedPropertyFromStrictConstructorRector.php
+++ b/rules/TypeDeclaration/Rector/Property/TypedPropertyFromStrictConstructorRector.php
@@ -108,14 +108,14 @@ public function refactor(Node $node) : ?Node
if (!$this->propertyTypeOverrideGuard->isLegal($property)) {
continue;
}
- $propertyType = $this->trustedClassMethodPropertyTypeInferer->inferProperty($property, $constructClassMethod);
+ $propertyType = $this->trustedClassMethodPropertyTypeInferer->inferProperty($node, $property, $constructClassMethod);
if ($this->shouldSkipPropertyType($propertyType)) {
continue;
}
$phpDocInfo = $this->phpDocInfoFactory->createFromNodeOrEmpty($property);
// public property can be anything
if ($property->isPublic()) {
- $this->phpDocTypeChanger->changeVarType($phpDocInfo, $propertyType);
+ $this->phpDocTypeChanger->changeVarType($property, $phpDocInfo, $propertyType);
$hasChanged = \true;
continue;
}
diff --git a/rules/TypeDeclaration/Rector/Property/TypedPropertyFromStrictSetUpRector.php b/rules/TypeDeclaration/Rector/Property/TypedPropertyFromStrictSetUpRector.php
index fd170b23b10d..3fc1a55e7f1a 100644
--- a/rules/TypeDeclaration/Rector/Property/TypedPropertyFromStrictSetUpRector.php
+++ b/rules/TypeDeclaration/Rector/Property/TypedPropertyFromStrictSetUpRector.php
@@ -84,7 +84,7 @@ public function refactor(Node $node) : ?Node
if (!$property->isPrivate()) {
continue;
}
- $propertyType = $this->trustedClassMethodPropertyTypeInferer->inferProperty($property, $setUpClassMethod);
+ $propertyType = $this->trustedClassMethodPropertyTypeInferer->inferProperty($node, $property, $setUpClassMethod);
$propertyTypeNode = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($propertyType, TypeKind::PROPERTY);
if (!$propertyTypeNode instanceof Node) {
continue;
diff --git a/rules/TypeDeclaration/Rector/Property/VarAnnotationIncorrectNullableRector.php b/rules/TypeDeclaration/Rector/Property/VarAnnotationIncorrectNullableRector.php
index 2f341392d14f..19222b5b5c37 100644
--- a/rules/TypeDeclaration/Rector/Property/VarAnnotationIncorrectNullableRector.php
+++ b/rules/TypeDeclaration/Rector/Property/VarAnnotationIncorrectNullableRector.php
@@ -109,7 +109,7 @@ public function refactor(Node $node) : ?Node
if (!$updatedPhpDocType instanceof Type) {
return null;
}
- $this->phpDocTypeChanger->changeVarType($phpDocInfo, $updatedPhpDocType);
+ $this->phpDocTypeChanger->changeVarType($node, $phpDocInfo, $updatedPhpDocType);
if (!$phpDocInfo->hasChanged()) {
return null;
}
diff --git a/rules/TypeDeclaration/TypeAnalyzer/AlwaysStrictScalarExprAnalyzer.php b/rules/TypeDeclaration/TypeAnalyzer/AlwaysStrictScalarExprAnalyzer.php
index 841102df6029..84a033939602 100644
--- a/rules/TypeDeclaration/TypeAnalyzer/AlwaysStrictScalarExprAnalyzer.php
+++ b/rules/TypeDeclaration/TypeAnalyzer/AlwaysStrictScalarExprAnalyzer.php
@@ -25,7 +25,6 @@
use PHPStan\Type\NullType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
-use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\NodeTypeResolver\PHPStan\ParametersAcceptorSelectorVariantsWrapper;
final class AlwaysStrictScalarExprAnalyzer
@@ -45,7 +44,7 @@ public function __construct(ReflectionProvider $reflectionProvider, NodeTypeReso
$this->reflectionProvider = $reflectionProvider;
$this->nodeTypeResolver = $nodeTypeResolver;
}
- public function matchStrictScalarExpr(Expr $expr) : ?Type
+ public function matchStrictScalarExpr(Expr $expr, Scope $scope) : ?Type
{
if ($expr instanceof Concat) {
return new StringType();
@@ -67,7 +66,7 @@ public function matchStrictScalarExpr(Expr $expr) : ?Type
return null;
}
if ($expr instanceof FuncCall) {
- return $this->resolveFuncCallType($expr);
+ return $this->resolveFuncCallType($expr, $scope);
}
return null;
}
@@ -111,7 +110,7 @@ private function resolveTypeFromScalar(Scalar $scalar) : ?\PHPStan\Type\Type
}
return null;
}
- private function resolveFuncCallType(FuncCall $funcCall) : ?Type
+ private function resolveFuncCallType(FuncCall $funcCall, Scope $scope) : ?Type
{
if (!$funcCall->name instanceof Name) {
return null;
@@ -123,10 +122,6 @@ private function resolveFuncCallType(FuncCall $funcCall) : ?Type
if (!$functionReflection instanceof NativeFunctionReflection) {
return null;
}
- $scope = $funcCall->getAttribute(AttributeKey::SCOPE);
- if (!$scope instanceof Scope) {
- return null;
- }
$parametersAcceptor = ParametersAcceptorSelectorVariantsWrapper::select($functionReflection, $funcCall, $scope);
$returnType = $parametersAcceptor->getReturnType();
if (!$this->isScalarType($returnType)) {
diff --git a/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php b/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php
index 9ee12296e833..3ebe57c8b82a 100644
--- a/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php
+++ b/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/AllAssignNodePropertyTypeInferer.php
@@ -5,8 +5,10 @@
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\Property;
+use PHPStan\Reflection\ClassReflection;
use PHPStan\Type\Type;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
+use Rector\Core\PhpParser\ClassLikeAstResolver;
+use Rector\Core\Reflection\ReflectionResolver;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\TypeDeclaration\TypeInferer\AssignToPropertyTypeInferer;
final class AllAssignNodePropertyTypeInferer
@@ -23,21 +25,29 @@ final class AllAssignNodePropertyTypeInferer
private $nodeNameResolver;
/**
* @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
+ * @var \Rector\Core\Reflection\ReflectionResolver
*/
- private $betterNodeFinder;
- public function __construct(AssignToPropertyTypeInferer $assignToPropertyTypeInferer, NodeNameResolver $nodeNameResolver, BetterNodeFinder $betterNodeFinder)
+ private $reflectionResolver;
+ /**
+ * @readonly
+ * @var \Rector\Core\PhpParser\ClassLikeAstResolver
+ */
+ private $classLikeAstResolver;
+ public function __construct(AssignToPropertyTypeInferer $assignToPropertyTypeInferer, NodeNameResolver $nodeNameResolver, ReflectionResolver $reflectionResolver, ClassLikeAstResolver $classLikeAstResolver)
{
$this->assignToPropertyTypeInferer = $assignToPropertyTypeInferer;
$this->nodeNameResolver = $nodeNameResolver;
- $this->betterNodeFinder = $betterNodeFinder;
+ $this->reflectionResolver = $reflectionResolver;
+ $this->classLikeAstResolver = $classLikeAstResolver;
}
public function inferProperty(Property $property) : ?Type
{
- $classLike = $this->betterNodeFinder->findParentType($property, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($property);
+ if (!$classReflection instanceof ClassReflection) {
return null;
}
+ /** @var ClassLike $classLike */
+ $classLike = $this->classLikeAstResolver->resolveClassFromClassReflection($classReflection);
$propertyName = $this->nodeNameResolver->getName($property);
return $this->assignToPropertyTypeInferer->inferPropertyInClassLike($property, $propertyName, $classLike);
}
diff --git a/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/TrustedClassMethodPropertyTypeInferer.php b/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/TrustedClassMethodPropertyTypeInferer.php
index b5d637733ddd..7a8c90a56e71 100644
--- a/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/TrustedClassMethodPropertyTypeInferer.php
+++ b/rules/TypeDeclaration/TypeInferer/PropertyTypeInferer/TrustedClassMethodPropertyTypeInferer.php
@@ -10,7 +10,7 @@
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\NullableType;
use PhpParser\Node\Param;
-use PhpParser\Node\Stmt\ClassLike;
+use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Property;
use PhpParser\NodeTraverser;
@@ -23,7 +23,6 @@
use PHPStan\Type\UnionType;
use Rector\Core\NodeAnalyzer\ParamAnalyzer;
use Rector\Core\NodeManipulator\ClassMethodPropertyFetchManipulator;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\NodeTypeResolver\NodeTypeResolver;
@@ -74,11 +73,6 @@ final class TrustedClassMethodPropertyTypeInferer
* @var \Rector\NodeTypeResolver\NodeTypeResolver
*/
private $nodeTypeResolver;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
/**
* @readonly
* @var \Rector\Core\NodeAnalyzer\ParamAnalyzer
@@ -94,7 +88,7 @@ final class TrustedClassMethodPropertyTypeInferer
* @var \Rector\NodeTypeResolver\TypeComparator\TypeComparator
*/
private $typeComparator;
- public function __construct(ClassMethodPropertyFetchManipulator $classMethodPropertyFetchManipulator, ReflectionProvider $reflectionProvider, NodeNameResolver $nodeNameResolver, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, TypeFactory $typeFactory, StaticTypeMapper $staticTypeMapper, NodeTypeResolver $nodeTypeResolver, BetterNodeFinder $betterNodeFinder, ParamAnalyzer $paramAnalyzer, AssignToPropertyTypeInferer $assignToPropertyTypeInferer, TypeComparator $typeComparator)
+ public function __construct(ClassMethodPropertyFetchManipulator $classMethodPropertyFetchManipulator, ReflectionProvider $reflectionProvider, NodeNameResolver $nodeNameResolver, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, TypeFactory $typeFactory, StaticTypeMapper $staticTypeMapper, NodeTypeResolver $nodeTypeResolver, ParamAnalyzer $paramAnalyzer, AssignToPropertyTypeInferer $assignToPropertyTypeInferer, TypeComparator $typeComparator)
{
$this->classMethodPropertyFetchManipulator = $classMethodPropertyFetchManipulator;
$this->reflectionProvider = $reflectionProvider;
@@ -103,22 +97,17 @@ public function __construct(ClassMethodPropertyFetchManipulator $classMethodProp
$this->typeFactory = $typeFactory;
$this->staticTypeMapper = $staticTypeMapper;
$this->nodeTypeResolver = $nodeTypeResolver;
- $this->betterNodeFinder = $betterNodeFinder;
$this->paramAnalyzer = $paramAnalyzer;
$this->assignToPropertyTypeInferer = $assignToPropertyTypeInferer;
$this->typeComparator = $typeComparator;
}
- public function inferProperty(Property $property, ClassMethod $classMethod) : Type
+ public function inferProperty(Class_ $class, Property $property, ClassMethod $classMethod) : Type
{
- $classLike = $this->betterNodeFinder->findParentType($property, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
- return new MixedType();
- }
$propertyName = $this->nodeNameResolver->getName($property);
// 1. direct property = param assign
$param = $this->classMethodPropertyFetchManipulator->findParamAssignToPropertyName($classMethod, $propertyName);
if ($param instanceof Param) {
- return $this->resolveTypeFromParam($param, $classMethod, $propertyName, $property, $classLike);
+ return $this->resolveTypeFromParam($param, $classMethod, $propertyName, $property, $class);
}
// 2. different assign
/** @var Expr[] $assignedExprs */
@@ -131,11 +120,11 @@ public function inferProperty(Property $property, ClassMethod $classMethod) : Ty
return new MixedType();
}
$resolvedType = \count($resolvedTypes) === 1 ? $resolvedTypes[0] : TypeCombinator::union(...$resolvedTypes);
- return $this->resolveType($property, $propertyName, $classLike, $resolvedType);
+ return $this->resolveType($property, $propertyName, $class, $resolvedType);
}
- private function resolveType(Property $property, string $propertyName, ClassLike $classLike, Type $resolvedType) : Type
+ private function resolveType(Property $property, string $propertyName, Class_ $class, Type $resolvedType) : Type
{
- $exactType = $this->assignToPropertyTypeInferer->inferPropertyInClassLike($property, $propertyName, $classLike);
+ $exactType = $this->assignToPropertyTypeInferer->inferPropertyInClassLike($property, $propertyName, $class);
if (!$exactType instanceof UnionType) {
return $resolvedType;
}
@@ -236,12 +225,12 @@ private function resolveFullyQualifiedOrAliasedObjectType(Param $param) : ?Type
}
return null;
}
- private function resolveTypeFromParam(Param $param, ClassMethod $classMethod, string $propertyName, Property $property, ClassLike $classLike) : Type
+ private function resolveTypeFromParam(Param $param, ClassMethod $classMethod, string $propertyName, Property $property, Class_ $class) : Type
{
if ($param->type === null) {
return new MixedType();
}
$resolvedType = $this->resolveFromParamType($param, $classMethod, $propertyName);
- return $this->resolveType($property, $propertyName, $classLike, $resolvedType);
+ return $this->resolveType($property, $propertyName, $class, $resolvedType);
}
}
diff --git a/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer.php b/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer.php
index d4ae0240a093..28b76a06a314 100644
--- a/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer.php
+++ b/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer.php
@@ -9,7 +9,6 @@
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Expr\Yield_;
use PhpParser\Node\FunctionLike;
-use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\Return_;
@@ -25,8 +24,8 @@
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\Php\PhpVersionProvider;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
+use Rector\Core\Reflection\ReflectionResolver;
use Rector\Core\ValueObject\PhpVersionFeature;
-use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\StaticTypeMapper\ValueObject\Type\FullyQualifiedObjectType;
use Rector\TypeDeclaration\TypeAnalyzer\GenericClassStringTypeNormalizer;
@@ -62,6 +61,11 @@ final class ReturnTypeInferer
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
*/
private $betterNodeFinder;
+ /**
+ * @readonly
+ * @var \Rector\Core\Reflection\ReflectionResolver
+ */
+ private $reflectionResolver;
/**
* @readonly
* @var \PHPStan\Reflection\ReflectionProvider
@@ -72,21 +76,16 @@ final class ReturnTypeInferer
* @var \Rector\NodeTypeResolver\NodeTypeResolver
*/
private $nodeTypeResolver;
- /**
- * @readonly
- * @var \Rector\NodeNameResolver\NodeNameResolver
- */
- private $nodeNameResolver;
- public function __construct(TypeNormalizer $typeNormalizer, ReturnedNodesReturnTypeInfererTypeInferer $returnedNodesReturnTypeInfererTypeInferer, GenericClassStringTypeNormalizer $genericClassStringTypeNormalizer, PhpVersionProvider $phpVersionProvider, BetterNodeFinder $betterNodeFinder, ReflectionProvider $reflectionProvider, NodeTypeResolver $nodeTypeResolver, NodeNameResolver $nodeNameResolver)
+ public function __construct(TypeNormalizer $typeNormalizer, ReturnedNodesReturnTypeInfererTypeInferer $returnedNodesReturnTypeInfererTypeInferer, GenericClassStringTypeNormalizer $genericClassStringTypeNormalizer, PhpVersionProvider $phpVersionProvider, BetterNodeFinder $betterNodeFinder, ReflectionResolver $reflectionResolver, ReflectionProvider $reflectionProvider, NodeTypeResolver $nodeTypeResolver)
{
$this->typeNormalizer = $typeNormalizer;
$this->returnedNodesReturnTypeInfererTypeInferer = $returnedNodesReturnTypeInfererTypeInferer;
$this->genericClassStringTypeNormalizer = $genericClassStringTypeNormalizer;
$this->phpVersionProvider = $phpVersionProvider;
$this->betterNodeFinder = $betterNodeFinder;
+ $this->reflectionResolver = $reflectionResolver;
$this->reflectionProvider = $reflectionProvider;
$this->nodeTypeResolver = $nodeTypeResolver;
- $this->nodeNameResolver = $nodeNameResolver;
}
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Stmt\Function_|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Expr\ArrowFunction $functionLike
@@ -128,13 +127,13 @@ private function verifyThisType(Type $type, FunctionLike $functionLike) : Type
if (!$type instanceof ThisType) {
return $type;
}
- $class = $this->betterNodeFinder->findParentType($functionLike, Class_::class);
+ $classReflection = $this->reflectionResolver->resolveClassReflection($functionLike);
$objectType = $type->getStaticObjectType();
$objectTypeClassName = $objectType->getClassName();
- if (!$class instanceof Class_) {
+ if (!$classReflection instanceof ClassReflection || !$classReflection->isClass()) {
return $type;
}
- if ($this->nodeNameResolver->isName($class, $objectTypeClassName)) {
+ if ($classReflection->getName() === $objectTypeClassName) {
return $type;
}
return new MixedType();
diff --git a/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInfererTypeInferer.php b/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInfererTypeInferer.php
index 3e2c2a59b619..661ae6c5431e 100644
--- a/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInfererTypeInferer.php
+++ b/rules/TypeDeclaration/TypeInferer/ReturnTypeInferer/ReturnedNodesReturnTypeInfererTypeInferer.php
@@ -4,23 +4,20 @@
namespace Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer;
use PhpParser\Node;
+use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\FunctionLike;
-use PhpParser\Node\Stmt\Class_;
-use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Return_;
-use PhpParser\Node\Stmt\Trait_;
use PhpParser\NodeTraverser;
+use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\ArrayType;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use PHPStan\Type\VoidType;
-use Rector\Core\Contract\PhpParser\NodePrinterInterface;
use Rector\Core\PhpParser\AstResolver;
-use Rector\Core\PhpParser\Node\BetterNodeFinder;
+use Rector\Core\PhpParser\Printer\BetterStandardPrinter;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\NodeTypeResolver\NodeTypeResolver;
use Rector\NodeTypeResolver\PHPStan\Type\TypeFactory;
@@ -64,20 +61,15 @@ final class ReturnedNodesReturnTypeInfererTypeInferer
private $reflectionAstResolver;
/**
* @readonly
- * @var \Rector\Core\Contract\PhpParser\NodePrinterInterface
+ * @var \Rector\Core\PhpParser\Printer\BetterStandardPrinter
*/
- private $nodePrinter;
+ private $betterStandardPrinter;
/**
* @readonly
* @var \Rector\Core\Reflection\ReflectionResolver
*/
private $reflectionResolver;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\Node\BetterNodeFinder
- */
- private $betterNodeFinder;
- public function __construct(SilentVoidResolver $silentVoidResolver, NodeTypeResolver $nodeTypeResolver, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, TypeFactory $typeFactory, SplArrayFixedTypeNarrower $splArrayFixedTypeNarrower, AstResolver $reflectionAstResolver, NodePrinterInterface $nodePrinter, ReflectionResolver $reflectionResolver, BetterNodeFinder $betterNodeFinder)
+ public function __construct(SilentVoidResolver $silentVoidResolver, NodeTypeResolver $nodeTypeResolver, SimpleCallableNodeTraverser $simpleCallableNodeTraverser, TypeFactory $typeFactory, SplArrayFixedTypeNarrower $splArrayFixedTypeNarrower, AstResolver $reflectionAstResolver, BetterStandardPrinter $betterStandardPrinter, ReflectionResolver $reflectionResolver)
{
$this->silentVoidResolver = $silentVoidResolver;
$this->nodeTypeResolver = $nodeTypeResolver;
@@ -85,24 +77,22 @@ public function __construct(SilentVoidResolver $silentVoidResolver, NodeTypeReso
$this->typeFactory = $typeFactory;
$this->splArrayFixedTypeNarrower = $splArrayFixedTypeNarrower;
$this->reflectionAstResolver = $reflectionAstResolver;
- $this->nodePrinter = $nodePrinter;
+ $this->betterStandardPrinter = $betterStandardPrinter;
$this->reflectionResolver = $reflectionResolver;
- $this->betterNodeFinder = $betterNodeFinder;
}
public function inferFunctionLike(FunctionLike $functionLike) : Type
{
- $classLike = $this->betterNodeFinder->findParentType($functionLike, ClassLike::class);
- if (!$classLike instanceof ClassLike) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($functionLike);
+ if (!$classReflection instanceof ClassReflection) {
return new MixedType();
}
- if ($functionLike instanceof ClassMethod && $classLike instanceof Interface_) {
+ if ($functionLike instanceof ClassMethod && $classReflection->isInterface()) {
return new MixedType();
}
$types = [];
$localReturnNodes = $this->collectReturns($functionLike);
if ($localReturnNodes === []) {
- /** @var Class_|Interface_|Trait_ $classLike */
- return $this->resolveNoLocalReturnNodes($classLike, $functionLike);
+ return $this->resolveNoLocalReturnNodes($classReflection, $functionLike);
}
foreach ($localReturnNodes as $localReturnNode) {
$returnedExprType = $this->nodeTypeResolver->getType($localReturnNode);
@@ -134,29 +124,25 @@ private function collectReturns(FunctionLike $functionLike) : array
return $returns;
}
/**
- * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_|\PhpParser\Node\Stmt\Trait_ $classLike
* @return \PHPStan\Type\VoidType|\PHPStan\Type\MixedType
*/
- private function resolveNoLocalReturnNodes($classLike, FunctionLike $functionLike)
+ private function resolveNoLocalReturnNodes(ClassReflection $classReflection, FunctionLike $functionLike)
{
// void type
- if (!$this->isAbstractMethod($classLike, $functionLike)) {
+ if (!$this->isAbstractMethod($classReflection, $functionLike)) {
return new VoidType();
}
return new MixedType();
}
- /**
- * @param \PhpParser\Node\Stmt\Class_|\PhpParser\Node\Stmt\Interface_|\PhpParser\Node\Stmt\Trait_ $classLike
- */
- private function isAbstractMethod($classLike, FunctionLike $functionLike) : bool
+ private function isAbstractMethod(ClassReflection $classReflection, FunctionLike $functionLike) : bool
{
if ($functionLike instanceof ClassMethod && $functionLike->isAbstract()) {
return \true;
}
- if (!$classLike instanceof Class_) {
+ if (!$classReflection->isClass()) {
return \false;
}
- return $classLike->isAbstract();
+ return $classReflection->isAbstract();
}
private function inferFromReturnedMethodCall(Return_ $return, FunctionLike $originalFunctionLike) : Type
{
@@ -167,8 +153,21 @@ private function inferFromReturnedMethodCall(Return_ $return, FunctionLike $orig
if (!$methodReflection instanceof MethodReflection) {
return new MixedType();
}
- $parentClassMethod = $this->betterNodeFinder->findParentType($return, ClassMethod::class);
- if ($parentClassMethod === $originalFunctionLike) {
+ $isReturnScoped = \false;
+ $this->simpleCallableNodeTraverser->traverseNodesWithCallable((array) $originalFunctionLike->getStmts(), static function (Node $subNode) use($return, &$isReturnScoped) : ?int {
+ if ($subNode instanceof FunctionLike && !$subNode instanceof ArrowFunction) {
+ return NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN;
+ }
+ if (!$subNode instanceof Return_) {
+ return null;
+ }
+ if ($return === $subNode) {
+ $isReturnScoped = \true;
+ return NodeTraverser::STOP_TRAVERSAL;
+ }
+ return null;
+ });
+ if ($isReturnScoped) {
return new MixedType();
}
return $this->resolveClassMethod($methodReflection, $originalFunctionLike);
@@ -200,8 +199,8 @@ private function resolveClassMethod(MethodReflection $methodReflection, Function
if (!$classMethod instanceof ClassMethod) {
return new MixedType();
}
- $classMethodCacheKey = $this->nodePrinter->print($classMethod);
- $functionLikeCacheKey = $this->nodePrinter->print($originalFunctionLike);
+ $classMethodCacheKey = $this->betterStandardPrinter->print($classMethod);
+ $functionLikeCacheKey = $this->betterStandardPrinter->print($originalFunctionLike);
if ($classMethodCacheKey === $functionLikeCacheKey) {
return new MixedType();
}
diff --git a/rules/TypeDeclaration/TypeInferer/SilentVoidResolver.php b/rules/TypeDeclaration/TypeInferer/SilentVoidResolver.php
index 1433ebac00de..5b6be56b195e 100644
--- a/rules/TypeDeclaration/TypeInferer/SilentVoidResolver.php
+++ b/rules/TypeDeclaration/TypeInferer/SilentVoidResolver.php
@@ -9,16 +9,16 @@
use PhpParser\Node\Expr\Yield_;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt;
-use PhpParser\Node\Stmt\ClassLike;
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 PHPStan\Reflection\ClassReflection;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
+use Rector\Core\Reflection\ReflectionResolver;
final class SilentVoidResolver
{
/**
@@ -26,17 +26,23 @@ final class SilentVoidResolver
* @var \Rector\Core\PhpParser\Node\BetterNodeFinder
*/
private $betterNodeFinder;
- public function __construct(BetterNodeFinder $betterNodeFinder)
+ /**
+ * @readonly
+ * @var \Rector\Core\Reflection\ReflectionResolver
+ */
+ private $reflectionResolver;
+ public function __construct(BetterNodeFinder $betterNodeFinder, ReflectionResolver $reflectionResolver)
{
$this->betterNodeFinder = $betterNodeFinder;
+ $this->reflectionResolver = $reflectionResolver;
}
/**
* @param \PhpParser\Node\Stmt\ClassMethod|\PhpParser\Node\Expr\Closure|\PhpParser\Node\Stmt\Function_ $functionLike
*/
public function hasExclusiveVoid($functionLike) : bool
{
- $classLike = $this->betterNodeFinder->findParentType($functionLike, ClassLike::class);
- if ($classLike instanceof Interface_) {
+ $classReflection = $this->reflectionResolver->resolveClassReflection($functionLike);
+ if ($classReflection instanceof ClassReflection && $classReflection->isInterface()) {
return \false;
}
if ($this->hasNeverType($functionLike)) {
diff --git a/rules/TypeDeclaration/TypeNormalizer.php b/rules/TypeDeclaration/TypeNormalizer.php
index 2791c9fa31a1..aec420f102e5 100644
--- a/rules/TypeDeclaration/TypeNormalizer.php
+++ b/rules/TypeDeclaration/TypeNormalizer.php
@@ -18,10 +18,6 @@
*/
final class TypeNormalizer
{
- /**
- * @var NestedArrayType[]
- */
- private $collectedNestedArrayTypes = [];
/**
* @readonly
* @var \Rector\NodeTypeResolver\PHPStan\Type\TypeFactory
@@ -32,6 +28,10 @@ final class TypeNormalizer
* @var \Rector\Core\Util\Reflection\PrivatesAccessor
*/
private $privatesAccessor;
+ /**
+ * @var NestedArrayType[]
+ */
+ private $collectedNestedArrayTypes = [];
public function __construct(TypeFactory $typeFactory, PrivatesAccessor $privatesAccessor)
{
$this->typeFactory = $typeFactory;
diff --git a/rules/Visibility/Rector/ClassConst/ChangeConstantVisibilityRector.php b/rules/Visibility/Rector/ClassConst/ChangeConstantVisibilityRector.php
index a5948980de89..074726a63a88 100644
--- a/rules/Visibility/Rector/ClassConst/ChangeConstantVisibilityRector.php
+++ b/rules/Visibility/Rector/ClassConst/ChangeConstantVisibilityRector.php
@@ -18,15 +18,15 @@
*/
final class ChangeConstantVisibilityRector extends AbstractRector implements ConfigurableRectorInterface
{
- /**
- * @var ChangeConstantVisibility[]
- */
- private $classConstantVisibilityChanges = [];
/**
* @readonly
* @var \Rector\Privatization\NodeManipulator\VisibilityManipulator
*/
private $visibilityManipulator;
+ /**
+ * @var ChangeConstantVisibility[]
+ */
+ private $classConstantVisibilityChanges = [];
public function __construct(VisibilityManipulator $visibilityManipulator)
{
$this->visibilityManipulator = $visibilityManipulator;
diff --git a/rules/Visibility/Rector/ClassMethod/ChangeMethodVisibilityRector.php b/rules/Visibility/Rector/ClassMethod/ChangeMethodVisibilityRector.php
index 41610d572555..a0eb4c5ed945 100644
--- a/rules/Visibility/Rector/ClassMethod/ChangeMethodVisibilityRector.php
+++ b/rules/Visibility/Rector/ClassMethod/ChangeMethodVisibilityRector.php
@@ -20,10 +20,6 @@
*/
final class ChangeMethodVisibilityRector extends AbstractScopeAwareRector implements ConfigurableRectorInterface
{
- /**
- * @var ChangeMethodVisibility[]
- */
- private $methodVisibilities = [];
/**
* @readonly
* @var \Rector\NodeCollector\ScopeResolver\ParentClassScopeResolver
@@ -34,6 +30,10 @@ final class ChangeMethodVisibilityRector extends AbstractScopeAwareRector implem
* @var \Rector\Privatization\NodeManipulator\VisibilityManipulator
*/
private $visibilityManipulator;
+ /**
+ * @var ChangeMethodVisibility[]
+ */
+ private $methodVisibilities = [];
public function __construct(ParentClassScopeResolver $parentClassScopeResolver, VisibilityManipulator $visibilityManipulator)
{
$this->parentClassScopeResolver = $parentClassScopeResolver;
diff --git a/src/Application/ApplicationFileProcessor.php b/src/Application/ApplicationFileProcessor.php
index 3fd451059656..f334e389334e 100644
--- a/src/Application/ApplicationFileProcessor.php
+++ b/src/Application/ApplicationFileProcessor.php
@@ -6,7 +6,6 @@
use PHPStan\Analyser\NodeScopeResolver;
use Rector\Caching\Detector\ChangedFilesDetector;
use Rector\Core\Application\FileDecorator\FileDiffFileDecorator;
-use Rector\Core\Application\FileSystem\RemovedAndAddedFilesProcessor;
use Rector\Core\Configuration\Option;
use Rector\Core\Configuration\Parameter\ParameterProvider;
use Rector\Core\Contract\Console\OutputStyleInterface;
@@ -26,14 +25,6 @@
use RectorPrefix202306\Symplify\EasyParallel\ScheduleFactory;
final class ApplicationFileProcessor
{
- /**
- * @var string
- */
- private const ARGV = 'argv';
- /**
- * @var SystemError[]
- */
- private $systemErrors = [];
/**
* @readonly
* @var \Symfony\Component\Filesystem\Filesystem
@@ -44,11 +35,6 @@ final class ApplicationFileProcessor
* @var \Rector\Core\Application\FileDecorator\FileDiffFileDecorator
*/
private $fileDiffFileDecorator;
- /**
- * @readonly
- * @var \Rector\Core\Application\FileSystem\RemovedAndAddedFilesProcessor
- */
- private $removedAndAddedFilesProcessor;
/**
* @readonly
* @var \Rector\Core\Contract\Console\OutputStyleInterface
@@ -98,15 +84,22 @@ final class ApplicationFileProcessor
* @var FileProcessorInterface[]
* @readonly
*/
- private $fileProcessors = [];
+ private $fileProcessors;
+ /**
+ * @var string
+ */
+ private const ARGV = 'argv';
+ /**
+ * @var SystemError[]
+ */
+ private $systemErrors = [];
/**
* @param FileProcessorInterface[] $fileProcessors
*/
- public function __construct(Filesystem $filesystem, FileDiffFileDecorator $fileDiffFileDecorator, RemovedAndAddedFilesProcessor $removedAndAddedFilesProcessor, OutputStyleInterface $rectorOutputStyle, FileFactory $fileFactory, NodeScopeResolver $nodeScopeResolver, ArrayParametersMerger $arrayParametersMerger, ParallelFileProcessor $parallelFileProcessor, ParameterProvider $parameterProvider, ScheduleFactory $scheduleFactory, CpuCoreCountProvider $cpuCoreCountProvider, ChangedFilesDetector $changedFilesDetector, array $fileProcessors = [])
+ public function __construct(Filesystem $filesystem, FileDiffFileDecorator $fileDiffFileDecorator, OutputStyleInterface $rectorOutputStyle, FileFactory $fileFactory, NodeScopeResolver $nodeScopeResolver, ArrayParametersMerger $arrayParametersMerger, ParallelFileProcessor $parallelFileProcessor, ParameterProvider $parameterProvider, ScheduleFactory $scheduleFactory, CpuCoreCountProvider $cpuCoreCountProvider, ChangedFilesDetector $changedFilesDetector, iterable $fileProcessors)
{
$this->filesystem = $filesystem;
$this->fileDiffFileDecorator = $fileDiffFileDecorator;
- $this->removedAndAddedFilesProcessor = $removedAndAddedFilesProcessor;
$this->rectorOutputStyle = $rectorOutputStyle;
$this->fileFactory = $fileFactory;
$this->nodeScopeResolver = $nodeScopeResolver;
@@ -171,7 +164,7 @@ public function processFiles(array $files, Configuration $configuration) : array
}
if ($systemErrorsAndFileDiffs[Bridge::SYSTEM_ERRORS] !== []) {
$this->changedFilesDetector->invalidateFile($file->getFilePath());
- } elseif (!$configuration->isDryRun()) {
+ } elseif (!$configuration->isDryRun() || $systemErrorsAndFileDiffs[Bridge::FILE_DIFFS] === []) {
$this->changedFilesDetector->cacheFileWithDependencies($file->getFilePath());
}
// progress bar +1
@@ -179,7 +172,6 @@ public function processFiles(array $files, Configuration $configuration) : array
$this->rectorOutputStyle->progressAdvance();
}
}
- $this->removedAndAddedFilesProcessor->run($configuration);
return $systemErrorsAndFileDiffs;
}
/**
diff --git a/src/Application/ChangedNodeScopeRefresher.php b/src/Application/ChangedNodeScopeRefresher.php
index 65b940a53055..ccc397f6ff00 100644
--- a/src/Application/ChangedNodeScopeRefresher.php
+++ b/src/Application/ChangedNodeScopeRefresher.php
@@ -16,9 +16,7 @@
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\FunctionLike;
use PhpParser\Node\Stmt;
-use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\Declare_;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\Stmt\Function_;
use PhpParser\Node\Stmt\If_;
@@ -26,7 +24,6 @@
use PhpParser\Node\Stmt\Switch_;
use PhpParser\Node\Stmt\TryCatch;
use PHPStan\Analyser\MutatingScope;
-use Rector\Core\Contract\PhpParser\Node\StmtsAwareInterface;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\NodeAnalyzer\ScopeAnalyzer;
use Rector\Core\Provider\CurrentFileProvider;
@@ -97,17 +94,6 @@ public function refresh(Node $node, ?MutatingScope $mutatingScope, ?string $file
}
public function reIndexNodeAttributes(Node $node) : void
{
- if ($this->hasArrayStmtsNode($node)) {
- /**
- * @var StmtsAwareInterface|ClassLike|Declare_ $node
- * @var Stmt[] $stmts
- */
- $stmts = $node->stmts;
- $node->stmts = \array_values($stmts);
- foreach ($node->stmts as $key => $stmt) {
- $stmt->setAttribute(AttributeKey::STMT_KEY, $key);
- }
- }
if ($node instanceof FunctionLike) {
/** @var ClassMethod|Function_|Closure $node */
$node->params = \array_values($node->params);
@@ -129,10 +115,6 @@ public function reIndexNodeAttributes(Node $node) : void
$node->cases = \array_values($node->cases);
}
}
- private function hasArrayStmtsNode(Node $node) : bool
- {
- return ($node instanceof ClassLike || $node instanceof StmtsAwareInterface || $node instanceof Declare_) && $node->stmts !== null;
- }
/**
* @return Stmt[]
*/
diff --git a/src/Application/FileProcessor.php b/src/Application/FileProcessor.php
index 63c3652a0107..09dd4ebf0e71 100644
--- a/src/Application/FileProcessor.php
+++ b/src/Application/FileProcessor.php
@@ -3,20 +3,12 @@
declare (strict_types=1);
namespace Rector\Core\Application;
-use Rector\ChangesReporting\Collector\AffectedFilesCollector;
-use Rector\Core\PhpParser\NodeTraverser\FileWithoutNamespaceNodeTraverser;
use Rector\Core\PhpParser\NodeTraverser\RectorNodeTraverser;
use Rector\Core\PhpParser\Parser\RectorParser;
use Rector\Core\ValueObject\Application\File;
-use Rector\Core\ValueObject\Configuration;
use Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator;
final class FileProcessor
{
- /**
- * @readonly
- * @var \Rector\ChangesReporting\Collector\AffectedFilesCollector
- */
- private $affectedFilesCollector;
/**
* @readonly
* @var \Rector\NodeTypeResolver\NodeScopeAndMetadataDecorator
@@ -32,18 +24,11 @@ final class FileProcessor
* @var \Rector\Core\PhpParser\NodeTraverser\RectorNodeTraverser
*/
private $rectorNodeTraverser;
- /**
- * @readonly
- * @var \Rector\Core\PhpParser\NodeTraverser\FileWithoutNamespaceNodeTraverser
- */
- private $fileWithoutNamespaceNodeTraverser;
- public function __construct(AffectedFilesCollector $affectedFilesCollector, NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator, RectorParser $rectorParser, RectorNodeTraverser $rectorNodeTraverser, FileWithoutNamespaceNodeTraverser $fileWithoutNamespaceNodeTraverser)
+ public function __construct(NodeScopeAndMetadataDecorator $nodeScopeAndMetadataDecorator, RectorParser $rectorParser, RectorNodeTraverser $rectorNodeTraverser)
{
- $this->affectedFilesCollector = $affectedFilesCollector;
$this->nodeScopeAndMetadataDecorator = $nodeScopeAndMetadataDecorator;
$this->rectorParser = $rectorParser;
$this->rectorNodeTraverser = $rectorNodeTraverser;
- $this->fileWithoutNamespaceNodeTraverser = $fileWithoutNamespaceNodeTraverser;
}
public function parseFileInfoToLocalCache(File $file) : void
{
@@ -54,14 +39,9 @@ public function parseFileInfoToLocalCache(File $file) : void
$newStmts = $this->nodeScopeAndMetadataDecorator->decorateNodesFromFile($file, $oldStmts);
$file->hydrateStmtsAndTokens($newStmts, $oldStmts, $oldTokens);
}
- public function refactor(File $file, Configuration $configuration) : void
+ public function refactor(File $file) : void
{
- $newStmts = $this->fileWithoutNamespaceNodeTraverser->traverse($file->getNewStmts());
- $newStmts = $this->rectorNodeTraverser->traverse($newStmts);
+ $newStmts = $this->rectorNodeTraverser->traverse($file->getNewStmts());
$file->changeNewStmts($newStmts);
- $this->affectedFilesCollector->removeFromList($file);
- while (($otherTouchedFile = $this->affectedFilesCollector->getNext()) instanceof File) {
- $this->refactor($otherTouchedFile, $configuration);
- }
}
}
diff --git a/src/Application/FileProcessor/PhpFileProcessor.php b/src/Application/FileProcessor/PhpFileProcessor.php
index 60563e5a2eef..e32cbc5bcfdf 100644
--- a/src/Application/FileProcessor/PhpFileProcessor.php
+++ b/src/Application/FileProcessor/PhpFileProcessor.php
@@ -9,7 +9,6 @@
use Rector\ChangesReporting\ValueObjectFactory\ErrorFactory;
use Rector\ChangesReporting\ValueObjectFactory\FileDiffFactory;
use Rector\Core\Application\FileProcessor;
-use Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector;
use Rector\Core\Contract\Console\OutputStyleInterface;
use Rector\Core\Contract\Processor\FileProcessorInterface;
use Rector\Core\Exception\ShouldNotHappenException;
@@ -23,14 +22,10 @@
use Rector\Parallel\ValueObject\Bridge;
use Rector\PostRector\Application\PostFileProcessor;
use Rector\Testing\PHPUnit\StaticPHPUnitEnvironment;
+use RectorPrefix202306\Symfony\Component\Console\Style\SymfonyStyle;
use Throwable;
final class PhpFileProcessor implements FileProcessorInterface
{
- /**
- * @var string
- * @see https://regex101.com/r/xP2MGa/1
- */
- private const OPEN_TAG_SPACED_REGEX = '#^(?[^\\S\\r\\n]+\\<\\?php)#m';
/**
* @readonly
* @var \Rector\Core\PhpParser\Printer\FormatPerservingPrinter
@@ -41,11 +36,6 @@ final class PhpFileProcessor implements FileProcessorInterface
* @var \Rector\Core\Application\FileProcessor
*/
private $fileProcessor;
- /**
- * @readonly
- * @var \Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector
- */
- private $removedAndAddedFilesCollector;
/**
* @readonly
* @var \Rector\Core\Contract\Console\OutputStyleInterface
@@ -81,11 +71,20 @@ final class PhpFileProcessor implements FileProcessorInterface
* @var \Rector\Core\FileSystem\FilePathHelper
*/
private $filePathHelper;
- public function __construct(FormatPerservingPrinter $formatPerservingPrinter, FileProcessor $fileProcessor, RemovedAndAddedFilesCollector $removedAndAddedFilesCollector, OutputStyleInterface $rectorOutputStyle, FileDiffFactory $fileDiffFactory, ChangedFilesDetector $changedFilesDetector, CurrentFileProvider $currentFileProvider, PostFileProcessor $postFileProcessor, ErrorFactory $errorFactory, FilePathHelper $filePathHelper)
+ /**
+ * @readonly
+ * @var \Symfony\Component\Console\Style\SymfonyStyle
+ */
+ private $symfonyStyle;
+ /**
+ * @var string
+ * @see https://regex101.com/r/xP2MGa/1
+ */
+ private const OPEN_TAG_SPACED_REGEX = '#^(?[^\\S\\r\\n]+\\<\\?php)#m';
+ public function __construct(FormatPerservingPrinter $formatPerservingPrinter, FileProcessor $fileProcessor, OutputStyleInterface $rectorOutputStyle, FileDiffFactory $fileDiffFactory, ChangedFilesDetector $changedFilesDetector, CurrentFileProvider $currentFileProvider, PostFileProcessor $postFileProcessor, ErrorFactory $errorFactory, FilePathHelper $filePathHelper, SymfonyStyle $symfonyStyle)
{
$this->formatPerservingPrinter = $formatPerservingPrinter;
$this->fileProcessor = $fileProcessor;
- $this->removedAndAddedFilesCollector = $removedAndAddedFilesCollector;
$this->rectorOutputStyle = $rectorOutputStyle;
$this->fileDiffFactory = $fileDiffFactory;
$this->changedFilesDetector = $changedFilesDetector;
@@ -93,6 +92,7 @@ public function __construct(FormatPerservingPrinter $formatPerservingPrinter, Fi
$this->postFileProcessor = $postFileProcessor;
$this->errorFactory = $errorFactory;
$this->filePathHelper = $filePathHelper;
+ $this->symfonyStyle = $symfonyStyle;
}
/**
* @return array{system_errors: SystemError[], file_diffs: FileDiff[]}
@@ -112,7 +112,7 @@ public function process(File $file, Configuration $configuration) : array
$rectorWithLineChanges = null;
do {
$file->changeHasChanged(\false);
- $this->fileProcessor->refactor($file, $configuration);
+ $this->fileProcessor->refactor($file);
// 3. apply post rectors
$newStmts = $this->postFileProcessor->traverse($file->getNewStmts());
// this is needed for new tokens added in "afterTraverse()"
@@ -127,6 +127,10 @@ public function process(File $file, Configuration $configuration) : array
$fileHasChanged = \true;
}
} while ($fileHasChangedInCurrentPass);
+ // show warning on has InlineHTML node if file has changed
+ if ($fileHasChanged && $file->hasInlineHTMLNode()) {
+ $this->symfonyStyle->warning(\sprintf('File %s has InlineHTML node, this may cause unexpected output, you may need to manually verify the changed file', $this->filePathHelper->relativePath($file->getFilePath())));
+ }
// 5. add as cacheable if not changed at all
if (!$fileHasChanged) {
$this->changedFilesDetector->addCachableFile($file->getFilePath());
@@ -184,11 +188,6 @@ private function parseFileAndDecorateNodes(File $file) : array
}
private function printFile(File $file, Configuration $configuration) : void
{
- $filePath = $file->getFilePath();
- if ($this->removedAndAddedFilesCollector->isFileRemoved($filePath)) {
- // skip, because this file exists no more
- return;
- }
// only save to string first, no need to print to file when not needed
$newContent = $this->formatPerservingPrinter->printParsedStmstAndTokensToString($file);
/**
diff --git a/src/Application/FileSystem/RemovedAndAddedFilesCollector.php b/src/Application/FileSystem/RemovedAndAddedFilesCollector.php
deleted file mode 100644
index f7ed44df4395..000000000000
--- a/src/Application/FileSystem/RemovedAndAddedFilesCollector.php
+++ /dev/null
@@ -1,81 +0,0 @@
-removedFilePaths[] = $filePath;
- }
- /**
- * @return string[]
- */
- public function getRemovedFiles() : array
- {
- return $this->removedFilePaths;
- }
- public function isFileRemoved(string $filePath) : bool
- {
- foreach ($this->removedFilePaths as $removedFilePath) {
- if ($removedFilePath !== $filePath) {
- continue;
- }
- return \true;
- }
- return \false;
- }
- /**
- * @api
- */
- public function addAddedFile(AddedFileInterface $addedFile) : void
- {
- $this->addedFiles[] = $addedFile;
- }
- /**
- * @return AddedFileWithContent[]
- */
- public function getAddedFilesWithContent() : array
- {
- return \array_filter($this->addedFiles, static function (AddedFileInterface $addedFile) : bool {
- return $addedFile instanceof AddedFileWithContent;
- });
- }
- /**
- * @return AddedFileWithNodes[]
- */
- public function getAddedFilesWithNodes() : array
- {
- return \array_filter($this->addedFiles, static function (AddedFileInterface $addedFile) : bool {
- return $addedFile instanceof AddedFileWithNodes;
- });
- }
- public function getAddedFileCount() : int
- {
- return \count($this->addedFiles);
- }
- public function getRemovedFilesCount() : int
- {
- return \count($this->removedFilePaths);
- }
- /**
- * @api For testing
- */
- public function reset() : void
- {
- $this->addedFiles = [];
- $this->removedFilePaths = [];
- }
-}
diff --git a/src/Application/FileSystem/RemovedAndAddedFilesProcessor.php b/src/Application/FileSystem/RemovedAndAddedFilesProcessor.php
deleted file mode 100644
index a10913637d10..000000000000
--- a/src/Application/FileSystem/RemovedAndAddedFilesProcessor.php
+++ /dev/null
@@ -1,98 +0,0 @@
-filesystem = $filesystem;
- $this->nodesWithFileDestinationPrinter = $nodesWithFileDestinationPrinter;
- $this->removedAndAddedFilesCollector = $removedAndAddedFilesCollector;
- $this->rectorOutputStyle = $rectorOutputStyle;
- $this->filePathHelper = $filePathHelper;
- }
- public function run(Configuration $configuration) : void
- {
- $this->processAddedFilesWithContent($configuration);
- $this->processAddedFilesWithNodes($configuration);
- $this->processDeletedFiles($configuration);
- }
- private function processDeletedFiles(Configuration $configuration) : void
- {
- foreach ($this->removedAndAddedFilesCollector->getRemovedFiles() as $removedFilePath) {
- $removedFileRelativePath = $this->filePathHelper->relativePath($removedFilePath);
- // @todo file helper
- // $removedFileRelativePath = $removedFile->getRelativeFilePathFromDirectory(getcwd());
- if ($configuration->isDryRun()) {
- $message = \sprintf('File "%s" will be removed', $removedFileRelativePath);
- $this->rectorOutputStyle->warning($message);
- } else {
- $message = \sprintf('File "%s" was removed', $removedFileRelativePath);
- $this->rectorOutputStyle->warning($message);
- $this->filesystem->remove($removedFilePath);
- }
- }
- }
- private function processAddedFilesWithContent(Configuration $configuration) : void
- {
- foreach ($this->removedAndAddedFilesCollector->getAddedFilesWithContent() as $addedFileWithContent) {
- if ($configuration->isDryRun()) {
- $message = \sprintf('File "%s" will be added', $addedFileWithContent->getFilePath());
- $this->rectorOutputStyle->note($message);
- } else {
- $this->filesystem->dumpFile($addedFileWithContent->getFilePath(), $addedFileWithContent->getFileContent());
- $message = \sprintf('File "%s" was added', $addedFileWithContent->getFilePath());
- $this->rectorOutputStyle->note($message);
- }
- }
- }
- private function processAddedFilesWithNodes(Configuration $configuration) : void
- {
- foreach ($this->removedAndAddedFilesCollector->getAddedFilesWithNodes() as $addedFileWithNode) {
- $fileContent = $this->nodesWithFileDestinationPrinter->printNodesWithFileDestination($addedFileWithNode);
- if ($configuration->isDryRun()) {
- $message = \sprintf('File "%s" will be added', $addedFileWithNode->getFilePath());
- $this->rectorOutputStyle->note($message);
- } else {
- $this->filesystem->dumpFile($addedFileWithNode->getFilePath(), $fileContent);
- $message = \sprintf('File "%s" was added', $addedFileWithNode->getFilePath());
- $this->rectorOutputStyle->note($message);
- }
- }
- }
-}
diff --git a/src/Application/VersionResolver.php b/src/Application/VersionResolver.php
index c40452a91ebc..20b093176c56 100644
--- a/src/Application/VersionResolver.php
+++ b/src/Application/VersionResolver.php
@@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
- public const PACKAGE_VERSION = '0.17.0';
+ public const PACKAGE_VERSION = '0.17.2';
/**
* @api
* @var string
*/
- public const RELEASE_DATE = '2023-06-01 11:38:16';
+ public const RELEASE_DATE = '2023-06-29 11:59:41';
/**
* @var int
*/
diff --git a/src/Autoloading/BootstrapFilesIncluder.php b/src/Autoloading/BootstrapFilesIncluder.php
index c9575601084a..287444b54fbb 100644
--- a/src/Autoloading/BootstrapFilesIncluder.php
+++ b/src/Autoloading/BootstrapFilesIncluder.php
@@ -19,10 +19,6 @@
*/
final class BootstrapFilesIncluder
{
- /**
- * @var array
- */
- private $configCache = [];
/**
* @readonly
* @var \Rector\Core\Configuration\Parameter\ParameterProvider
@@ -33,6 +29,10 @@ final class BootstrapFilesIncluder
* @var \Rector\NodeTypeResolver\DependencyInjection\PHPStanExtensionsConfigResolver
*/
private $phpStanExtensionsConfigResolver;
+ /**
+ * @var array
+ */
+ private $configCache = [];
public function __construct(ParameterProvider $parameterProvider, PHPStanExtensionsConfigResolver $phpStanExtensionsConfigResolver)
{
$this->parameterProvider = $parameterProvider;
diff --git a/src/Configuration/ConfigInitializer.php b/src/Configuration/ConfigInitializer.php
index 0355cccde3a0..de63c319cc56 100644
--- a/src/Configuration/ConfigInitializer.php
+++ b/src/Configuration/ConfigInitializer.php
@@ -11,13 +11,9 @@
use Rector\PostRector\Contract\Rector\ComplementaryRectorInterface;
use Rector\PostRector\Contract\Rector\PostRectorInterface;
use RectorPrefix202306\Symfony\Component\Console\Style\SymfonyStyle;
+use RectorPrefix202306\Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
final class ConfigInitializer
{
- /**
- * @var RectorInterface[]
- * @readonly
- */
- private $rectors;
/**
* @readonly
* @var \Rector\Core\FileSystem\InitFilePathsResolver
@@ -34,14 +30,18 @@ final class ConfigInitializer
*/
private $phpVersionProvider;
/**
- * @param RectorInterface[] $rectors
+ * @var RectorInterface[]
+ */
+ private $rectors = [];
+ /**
+ * @param RewindableGenerator $rectors
*/
- public function __construct(array $rectors, InitFilePathsResolver $initFilePathsResolver, SymfonyStyle $symfonyStyle, PhpVersionProvider $phpVersionProvider)
+ public function __construct(RewindableGenerator $rectors, InitFilePathsResolver $initFilePathsResolver, SymfonyStyle $symfonyStyle, PhpVersionProvider $phpVersionProvider)
{
- $this->rectors = $rectors;
$this->initFilePathsResolver = $initFilePathsResolver;
$this->symfonyStyle = $symfonyStyle;
$this->phpVersionProvider = $phpVersionProvider;
+ $this->rectors = \iterator_to_array($rectors);
}
public function createConfig(string $projectDirectory) : void
{
diff --git a/src/Configuration/Parameter/ParameterProvider.php b/src/Configuration/Parameter/ParameterProvider.php
index 1577997d48a4..f9ecda65b638 100644
--- a/src/Configuration/Parameter/ParameterProvider.php
+++ b/src/Configuration/Parameter/ParameterProvider.php
@@ -36,10 +36,12 @@ public function provideParameter(string $name)
/**
* @api
*/
- public function provideStringParameter(string $name) : string
+ public function provideStringParameter(string $name, ?string $default = null) : string
{
- $this->ensureParameterIsSet($name);
- return (string) $this->parameters[$name];
+ if ($default === null) {
+ $this->ensureParameterIsSet($name);
+ }
+ return (string) ($this->parameters[$name] ?? $default);
}
/**
* @api
diff --git a/src/Configuration/RectorConfigProvider.php b/src/Configuration/RectorConfigProvider.php
index b0ea1089ab31..a42c95c3381a 100644
--- a/src/Configuration/RectorConfigProvider.php
+++ b/src/Configuration/RectorConfigProvider.php
@@ -43,7 +43,7 @@ public function getSymfonyContainerXml() : string
}
public function getIndentChar() : string
{
- return $this->parameterProvider->provideStringParameter(\Rector\Core\Configuration\Option::INDENT_CHAR);
+ return $this->parameterProvider->provideStringParameter(\Rector\Core\Configuration\Option::INDENT_CHAR, ' ');
}
public function getIndentSize() : int
{
diff --git a/src/Configuration/RenamedClassesDataCollector.php b/src/Configuration/RenamedClassesDataCollector.php
index 842d8511bf26..5f99664ccffe 100644
--- a/src/Configuration/RenamedClassesDataCollector.php
+++ b/src/Configuration/RenamedClassesDataCollector.php
@@ -23,9 +23,8 @@ public function hasOldClass(string $oldClass) : bool
*/
public function addOldToNewClasses(array $oldToNewClasses) : void
{
- $item0Unpacked = $this->oldToNewClasses;
/** @var array $oldToNewClasses */
- $oldToNewClasses = \array_merge($item0Unpacked, $oldToNewClasses);
+ $oldToNewClasses = \array_merge($this->oldToNewClasses, $oldToNewClasses);
$this->oldToNewClasses = $oldToNewClasses;
}
/**
diff --git a/src/Console/Command/InitCommand.php b/src/Console/Command/InitCommand.php
deleted file mode 100644
index b8f6550ca205..000000000000
--- a/src/Console/Command/InitCommand.php
+++ /dev/null
@@ -1,35 +0,0 @@
-configInitializer = $configInitializer;
- parent::__construct();
- }
- protected function configure() : void
- {
- $this->setName('init');
- $this->setDescription('Generate rector.php configuration file');
- }
- protected function execute(InputInterface $input, OutputInterface $output) : int
- {
- $this->configInitializer->createConfig(\getcwd());
- return Command::SUCCESS;
- }
-}
diff --git a/src/Console/Command/ListRulesCommand.php b/src/Console/Command/ListRulesCommand.php
index fd6652def31c..4429252b73c4 100644
--- a/src/Console/Command/ListRulesCommand.php
+++ b/src/Console/Command/ListRulesCommand.php
@@ -15,6 +15,7 @@
use RectorPrefix202306\Symfony\Component\Console\Input\InputInterface;
use RectorPrefix202306\Symfony\Component\Console\Input\InputOption;
use RectorPrefix202306\Symfony\Component\Console\Output\OutputInterface;
+use RectorPrefix202306\Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
final class ListRulesCommand extends Command
{
/**
@@ -29,18 +30,17 @@ final class ListRulesCommand extends Command
private $skippedClassResolver;
/**
* @var RectorInterface[]
- * @readonly
*/
- private $rectors;
+ private $rectors = [];
/**
- * @param RectorInterface[] $rectors
+ * @param RewindableGenerator $rectors
*/
- public function __construct(RectorOutputStyle $rectorOutputStyle, SkippedClassResolver $skippedClassResolver, array $rectors)
+ public function __construct(RectorOutputStyle $rectorOutputStyle, SkippedClassResolver $skippedClassResolver, RewindableGenerator $rectors)
{
$this->rectorOutputStyle = $rectorOutputStyle;
$this->skippedClassResolver = $skippedClassResolver;
- $this->rectors = $rectors;
parent::__construct();
+ $this->rectors = \iterator_to_array($rectors);
}
protected function configure() : void
{
diff --git a/src/Console/Command/ProcessCommand.php b/src/Console/Command/ProcessCommand.php
index 7bf79df6ed86..128de36d8611 100644
--- a/src/Console/Command/ProcessCommand.php
+++ b/src/Console/Command/ProcessCommand.php
@@ -13,7 +13,6 @@
use Rector\Core\Console\Output\OutputFormatterCollector;
use Rector\Core\Contract\Console\OutputStyleInterface;
use Rector\Core\Exception\ShouldNotHappenException;
-use Rector\Core\Kernel\RectorKernel;
use Rector\Core\StaticReflection\DynamicSourceLocatorDecorator;
use Rector\Core\Util\MemoryLimiter;
use Rector\Core\Validation\EmptyConfigurableRectorChecker;
@@ -113,6 +112,10 @@ protected function execute(InputInterface $input, OutputInterface $output) : int
$paths = $configuration->getPaths();
// 1. add files and directories to static locator
$this->dynamicSourceLocatorDecorator->addPaths($paths);
+ if ($this->dynamicSourceLocatorDecorator->isPathsEmpty()) {
+ $this->rectorOutputStyle->error('The given paths do not match any files');
+ return ExitCode::FAILURE;
+ }
// 2. inform user about registering configurable rule without configuration
$this->emptyConfigurableRectorChecker->check();
// MAIN PHASE
@@ -141,7 +144,6 @@ protected function initialize(InputInterface $input, OutputInterface $output) :
$optionClearCache = (bool) $input->getOption(Option::CLEAR_CACHE);
if ($optionDebug || $optionClearCache) {
$this->changedFilesDetector->clear();
- RectorKernel::clearCache();
}
}
/**
diff --git a/src/Console/Command/SetupCICommand.php b/src/Console/Command/SetupCICommand.php
index 972f8553f31f..f022fe2ea9f3 100644
--- a/src/Console/Command/SetupCICommand.php
+++ b/src/Console/Command/SetupCICommand.php
@@ -14,16 +14,16 @@
use RectorPrefix202306\Symfony\Component\Process\Process;
final class SetupCICommand extends Command
{
- /**
- * @var string
- * @see https://regex101.com/r/etcmog/2
- */
- private const GITHUB_REPOSITORY_REGEX = '#github\\.com[:\\/](?.*?)\\.git#';
/**
* @readonly
* @var \Symfony\Component\Console\Style\SymfonyStyle
*/
private $symfonyStyle;
+ /**
+ * @var string
+ * @see https://regex101.com/r/etcmog/2
+ */
+ private const GITHUB_REPOSITORY_REGEX = '#github\\.com[:\\/](?.*?)\\.git#';
public function __construct(SymfonyStyle $symfonyStyle)
{
$this->symfonyStyle = $symfonyStyle;
diff --git a/src/Console/Command/WorkerCommand.php b/src/Console/Command/WorkerCommand.php
index 4730ccdacad3..14af5998bd73 100644
--- a/src/Console/Command/WorkerCommand.php
+++ b/src/Console/Command/WorkerCommand.php
@@ -42,7 +42,7 @@ public function __construct(WorkerRunner $workerRunner, MemoryLimiter $memoryLim
protected function configure() : void
{
$this->setName('worker');
- $this->setDescription('(Internal) Support for parallel process');
+ $this->setDescription('[INTERNAL] Support for parallel process');
parent::configure();
}
protected function execute(InputInterface $input, OutputInterface $output) : int
diff --git a/src/Console/ConsoleApplication.php b/src/Console/ConsoleApplication.php
index a7e5ec34911b..0cc72405c3eb 100644
--- a/src/Console/ConsoleApplication.php
+++ b/src/Console/ConsoleApplication.php
@@ -7,8 +7,11 @@
use Rector\ChangesReporting\Output\ConsoleOutputFormatter;
use Rector\Core\Application\VersionResolver;
use Rector\Core\Configuration\Option;
+use Rector\Core\Console\Command\ListRulesCommand;
+use Rector\Core\Console\Command\ProcessCommand;
+use Rector\Core\Console\Command\SetupCICommand;
+use Rector\Core\Console\Command\WorkerCommand;
use RectorPrefix202306\Symfony\Component\Console\Application;
-use RectorPrefix202306\Symfony\Component\Console\Command\Command;
use RectorPrefix202306\Symfony\Component\Console\Input\InputDefinition;
use RectorPrefix202306\Symfony\Component\Console\Input\InputInterface;
use RectorPrefix202306\Symfony\Component\Console\Input\InputOption;
@@ -19,13 +22,10 @@ final class ConsoleApplication extends Application
* @var string
*/
private const NAME = 'Rector';
- /**
- * @param Command[] $commands
- */
- public function __construct(array $commands = [])
+ public function __construct(ProcessCommand $processCommand, WorkerCommand $workerCommand, SetupCICommand $setupCICommand, ListRulesCommand $listRulesCommand)
{
parent::__construct(self::NAME, VersionResolver::PACKAGE_VERSION);
- $this->addCommands($commands);
+ $this->addCommands([$processCommand, $workerCommand, $setupCICommand, $listRulesCommand]);
$this->setDefaultCommand('process');
}
public function doRun(InputInterface $input, OutputInterface $output) : int
diff --git a/src/Console/Formatter/ConsoleDiffer.php b/src/Console/Formatter/ConsoleDiffer.php
index 2c35afa4b29c..0b77cce67575 100644
--- a/src/Console/Formatter/ConsoleDiffer.php
+++ b/src/Console/Formatter/ConsoleDiffer.php
@@ -4,20 +4,19 @@
namespace Rector\Core\Console\Formatter;
use RectorPrefix202306\SebastianBergmann\Diff\Differ;
-use RectorPrefix202306\SebastianBergmann\Diff\Output\StrictUnifiedDiffOutputBuilder;
use RectorPrefix202306\SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;
final class ConsoleDiffer
{
/**
* @readonly
- * @var \SebastianBergmann\Diff\Differ
+ * @var \Rector\Core\Console\Formatter\ColorConsoleDiffFormatter
*/
- private $differ;
+ private $colorConsoleDiffFormatter;
/**
* @readonly
- * @var \Rector\Core\Console\Formatter\ColorConsoleDiffFormatter
+ * @var \SebastianBergmann\Diff\Differ
*/
- private $colorConsoleDiffFormatter;
+ private $differ;
public function __construct(\Rector\Core\Console\Formatter\ColorConsoleDiffFormatter $colorConsoleDiffFormatter)
{
$this->colorConsoleDiffFormatter = $colorConsoleDiffFormatter;
diff --git a/src/Console/Output/OutputFormatterCollector.php b/src/Console/Output/OutputFormatterCollector.php
index 2a36e339b75d..79827e21e527 100644
--- a/src/Console/Output/OutputFormatterCollector.php
+++ b/src/Console/Output/OutputFormatterCollector.php
@@ -14,7 +14,7 @@ final class OutputFormatterCollector
/**
* @param OutputFormatterInterface[] $outputFormatters
*/
- public function __construct(array $outputFormatters)
+ public function __construct(iterable $outputFormatters)
{
foreach ($outputFormatters as $outputFormatter) {
$this->outputFormatters[$outputFormatter->getName()] = $outputFormatter;
diff --git a/src/Console/Style/SymfonyStyleFactory.php b/src/Console/Style/SymfonyStyleFactory.php
index e3fb44d4cf1a..85dfbde0d0e0 100644
--- a/src/Console/Style/SymfonyStyleFactory.php
+++ b/src/Console/Style/SymfonyStyleFactory.php
@@ -20,6 +20,9 @@ public function __construct(PrivatesAccessor $privatesAccessor)
{
$this->privatesAccessor = $privatesAccessor;
}
+ /**
+ * @api
+ */
public function create() : SymfonyStyle
{
// to prevent missing argv indexes
diff --git a/src/Contract/PhpParser/NodePrinterInterface.php b/src/Contract/PhpParser/NodePrinterInterface.php
deleted file mode 100644
index 6bc7b0923c8b..000000000000
--- a/src/Contract/PhpParser/NodePrinterInterface.php
+++ /dev/null
@@ -1,25 +0,0 @@
-arrayParametersMerger = new ArrayParametersMerger();
- $symfonyStyleFactory = new SymfonyStyleFactory(new PrivatesAccessor());
- $this->symfonyStyle = $symfonyStyleFactory->create();
}
/**
* @return mixed[]
@@ -59,39 +47,6 @@ public function collectFromServiceAndClassName(string $className, Definition $de
private function addConfigureCallValues(string $rectorClass, array $configureValues) : void
{
foreach ($configureValues as $configureValue) {
- // is nested or unnested value?
- if (\is_array($configureValue) && \count($configureValue) === 1) {
- \reset($configureValue);
- $firstKey = \key($configureValue);
- if (\is_string($firstKey) && \is_array($configureValue[$firstKey])) {
- // has class some public constants?
- // fixes bug when 1 item is unwrapped and treated as constant key, without rule having public constant
- $classReflection = new ReflectionClass($rectorClass);
- $reflectionClassConstants = $classReflection->getReflectionConstants();
- $result = [];
- \array_walk($reflectionClassConstants, function ($value) use(&$result) {
- if ($value->isPublic()) {
- $result[$value->getName()] = $value->getValue();
- }
- });
- $constantNamesToValues = $result;
- foreach ($constantNamesToValues as $constantName => $constantValue) {
- if ($constantValue === $firstKey) {
- $reflectionConstant = $classReflection->getReflectionConstant($constantName);
- if ($reflectionConstant === \false) {
- continue;
- }
- if (\strpos((string) $reflectionConstant->getDocComment(), '@deprecated') === \false) {
- continue;
- }
- $warningMessage = \sprintf('The constant for "%s::%s" is deprecated.%sUse "$rectorConfig->ruleWithConfiguration()" instead.', $rectorClass, $constantName, \PHP_EOL);
- $this->symfonyStyle->warning($warningMessage);
- $configureValue = $configureValue[$firstKey];
- break;
- }
- }
- }
- }
if (!isset($this->configureCallValuesByRectorClass[$rectorClass])) {
$this->configureCallValuesByRectorClass[$rectorClass] = $configureValue;
} else {
diff --git a/src/DependencyInjection/CompilerPass/AutowireArrayParameterCompilerPass.php b/src/DependencyInjection/CompilerPass/AutowireArrayParameterCompilerPass.php
deleted file mode 100644
index f38e3511a65c..000000000000
--- a/src/DependencyInjection/CompilerPass/AutowireArrayParameterCompilerPass.php
+++ /dev/null
@@ -1,156 +0,0 @@
-[]|string[]
- */
- private const EXCLUDED_FATAL_CLASSES = ['Symfony\\Component\\Form\\FormExtensionInterface', 'Symfony\\Component\\Asset\\PackageInterface', 'Symfony\\Component\\Config\\Loader\\LoaderInterface', 'Symfony\\Component\\VarDumper\\Dumper\\ContextProvider\\ContextProviderInterface', 'EasyCorp\\Bundle\\EasyAdminBundle\\Form\\Type\\Configurator\\TypeConfiguratorInterface', 'Sonata\\CoreBundle\\Model\\Adapter\\AdapterInterface', 'Sonata\\Doctrine\\Adapter\\AdapterChain', 'Sonata\\Twig\\Extension\\TemplateExtension', 'Symfony\\Component\\HttpKernel\\KernelInterface'];
- /**
- * @readonly
- * @var \Rector\Core\DependencyInjection\DefinitionFinder
- */
- private $definitionFinder;
- /**
- * @readonly
- * @var \Rector\Core\DependencyInjection\TypeResolver\ParameterTypeResolver
- */
- private $parameterTypeResolver;
- /**
- * @readonly
- * @var \Rector\Core\DependencyInjection\Skipper\ParameterSkipper
- */
- private $parameterSkipper;
- /**
- * @param string[] $excludedFatalClasses
- */
- public function __construct(array $excludedFatalClasses = [])
- {
- $this->definitionFinder = new DefinitionFinder();
- $paramTypeDocBlockResolver = new ParamTypeDocBlockResolver();
- $this->parameterTypeResolver = new ParameterTypeResolver($paramTypeDocBlockResolver);
- $this->parameterSkipper = new ParameterSkipper($this->parameterTypeResolver, $excludedFatalClasses);
- }
- public function process(ContainerBuilder $containerBuilder) : void
- {
- $definitions = $containerBuilder->getDefinitions();
- foreach ($definitions as $definition) {
- if ($this->shouldSkipDefinition($containerBuilder, $definition)) {
- continue;
- }
- /** @var ReflectionClass